diff --git a/bolt/include/bolt/Core/BinaryBasicBlock.h b/bolt/include/bolt/Core/BinaryBasicBlock.h index 9a9d7b8735d71..b4f31cf2bae6f 100644 --- a/bolt/include/bolt/Core/BinaryBasicBlock.h +++ b/bolt/include/bolt/Core/BinaryBasicBlock.h @@ -19,6 +19,7 @@ #include "bolt/Core/MCPlus.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorOr.h" diff --git a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp index a9b773353fe69..36fddcba25d61 100644 --- a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp +++ b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp @@ -76,11 +76,10 @@ HelperDeclRefGraph::getReachableNodes(const Decl *Root) const { llvm::DenseSet ConnectedNodes; std::function VisitNode = [&](const CallGraphNode *Node) { - if (ConnectedNodes.count(Node)) + if (!ConnectedNodes.insert(Node).second) return; - ConnectedNodes.insert(Node); - for (auto It = Node->begin(), End = Node->end(); It != End; ++It) - VisitNode(*It); + for (const CallGraphNode::CallRecord &Callee : *Node) + VisitNode(Callee); }; VisitNode(RootNode); diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp index 5e2cc207560d3..fef086c5a99d8 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @@ -116,9 +116,8 @@ void ExpandModularHeadersPPCallbacks::handleModuleFile( if (!MF) return; // Avoid processing a ModuleFile more than once. - if (VisitedModules.count(MF)) + if (!VisitedModules.insert(MF).second) return; - VisitedModules.insert(MF); // Visit all the input files of this module and mark them to record their // contents later. diff --git a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp index d55df3a6d7b74..e13b1ceacc539 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp @@ -97,8 +97,8 @@ DanglingHandleCheck::DanglingHandleCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), HandleClasses(utils::options::parseStringList(Options.get( - "HandleClasses", - "std::basic_string_view;std::experimental::basic_string_view"))), + "HandleClasses", "std::basic_string_view;std::experimental::basic_" + "string_view;std::span"))), IsAHandle(cxxRecordDecl(hasAnyName(HandleClasses)).bind("handle")) {} void DanglingHandleCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { diff --git a/clang-tools-extra/clangd/FS.cpp b/clang-tools-extra/clangd/FS.cpp index bd3c6440c24b0..5729b9341d9d4 100644 --- a/clang-tools-extra/clangd/FS.cpp +++ b/clang-tools-extra/clangd/FS.cpp @@ -64,8 +64,8 @@ PreambleFileStatusCache::getProducingFS( : ProxyFileSystem(std::move(FS)), StatCache(StatCache) {} llvm::ErrorOr> - openFileForRead(const llvm::Twine &Path, bool IsText = true) override { - auto File = getUnderlyingFS().openFileForRead(Path, IsText); + openFileForRead(const llvm::Twine &Path) override { + auto File = getUnderlyingFS().openFileForRead(Path); if (!File || !*File) return File; // Eagerly stat opened file, as the followup `status` call on the file diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 4491be9aa0362..5cf1691ce3961 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -280,6 +280,8 @@ class TidyDiagnosticGroups { llvm::StringRef Check; while (!Checks.empty()) { std::tie(Check, Checks) = Checks.split(','); + Check = Check.trim(); + if (Check.empty()) continue; diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index 44c6acd3ed83a..84e8fec342829 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -479,9 +479,9 @@ class TimerFS : public llvm::vfs::ProxyFileSystem { : ProxyFileSystem(std::move(FS)) {} llvm::ErrorOr> - openFileForRead(const llvm::Twine &Path, bool IsText = true) override { + openFileForRead(const llvm::Twine &Path) override { WallTimerRegion T(Timer); - auto FileOr = getUnderlyingFS().openFileForRead(Path, IsText); + auto FileOr = getUnderlyingFS().openFileForRead(Path); if (!FileOr) return FileOr; return std::make_unique(Timer, std::move(FileOr.get())); diff --git a/clang-tools-extra/clangd/index/Symbol.h b/clang-tools-extra/clangd/index/Symbol.h index 1aa5265299231..62c47ddfc5758 100644 --- a/clang-tools-extra/clangd/index/Symbol.h +++ b/clang-tools-extra/clangd/index/Symbol.h @@ -145,9 +145,11 @@ struct Symbol { ImplementationDetail = 1 << 2, /// Symbol is visible to other files (not e.g. a static helper function). VisibleOutsideFile = 1 << 3, + /// Symbol has an attached documentation comment. + HasDocComment = 1 << 4 }; - SymbolFlag Flags = SymbolFlag::None; + /// FIXME: also add deprecation message and fixit? }; diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 5c4e2150cf312..a76894cf0855f 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -635,17 +635,21 @@ bool SymbolCollector::handleDeclOccurrence( return true; const Symbol *BasicSymbol = Symbols.find(ID); - if (isPreferredDeclaration(*OriginalDecl, Roles)) + bool SkipDocCheckInDef = false; + if (isPreferredDeclaration(*OriginalDecl, Roles)) { // If OriginalDecl is preferred, replace/create the existing canonical // declaration (e.g. a class forward declaration). There should be at most // one duplicate as we expect to see only one preferred declaration per // TU, because in practice they are definitions. BasicSymbol = addDeclaration(*OriginalDecl, std::move(ID), IsMainFileOnly); - else if (!BasicSymbol || DeclIsCanonical) + SkipDocCheckInDef = true; + } else if (!BasicSymbol || DeclIsCanonical) { BasicSymbol = addDeclaration(*ND, std::move(ID), IsMainFileOnly); + SkipDocCheckInDef = true; + } if (Roles & static_cast(index::SymbolRole::Definition)) - addDefinition(*OriginalDecl, *BasicSymbol); + addDefinition(*OriginalDecl, *BasicSymbol, SkipDocCheckInDef); return true; } @@ -1025,16 +1029,28 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID, *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator, *CompletionTUInfo, /*IncludeBriefComments*/ false); - std::string Documentation = - formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion, - /*CommentsFromHeaders=*/true)); + std::string DocComment; + std::string Documentation; + bool AlreadyHasDoc = S.Flags & Symbol::HasDocComment; + if (!AlreadyHasDoc) { + DocComment = getDocComment(Ctx, SymbolCompletion, + /*CommentsFromHeaders=*/true); + Documentation = formatDocumentation(*CCS, DocComment); + } + const auto UpdateDoc = [&] { + if (!AlreadyHasDoc) { + if (!DocComment.empty()) + S.Flags |= Symbol::HasDocComment; + S.Documentation = Documentation; + } + }; if (!(S.Flags & Symbol::IndexedForCodeCompletion)) { if (Opts.StoreAllDocumentation) - S.Documentation = Documentation; + UpdateDoc(); Symbols.insert(S); return Symbols.find(S.ID); } - S.Documentation = Documentation; + UpdateDoc(); std::string Signature; std::string SnippetSuffix; getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind, @@ -1058,8 +1074,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID, return Symbols.find(S.ID); } -void SymbolCollector::addDefinition(const NamedDecl &ND, - const Symbol &DeclSym) { +void SymbolCollector::addDefinition(const NamedDecl &ND, const Symbol &DeclSym, + bool SkipDocCheck) { if (DeclSym.Definition) return; const auto &SM = ND.getASTContext().getSourceManager(); @@ -1074,6 +1090,27 @@ void SymbolCollector::addDefinition(const NamedDecl &ND, Symbol S = DeclSym; // FIXME: use the result to filter out symbols. S.Definition = *DefLoc; + + std::string DocComment; + std::string Documentation; + if (!SkipDocCheck && !(S.Flags & Symbol::HasDocComment) && + (llvm::isa(ND) || llvm::isa(ND))) { + CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0); + const auto *CCS = SymbolCompletion.CreateCodeCompletionString( + *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator, + *CompletionTUInfo, + /*IncludeBriefComments*/ false); + DocComment = getDocComment(ND.getASTContext(), SymbolCompletion, + /*CommentsFromHeaders=*/true); + if (!S.Documentation.empty()) + Documentation = S.Documentation.str() + '\n' + DocComment; + else + Documentation = formatDocumentation(*CCS, DocComment); + if (!DocComment.empty()) + S.Flags |= Symbol::HasDocComment; + S.Documentation = Documentation; + } + Symbols.insert(S); } diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h index 20116fca7c51e..6ff7a0145ff87 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -161,7 +161,8 @@ class SymbolCollector : public index::IndexDataConsumer { private: const Symbol *addDeclaration(const NamedDecl &, SymbolID, bool IsMainFileSymbol); - void addDefinition(const NamedDecl &, const Symbol &DeclSymbol); + void addDefinition(const NamedDecl &, const Symbol &DeclSymbol, + bool SkipDocCheck); void processRelations(const NamedDecl &ND, const SymbolID &ID, ArrayRef Relations); diff --git a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp index bc0b984e577cb..7398e4258527b 100644 --- a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp +++ b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp @@ -29,7 +29,7 @@ class VolatileFileSystem : public llvm::vfs::ProxyFileSystem { : ProxyFileSystem(std::move(FS)) {} llvm::ErrorOr> - openFileForRead(const llvm::Twine &InPath, bool IsText = true) override { + openFileForRead(const llvm::Twine &InPath) override { llvm::SmallString<128> Path; InPath.toVector(Path); diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index e86385c2072b3..643b8e9f12d75 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -1010,7 +1010,7 @@ TEST(ClangdTests, PreambleVFSStatCache) { : ProxyFileSystem(std::move(FS)), CountStats(CountStats) {} llvm::ErrorOr> - openFileForRead(const Twine &Path, bool IsText = true) override { + openFileForRead(const Twine &Path) override { ++CountStats[llvm::sys::path::filename(Path.str())]; return ProxyFileSystem::openFileForRead(Path); } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 096f77e414f5a..efb2e5ed2fbe1 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -748,6 +748,10 @@ TEST(DiagnosticTest, ClangTidyEnablesClangWarning) { TU.ExtraArgs = {"-Wunused"}; TU.ClangTidyProvider = addClangArgs({"-Wno-unused"}, {}); EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty()); + + TU.ExtraArgs = {"-Wno-unused"}; + TU.ClangTidyProvider = addClangArgs({"-Wunused"}, {"-*, clang-diagnostic-*"}); + EXPECT_THAT(TU.build().getDiagnostics(), SizeIs(1)); } TEST(DiagnosticTest, LongFixMessages) { diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp index 1e7a30e69fabe..0666be95b6b9e 100644 --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -1477,6 +1477,58 @@ TEST_F(SymbolCollectorTest, Documentation) { forCodeCompletion(false)))); } +TEST_F(SymbolCollectorTest, DocumentationInMain) { + const std::string Header = R"( + // doc Foo + class Foo { + void f(); + }; + )"; + const std::string Main = R"( + // doc f + void Foo::f() {} + )"; + CollectorOpts.StoreAllDocumentation = true; + runSymbolCollector(Header, Main); + EXPECT_THAT(Symbols, + UnorderedElementsAre( + AllOf(qName("Foo"), doc("doc Foo"), forCodeCompletion(true)), + AllOf(qName("Foo::f"), doc("doc f"), returnType(""), + forCodeCompletion(false)))); +} + +TEST_F(SymbolCollectorTest, DocumentationAtDeclThenDef) { + const std::string Header = R"( + class Foo { + // doc f decl + void f(); + }; + )"; + const std::string Main = R"( + // doc f def + void Foo::f() {} + )"; + CollectorOpts.StoreAllDocumentation = true; + runSymbolCollector(Header, Main); + EXPECT_THAT(Symbols, + UnorderedElementsAre(AllOf(qName("Foo")), + AllOf(qName("Foo::f"), doc("doc f decl")))); +} + +TEST_F(SymbolCollectorTest, DocumentationAtDefThenDecl) { + const std::string Header = R"( + // doc f def + void f() {} + + // doc f decl + void f(); + )"; + CollectorOpts.StoreAllDocumentation = true; + runSymbolCollector(Header, "" /*Main*/); + EXPECT_THAT(Symbols, + UnorderedElementsAre(AllOf(qName("f"), doc("doc f def")))); +} + TEST_F(SymbolCollectorTest, ClassMembers) { const std::string Header = R"( class Foo { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index d032cef6b7616..8f7b0b5333f3a 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -117,6 +117,10 @@ Changes in existing checks ` check to suggest replacing the offending code with ``reinterpret_cast``, to more clearly express intent. +- Improved :doc:`bugprone-dangling-handle + ` check to treat `std::span` as a + handle class. + - Improved :doc:`bugprone-forwarding-reference-overload ` check by fixing a crash when determining if an ``enable_if[_t]`` was found. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/dangling-handle.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/dangling-handle.rst index 701b67d77acaa..752b711b4ef54 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/dangling-handle.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/dangling-handle.rst @@ -28,11 +28,18 @@ Examples: return Array; } + span g() { + array V; + return {V}; + int Array[10]{}; + return {Array}; + } + Options ------- .. option:: HandleClasses A semicolon-separated list of class names that should be treated as handles. - By default only ``std::basic_string_view`` and - ``std::experimental::basic_string_view`` are considered. + By default only ``std::basic_string_view``, + ``std::experimental::basic_string_view`` and ``std::span`` are considered. diff --git a/clang/README.md b/clang/README.md new file mode 100644 index 0000000000000..b98182d8a3f68 --- /dev/null +++ b/clang/README.md @@ -0,0 +1,25 @@ +# C language Family Front-end + +Welcome to Clang. + +This is a compiler front-end for the C family of languages (C, C++ and Objective-C) which is built as part of the LLVM compiler infrastructure project. + +Unlike many other compiler frontends, Clang is useful for a number of things beyond just compiling code: we intend for Clang to be host to a number of different source-level tools. One example of this is the Clang Static Analyzer. + +If you're interested in more (including how to build Clang) it is best to read the relevant websites. Here are some pointers: + +* Information on Clang:     http://clang.llvm.org/ + +* Building and using Clang: http://clang.llvm.org/get_started.html + +* Clang Static Analyzer: http://clang-analyzer.llvm.org/ + +* Information on the LLVM project: http://llvm.org/ + +* If you have questions or comments about Clang, a great place to disucss them is on the Clang forums:     + + [Clang Frontend - LLVM Discussion Forums](https://discourse.llvm.org/c/clang/) + +* If you find a bug in Clang, please file it in the LLVM bug tracker: + + https://github.com/llvm/llvm-project/issues diff --git a/clang/README.txt b/clang/README.txt deleted file mode 100644 index 477f720b193fb..0000000000000 --- a/clang/README.txt +++ /dev/null @@ -1,26 +0,0 @@ -//===----------------------------------------------------------------------===// -// C Language Family Front-end -//===----------------------------------------------------------------------===// - -Welcome to Clang. This is a compiler front-end for the C family of languages -(C, C++, Objective-C, and Objective-C++) which is built as part of the LLVM -compiler infrastructure project. - -Unlike many other compiler frontends, Clang is useful for a number of things -beyond just compiling code: we intend for Clang to be host to a number of -different source-level tools. One example of this is the Clang Static Analyzer. - -If you're interested in more (including how to build Clang) it is best to read -the relevant web sites. Here are some pointers: - -Information on Clang: http://clang.llvm.org/ -Building and using Clang: http://clang.llvm.org/get_started.html -Clang Static Analyzer: http://clang-analyzer.llvm.org/ -Information on the LLVM project: http://llvm.org/ - -If you have questions or comments about Clang, a great place to discuss them is -on the Clang forums: - https://discourse.llvm.org/c/clang/ - -If you find a bug in Clang, please file it in the LLVM bug tracker: - https://github.com/llvm/llvm-project/issues diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3f146cb9247a7..f4535db735619 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -403,6 +403,10 @@ Bug Fixes to C++ Support - Avoided a redundant friend declaration instantiation under a certain ``consteval`` context. (#GH107175) - Fixed an assertion failure in debug mode, and potential crashes in release mode, when diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter. +- Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326) +- Clang now uses the correct set of template argument lists when comparing the constraints of + out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of + a class template. (#GH102320) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 687715a22e9fd..05739f39d2a49 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -781,15 +781,11 @@ class RedeclarableTemplateDecl : public TemplateDecl, EntryType *Entry, void *InsertPos); struct CommonBase { - CommonBase() : InstantiatedFromMember(nullptr, false) {} + CommonBase() {} /// The template from which this was most /// directly instantiated (or null). - /// - /// The boolean value indicates whether this template - /// was explicitly specialized. - llvm::PointerIntPair - InstantiatedFromMember; + RedeclarableTemplateDecl *InstantiatedFromMember = nullptr; /// If non-null, points to an array of specializations (including /// partial specializations) known only by their external declaration IDs. @@ -809,14 +805,19 @@ class RedeclarableTemplateDecl : public TemplateDecl, }; /// Pointer to the common data shared by all declarations of this - /// template. - mutable CommonBase *Common = nullptr; + /// template, and a flag indicating if the template is a member + /// specialization. + mutable llvm::PointerIntPair Common; + + CommonBase *getCommonPtrInternal() const { return Common.getPointer(); } /// Retrieves the "common" pointer shared by all (re-)declarations of /// the same template. Calling this routine may implicitly allocate memory /// for the common pointer. CommonBase *getCommonPtr() const; + void setCommonPtr(CommonBase *C) const { Common.setPointer(C); } + virtual CommonBase *newCommon(ASTContext &C) const = 0; // Construct a template decl with name, parameters, and templated element. @@ -857,15 +858,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// template<> template /// struct X::Inner { /* ... */ }; /// \endcode - bool isMemberSpecialization() const { - return getCommonPtr()->InstantiatedFromMember.getInt(); - } + bool isMemberSpecialization() const { return Common.getInt(); } /// Note that this member template is a specialization. void setMemberSpecialization() { - assert(getCommonPtr()->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - getCommonPtr()->InstantiatedFromMember.setInt(true); + assert(!isMemberSpecialization() && "already a member specialization"); + Common.setInt(true); } /// Retrieve the member template from which this template was @@ -905,12 +903,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// void X::f(T, U); /// \endcode RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const { - return getCommonPtr()->InstantiatedFromMember.getPointer(); + return getCommonPtr()->InstantiatedFromMember; } void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { - assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); - getCommonPtr()->InstantiatedFromMember.setPointer(TD); + assert(!getCommonPtr()->InstantiatedFromMember); + getCommonPtr()->InstantiatedFromMember = TD; } /// Retrieve the "injected" template arguments that correspond to the @@ -1989,6 +1987,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// template arguments have been deduced. void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { + assert(!isa(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Already set to a class template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2000,6 +2000,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// Note that this class template specialization is an instantiation /// of the given class template. void setInstantiationOf(ClassTemplateDecl *TemplDecl) { + assert(!isa(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Previously set to a class template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2187,18 +2189,11 @@ class ClassTemplatePartialSpecializationDecl /// struct X::Inner { /* ... */ }; /// \endcode bool isMemberSpecialization() const { - const auto *First = - cast(getFirstDecl()); - return First->InstantiatedFromMember.getInt(); + return InstantiatedFromMember.getInt(); } /// Note that this member template is a specialization. - void setMemberSpecialization() { - auto *First = cast(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); - } + void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } /// Retrieves the injected specialization type for this partial /// specialization. This is not the same as the type-decl-type for @@ -2268,10 +2263,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { return static_cast(RedeclarableTemplateDecl::getCommonPtr()); } - void setCommonPtr(Common *C) { - RedeclarableTemplateDecl::Common = C; - } - public: friend class ASTDeclReader; @@ -2754,6 +2745,8 @@ class VarTemplateSpecializationDecl : public VarDecl, /// template arguments have been deduced. void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { + assert(!isa(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Already set to a variable template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2765,6 +2758,8 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Note that this variable template specialization is an instantiation /// of the given variable template. void setInstantiationOf(VarTemplateDecl *TemplDecl) { + assert(!isa(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Previously set to a variable template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2949,18 +2944,11 @@ class VarTemplatePartialSpecializationDecl /// U* X::Inner = (T*)(0) + 1; /// \endcode bool isMemberSpecialization() const { - const auto *First = - cast(getFirstDecl()); - return First->InstantiatedFromMember.getInt(); + return InstantiatedFromMember.getInt(); } /// Note that this member template is a specialization. - void setMemberSpecialization() { - auto *First = cast(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); - } + void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index be9ba7599fe5a..90441a5d50012 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -68,11 +68,6 @@ TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i64_f64, "LLid", "nc", "nontrappi // SIMD builtins TARGET_BUILTIN(__builtin_wasm_swizzle_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_sat_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_sat_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_sat_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_sat_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") - TARGET_BUILTIN(__builtin_wasm_sub_sat_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_sub_sat_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_sub_sat_s_i16x8, "V8sV8sV8s", "nc", "simd128") @@ -83,19 +78,6 @@ TARGET_BUILTIN(__builtin_wasm_abs_i16x8, "V8sV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_i32x4, "V4iV4i", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_i64x2, "V2LLiV2LLi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_s_i32x4, "V4iV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i32x4, "V4UiV4UiV4Ui", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_s_i32x4, "V4iV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i32x4, "V4UiV4UiV4Ui", "nc", "simd128") - TARGET_BUILTIN(__builtin_wasm_avgr_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_avgr_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index a85b72a398157..292e4af1b3b30 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -382,4 +382,8 @@ def err_ast_action_on_llvm_ir : Error< def err_os_unsupport_riscv_fmv : Error< "function multiversioning is currently only supported on Linux">; +def warn_hlsl_langstd_minimal : + Warning<"support for HLSL language version %0 is incomplete, " + "recommend using %1 instead">, + InGroup; } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e250f81a0b52a..7d81bdf827ea0 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1549,6 +1549,9 @@ def DXILValidation : DiagGroup<"dxil-validation">; // Warning for HLSL API availability def HLSLAvailability : DiagGroup<"hlsl-availability">; +// Warnings specifically for DXC incompatabilities. +def HLSLDXCCompat : DiagGroup<"hlsl-dxc-compatability">; + // Warnings for legacy binding behavior def LegacyConstantRegisterBinding : DiagGroup<"legacy-constant-register-binding">; diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 67a69fb79ccef..527bbef24793e 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -286,21 +286,21 @@ class FileManager : public RefCountedBase { /// MemoryBuffer if successful, otherwise returning null. llvm::ErrorOr> getBufferForFile(FileEntryRef Entry, bool isVolatile = false, - bool RequiresNullTerminator = true, bool IsText = true, + bool RequiresNullTerminator = true, std::optional MaybeLimit = std::nullopt); llvm::ErrorOr> getBufferForFile(StringRef Filename, bool isVolatile = false, - bool RequiresNullTerminator = true, bool IsText = true, + bool RequiresNullTerminator = true, std::optional MaybeLimit = std::nullopt) const { return getBufferForFileImpl(Filename, /*FileSize=*/(MaybeLimit ? *MaybeLimit : -1), - isVolatile, RequiresNullTerminator, IsText); + isVolatile, RequiresNullTerminator); } private: llvm::ErrorOr> getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile, - bool RequiresNullTerminator, bool IsText) const; + bool RequiresNullTerminator) const; DirectoryEntry *&getRealDirEntry(const llvm::vfs::Status &Status); diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6c6759f19f9b3..376d7d4290c0b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1994,18 +1994,16 @@ def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group, MarshallingInfoFlag>; def frecord_command_line : Flag<["-"], "frecord-command-line">, - DocBrief<[{Generate a section named ".GCC.command.line" containing the + DocBrief<[{Generate a section named ".GCC.command.line" containing the clang driver command-line. After linking, the section may contain multiple command lines, which will be individually terminated by null bytes. Separate arguments within a command line are combined with spaces; spaces and backslashes within an argument are escaped with backslashes. This format differs from the format of the equivalent section produced by GCC with the -frecord-gcc-switches flag. This option is currently only supported on ELF targets.}]>, - Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Group; def fno_record_command_line : Flag<["-"], "fno-record-command-line">, - Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Group; def : Flag<["-"], "frecord-gcc-switches">, Alias; def : Flag<["-"], "fno-record-gcc-switches">, Alias; def fcommon : Flag<["-"], "fcommon">, Group, @@ -7149,9 +7147,6 @@ def mrelocation_model : Separate<["-"], "mrelocation-model">, NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>, MarshallingInfoEnum, "PIC_">; def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; -def record_command_line : Separate<["-"], "record-command-line">, - HelpText<"The string to embed in the .LLVM.command.line section.">, - MarshallingInfoString>; } // let Visibility = [CC1Option, CC1AsOption, FC1Option] @@ -7172,6 +7167,9 @@ def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">, def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">, HelpText<"The string to embed in the Dwarf debug flags record.">, MarshallingInfoString>; +def record_command_line : Separate<["-"], "record-command-line">, + HelpText<"The string to embed in the .LLVM.command.line section.">, + MarshallingInfoString>; def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">, HelpText<"DWARF debug sections compression type">, Values<"none,zlib,zstd">, NormalizedValuesScope<"llvm::DebugCompressionType">, NormalizedValues<["None", "Zlib", "Zstd"]>, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 47f72135c97cf..eb8a851da7e04 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1355,6 +1355,10 @@ class Parser : public CodeCompletionHandler { void ParseLexedAttributes() override; void ParseLexedPragmas() override; + // Delete copy constructor and copy assignment operator. + LateParsedClass(const LateParsedClass &) = delete; + LateParsedClass &operator=(const LateParsedClass &) = delete; + private: Parser *Self; ParsingClass *Class; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e1c3a99cfa167..b86861ce7e8cf 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11389,9 +11389,9 @@ class Sema final : public SemaBase { CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, - TemplateParameterList **OuterTemplateParamLists, - SkipBodyInfo *SkipBody = nullptr); + SourceLocation FriendLoc, + ArrayRef OuterTemplateParamLists, + bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr); /// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. @@ -11430,7 +11430,8 @@ class Sema final : public SemaBase { DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization); + StorageClass SC, bool IsPartialSpecialization, + bool IsMemberSpecialization); /// Get the specialization of the given variable template corresponding to /// the specified argument list, or a null-but-valid result if the arguments @@ -13071,28 +13072,14 @@ class Sema final : public SemaBase { /// dealing with a specialization. This is only relevant for function /// template specializations. /// - /// \param Pattern If non-NULL, indicates the pattern from which we will be - /// instantiating the definition of the given declaration, \p ND. This is - /// used to determine the proper set of template instantiation arguments for - /// friend function template specializations. - /// /// \param ForConstraintInstantiation when collecting arguments, /// ForConstraintInstantiation indicates we should continue looking when /// encountering a lambda generic call operator, and continue looking for /// arguments on an enclosing class template. - /// - /// \param SkipForSpecialization when specified, any template specializations - /// in a traversal would be ignored. - /// \param ForDefaultArgumentSubstitution indicates we should continue looking - /// when encountering a specialized member function template, rather than - /// returning immediately. MultiLevelTemplateArgumentList getTemplateInstantiationArgs( const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false, std::optional> Innermost = std::nullopt, - bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool ForConstraintInstantiation = false, - bool SkipForSpecialization = false, - bool ForDefaultArgumentSubstitution = false); + bool RelativeToPrimary = false, bool ForConstraintInstantiation = false); /// RAII object to handle the state changes required to synthesize /// a function body. diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index 213c37b5091fe..9367c680953f7 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -208,22 +208,8 @@ class SemaObjC : public SemaBase { /// of -Wselector. llvm::MapVector ReferencedSelectors; - class GlobalMethodPool { - public: - using Lists = std::pair; - using iterator = llvm::DenseMap::iterator; - iterator begin() { return Methods.begin(); } - iterator end() { return Methods.end(); } - iterator find(Selector Sel) { return Methods.find(Sel); } - std::pair insert(std::pair &&Val) { - return Methods.insert(Val); - } - int count(Selector Sel) const { return Methods.count(Sel); } - bool empty() const { return Methods.empty(); } - - private: - llvm::DenseMap Methods; - }; + using GlobalMethodPool = + llvm::DenseMap>; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index 635fdd0e00c43..d12814e7c9253 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -346,7 +346,7 @@ class DependencyScanningWorkerFilesystem llvm::ErrorOr status(const Twine &Path) override; llvm::ErrorOr> - openFileForRead(const Twine &Path, bool IsText = true) override; + openFileForRead(const Twine &Path) override; std::error_code getRealPath(const Twine &Path, SmallVectorImpl &Output) override; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 17cf3ccdeb6a9..ede52de1c5e7b 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -90,10 +90,12 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD) { - if (!S.getLangOpts().CPlusPlus) + const SourceInfo &Loc = S.Current->getSource(OpPC); + if (!S.getLangOpts().CPlusPlus) { + S.FFDiag(Loc); return; + } - const SourceInfo &Loc = S.Current->getSource(OpPC); if (const auto *VarD = dyn_cast(VD); VarD && VarD->getType().isConstQualified() && !VarD->getAnyInitializer()) { @@ -620,6 +622,8 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) return false; + if (!CheckWeak(S, OpPC, Ptr)) + return false; if (!CheckMutable(S, OpPC, Ptr)) return false; return true; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 976b3a3e1eced..b779d79af81f2 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -309,16 +309,16 @@ bool TemplateDecl::isTypeAlias() const { void RedeclarableTemplateDecl::anchor() {} RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { - if (Common) - return Common; + if (CommonBase *C = getCommonPtrInternal()) + return C; // Walk the previous-declaration chain until we either find a declaration // with a common pointer or we run out of previous declarations. SmallVector PrevDecls; for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { - if (Prev->Common) { - Common = Prev->Common; + if (CommonBase *C = Prev->getCommonPtrInternal()) { + setCommonPtr(C); break; } @@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c } // If we never found a common pointer, allocate one now. - if (!Common) { + if (!getCommonPtrInternal()) { // FIXME: If any of the declarations is from an AST file, we probably // need an update record to add the common data. - Common = newCommon(getASTContext()); + setCommonPtr(newCommon(getASTContext())); } // Update any previous declarations we saw with the common pointer. for (const RedeclarableTemplateDecl *Prev : PrevDecls) - Prev->Common = Common; + Prev->setCommonPtr(getCommonPtrInternal()); - return Common; + return getCommonPtrInternal(); } void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { @@ -463,19 +463,17 @@ void FunctionTemplateDecl::addSpecialization( } void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { - using Base = RedeclarableTemplateDecl; - // If we haven't created a common pointer yet, then it can just be created // with the usual method. - if (!Base::Common) + if (!getCommonPtrInternal()) return; - Common *ThisCommon = static_cast(Base::Common); + Common *ThisCommon = static_cast(getCommonPtrInternal()); Common *PrevCommon = nullptr; SmallVector PreviousDecls; for (; Prev; Prev = Prev->getPreviousDecl()) { - if (Prev->Base::Common) { - PrevCommon = static_cast(Prev->Base::Common); + if (CommonBase *C = Prev->getCommonPtrInternal()) { + PrevCommon = static_cast(C); break; } PreviousDecls.push_back(Prev); @@ -485,7 +483,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { // use this common pointer. if (!PrevCommon) { for (auto *D : PreviousDecls) - D->Base::Common = ThisCommon; + D->setCommonPtr(ThisCommon); return; } @@ -493,7 +491,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { assert(ThisCommon->Specializations.size() == 0 && "Can't merge incompatible declarations!"); - Base::Common = PrevCommon; + setCommonPtr(PrevCommon); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 27075cefafdc2..6097b85a03064 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -530,7 +530,7 @@ void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { llvm::ErrorOr> FileManager::getBufferForFile(FileEntryRef FE, bool isVolatile, - bool RequiresNullTerminator, bool IsText, + bool RequiresNullTerminator, std::optional MaybeLimit) { const FileEntry *Entry = &FE.getFileEntry(); // If the content is living on the file entry, return a reference to it. @@ -558,21 +558,21 @@ FileManager::getBufferForFile(FileEntryRef FE, bool isVolatile, // Otherwise, open the file. return getBufferForFileImpl(Filename, FileSize, isVolatile, - RequiresNullTerminator, IsText); + RequiresNullTerminator); } llvm::ErrorOr> FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize, - bool isVolatile, bool RequiresNullTerminator, - bool IsText) const { + bool isVolatile, + bool RequiresNullTerminator) const { if (FileSystemOpts.WorkingDir.empty()) return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator, - isVolatile, IsText); + isVolatile); SmallString<128> FilePath(Filename); FixupRelativePath(FilePath); return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator, - isVolatile, IsText); + isVolatile); } /// getStatValue - Get the 'stat' information for the specified path, diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index fe3aff7a9af68..65a8a7253e054 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -121,18 +121,8 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, // Start with the assumption that the buffer is invalid to simplify early // return paths. IsBufferInvalid = true; - bool IsText = false; - -#ifdef __MVS__ - // If the file is tagged with a text ccsid, it may require autoconversion. - llvm::ErrorOr IsFileText = - llvm::iszOSTextFile(ContentsEntry->getName().data()); - if (IsFileText) - IsText = *IsFileText; -#endif - - auto BufferOrError = FM.getBufferForFile( - *ContentsEntry, IsFileVolatile, /*RequiresNullTerminator=*/true, IsText); + + auto BufferOrError = FM.getBufferForFile(*ContentsEntry, IsFileVolatile); // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 0b8e565345b6a..4917ef015941b 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -613,6 +613,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::Solaris: return std::make_unique>(Triple, Opts); + case llvm::Triple::UEFI: + return std::make_unique(Triple, Opts); + case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 0a4f06967fff5..a83d6464e789d 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -778,6 +778,21 @@ class LLVM_LIBRARY_VISIBILITY ZOSTargetInfo : public OSTargetInfo { } }; +// UEFI target +template +class LLVM_LIBRARY_VISIBILITY UEFITargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override {} + +public: + UEFITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + this->WIntType = TargetInfo::UnsignedShort; + } +}; + void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts, MacroBuilder &Builder); diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 79fd5867cf667..a99ae62984c7d 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -814,6 +814,43 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { } }; +// x86-64 UEFI target +class LLVM_LIBRARY_VISIBILITY UEFIX86_64TargetInfo + : public UEFITargetInfo { +public: + UEFIX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : UEFITargetInfo(Triple, Opts) { + this->TheCXXABI.set(TargetCXXABI::Microsoft); + this->MaxTLSAlign = 8192u * this->getCharWidth(); + this->resetDataLayout("e-m:w-p270:32:32-p271:32:32-p272:64:64-" + "i64:64-i128:128-f80:128-n8:16:32:64-S128"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + getOSDefines(Opts, X86TargetInfo::getTriple(), Builder); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Win64: + return CCCR_OK; + default: + return CCCR_Warning; + } + } + + TargetInfo::CallingConvKind + getCallingConvKind(bool ClangABICompat4) const override { + return CCK_MicrosoftWin64; + } +}; + // x86-64 Windows target class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo : public WindowsTargetInfo { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e2711f1ba7023..3d1138b777385 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -21443,24 +21443,12 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle); return Builder.CreateCall(Callee, {Src, Indices}); } - case WebAssembly::BI__builtin_wasm_add_sat_s_i8x16: - case WebAssembly::BI__builtin_wasm_add_sat_u_i8x16: - case WebAssembly::BI__builtin_wasm_add_sat_s_i16x8: - case WebAssembly::BI__builtin_wasm_add_sat_u_i16x8: case WebAssembly::BI__builtin_wasm_sub_sat_s_i8x16: case WebAssembly::BI__builtin_wasm_sub_sat_u_i8x16: case WebAssembly::BI__builtin_wasm_sub_sat_s_i16x8: case WebAssembly::BI__builtin_wasm_sub_sat_u_i16x8: { unsigned IntNo; switch (BuiltinID) { - case WebAssembly::BI__builtin_wasm_add_sat_s_i8x16: - case WebAssembly::BI__builtin_wasm_add_sat_s_i16x8: - IntNo = Intrinsic::sadd_sat; - break; - case WebAssembly::BI__builtin_wasm_add_sat_u_i8x16: - case WebAssembly::BI__builtin_wasm_add_sat_u_i16x8: - IntNo = Intrinsic::uadd_sat; - break; case WebAssembly::BI__builtin_wasm_sub_sat_s_i8x16: case WebAssembly::BI__builtin_wasm_sub_sat_s_i16x8: IntNo = Intrinsic::wasm_sub_sat_signed; @@ -21487,47 +21475,6 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond"); return Builder.CreateSelect(ICmp, Neg, Vec, "abs"); } - case WebAssembly::BI__builtin_wasm_min_s_i8x16: - case WebAssembly::BI__builtin_wasm_min_u_i8x16: - case WebAssembly::BI__builtin_wasm_max_s_i8x16: - case WebAssembly::BI__builtin_wasm_max_u_i8x16: - case WebAssembly::BI__builtin_wasm_min_s_i16x8: - case WebAssembly::BI__builtin_wasm_min_u_i16x8: - case WebAssembly::BI__builtin_wasm_max_s_i16x8: - case WebAssembly::BI__builtin_wasm_max_u_i16x8: - case WebAssembly::BI__builtin_wasm_min_s_i32x4: - case WebAssembly::BI__builtin_wasm_min_u_i32x4: - case WebAssembly::BI__builtin_wasm_max_s_i32x4: - case WebAssembly::BI__builtin_wasm_max_u_i32x4: { - Value *LHS = EmitScalarExpr(E->getArg(0)); - Value *RHS = EmitScalarExpr(E->getArg(1)); - Value *ICmp; - switch (BuiltinID) { - case WebAssembly::BI__builtin_wasm_min_s_i8x16: - case WebAssembly::BI__builtin_wasm_min_s_i16x8: - case WebAssembly::BI__builtin_wasm_min_s_i32x4: - ICmp = Builder.CreateICmpSLT(LHS, RHS); - break; - case WebAssembly::BI__builtin_wasm_min_u_i8x16: - case WebAssembly::BI__builtin_wasm_min_u_i16x8: - case WebAssembly::BI__builtin_wasm_min_u_i32x4: - ICmp = Builder.CreateICmpULT(LHS, RHS); - break; - case WebAssembly::BI__builtin_wasm_max_s_i8x16: - case WebAssembly::BI__builtin_wasm_max_s_i16x8: - case WebAssembly::BI__builtin_wasm_max_s_i32x4: - ICmp = Builder.CreateICmpSGT(LHS, RHS); - break; - case WebAssembly::BI__builtin_wasm_max_u_i8x16: - case WebAssembly::BI__builtin_wasm_max_u_i16x8: - case WebAssembly::BI__builtin_wasm_max_u_i32x4: - ICmp = Builder.CreateICmpUGT(LHS, RHS); - break; - default: - llvm_unreachable("unexpected builtin ID"); - } - return Builder.CreateSelect(ICmp, LHS, RHS); - } case WebAssembly::BI__builtin_wasm_avgr_u_i8x16: case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: { Value *LHS = EmitScalarExpr(E->getArg(0)); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index f22321f0e738a..dd65080a84044 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -738,7 +738,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { // Zero-sized fields are not emitted, but their initializers may still // prevent emission of this struct as a constant. if (isEmptyFieldForLayout(CGM.getContext(), Field)) { - if (Init->HasSideEffects(CGM.getContext())) + if (Init && Init->HasSideEffects(CGM.getContext())) return false; continue; } diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 32a4378ab499f..4fd10bf671512 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -78,6 +78,7 @@ add_clang_library(clangDriver ToolChains/Solaris.cpp ToolChains/SPIRV.cpp ToolChains/TCE.cpp + ToolChains/UEFI.cpp ToolChains/VEToolchain.cpp ToolChains/WebAssembly.cpp ToolChains/XCore.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 1c64ceabad1bf..44548fa9d706f 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -45,6 +45,7 @@ #include "ToolChains/SPIRV.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" +#include "ToolChains/UEFI.h" #include "ToolChains/VEToolchain.h" #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" @@ -6422,6 +6423,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Mesa3D: TC = std::make_unique(*this, Target, Args); break; + case llvm::Triple::UEFI: + TC = std::make_unique(*this, Target, Args); + break; case llvm::Triple::Win32: switch (Target.getEnvironment()) { default: diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index d43e683e46852..3f0b3f2d86b3e 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -120,6 +120,11 @@ AMDGPUOpenMPToolChain::GetCXXStdlibType(const ArgList &Args) const { return HostTC.GetCXXStdlibType(Args); } +void AMDGPUOpenMPToolChain::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + void AMDGPUOpenMPToolChain::AddClangSystemIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h index 2be444a42c55f..0536c9f7f564c 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h @@ -42,6 +42,9 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUOpenMPToolChain final Action::OffloadKind DeviceOffloadKind) const override; void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0a2c7b67cc2f0..0bab48caf1a5e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -94,6 +94,24 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { << "-static"; } +// Add backslashes to escape spaces and other backslashes. +// This is used for the space-separated argument list specified with +// the -dwarf-debug-flags option. +static void EscapeSpacesAndBackslashes(const char *Arg, + SmallVectorImpl &Res) { + for (; *Arg; ++Arg) { + switch (*Arg) { + default: + break; + case ' ': + case '\\': + Res.push_back('\\'); + break; + } + Res.push_back(*Arg); + } +} + /// Apply \a Work on the current tool chain \a RegularToolChain and any other /// offloading tool chain that is associated with the current action \a JA. static void @@ -7687,10 +7705,31 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Also record command line arguments into the debug info if // -grecord-gcc-switches options is set on. // By default, -gno-record-gcc-switches is set on and no recording. - auto GRecordSwitches = false; - auto FRecordSwitches = false; - if (shouldRecordCommandLine(TC, Args, FRecordSwitches, GRecordSwitches)) { - auto FlagsArgString = renderEscapedCommandLine(TC, Args); + auto GRecordSwitches = + Args.hasFlag(options::OPT_grecord_command_line, + options::OPT_gno_record_command_line, false); + auto FRecordSwitches = + Args.hasFlag(options::OPT_frecord_command_line, + options::OPT_fno_record_command_line, false); + if (FRecordSwitches && !Triple.isOSBinFormatELF() && + !Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) + << TripleStr; + if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) { + ArgStringList OriginalArgs; + for (const auto &Arg : Args) + Arg->render(Args, OriginalArgs); + + SmallString<256> Flags; + EscapeSpacesAndBackslashes(Exec, Flags); + for (const char *OriginalArg : OriginalArgs) { + SmallString<128> EscapedArg; + EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); + Flags += " "; + Flags += EscapedArg; + } + auto FlagsArgString = Args.MakeArgString(Flags); if (TC.UseDwarfDebugFlags() || GRecordSwitches) { CmdArgs.push_back("-dwarf-debug-flags"); CmdArgs.push_back(FlagsArgString); @@ -8690,10 +8729,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, SmallString<256> Flags; const char *Exec = getToolChain().getDriver().getClangProgramPath(); - escapeSpacesAndBackslashes(Exec, Flags); + EscapeSpacesAndBackslashes(Exec, Flags); for (const char *OriginalArg : OriginalArgs) { SmallString<128> EscapedArg; - escapeSpacesAndBackslashes(OriginalArg, EscapedArg); + EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); Flags += " "; Flags += EscapedArg; } diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 102e5231d3160..043d9e4876443 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -2960,62 +2960,3 @@ void tools::addMCModel(const Driver &D, const llvm::opt::ArgList &Args, } } } - -void tools::escapeSpacesAndBackslashes(const char *Arg, - llvm::SmallVectorImpl &Res) { - for (; *Arg; ++Arg) { - switch (*Arg) { - default: - break; - case ' ': - case '\\': - Res.push_back('\\'); - break; - } - Res.push_back(*Arg); - } -} - -const char *tools::renderEscapedCommandLine(const ToolChain &TC, - const llvm::opt::ArgList &Args) { - const Driver &D = TC.getDriver(); - const char *Exec = D.getClangProgramPath(); - - llvm::opt::ArgStringList OriginalArgs; - for (const auto &Arg : Args) - Arg->render(Args, OriginalArgs); - - llvm::SmallString<256> Flags; - escapeSpacesAndBackslashes(Exec, Flags); - for (const char *OriginalArg : OriginalArgs) { - llvm::SmallString<128> EscapedArg; - escapeSpacesAndBackslashes(OriginalArg, EscapedArg); - Flags += " "; - Flags += EscapedArg; - } - - return Args.MakeArgString(Flags); -} - -bool tools::shouldRecordCommandLine(const ToolChain &TC, - const llvm::opt::ArgList &Args, - bool &FRecordCommandLine, - bool &GRecordCommandLine) { - const Driver &D = TC.getDriver(); - const llvm::Triple &Triple = TC.getEffectiveTriple(); - const std::string &TripleStr = Triple.getTriple(); - - FRecordCommandLine = - Args.hasFlag(options::OPT_frecord_command_line, - options::OPT_fno_record_command_line, false); - GRecordCommandLine = - Args.hasFlag(options::OPT_grecord_command_line, - options::OPT_gno_record_command_line, false); - if (FRecordCommandLine && !Triple.isOSBinFormatELF() && - !Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO()) - D.Diag(diag::err_drv_unsupported_opt_for_target) - << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) - << TripleStr; - - return FRecordCommandLine || TC.UseDwarfDebugFlags() || GRecordCommandLine; -} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index e9b42bb872ed5..8695d3fe5b55b 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -233,31 +233,6 @@ void addMCModel(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Reloc::Model &RelocationModel, llvm::opt::ArgStringList &CmdArgs); -/// Add backslashes to escape spaces and other backslashes. -/// This is used for the space-separated argument list specified with -/// the -dwarf-debug-flags option. -void escapeSpacesAndBackslashes(const char *Arg, - llvm::SmallVectorImpl &Res); - -/// Join the args in the given ArgList, escape spaces and backslashes and -/// return the joined string. This is used when saving the command line as a -/// result of using either the -frecord-command-line or -grecord-command-line -/// options. The lifetime of the returned c-string will match that of the Args -/// argument. -const char *renderEscapedCommandLine(const ToolChain &TC, - const llvm::opt::ArgList &Args); - -/// Check if the command line should be recorded in the object file. This is -/// done if either -frecord-command-line or -grecord-command-line options have -/// been passed. This also does some error checking since -frecord-command-line -/// is currently only supported on ELF platforms. The last two boolean -/// arguments are out parameters and will be set depending on the command -/// line options that were passed. -bool shouldRecordCommandLine(const ToolChain &TC, - const llvm::opt::ArgList &Args, - bool &FRecordCommandLine, - bool &GRecordCommandLine); - } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 65c29b3dd7f65..6ce79d27e98c4 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -885,20 +885,6 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, addDashXForInput(Args, Input, CmdArgs); - bool FRecordCmdLine = false; - bool GRecordCmdLine = false; - if (shouldRecordCommandLine(TC, Args, FRecordCmdLine, GRecordCmdLine)) { - const char *CmdLine = renderEscapedCommandLine(TC, Args); - if (FRecordCmdLine) { - CmdArgs.push_back("-record-command-line"); - CmdArgs.push_back(CmdLine); - } - if (TC.UseDwarfDebugFlags() || GRecordCmdLine) { - CmdArgs.push_back("-dwarf-debug-flags"); - CmdArgs.push_back(CmdLine); - } - } - CmdArgs.push_back(Input.getFilename()); // TODO: Replace flang-new with flang once the new driver replaces the diff --git a/clang/lib/Driver/ToolChains/UEFI.cpp b/clang/lib/Driver/ToolChains/UEFI.cpp new file mode 100644 index 0000000000000..66cbbec59246c --- /dev/null +++ b/clang/lib/Driver/ToolChains/UEFI.cpp @@ -0,0 +1,88 @@ +//===--- UEFI.cpp - UEFI ToolChain Implementations -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "UEFI.h" +#include "CommonArgs.h" +#include "Darwin.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : ToolChain(D, Triple, Args) {} + +Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); } + +void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + auto &TC = static_cast(getToolChain()); + + assert((Output.isFilename() || Output.isNothing()) && "invalid output"); + if (Output.isFilename()) + CmdArgs.push_back( + Args.MakeArgString(std::string("-out:") + Output.getFilename())); + + CmdArgs.push_back("-nologo"); + + // TODO: Other UEFI binary subsystems that are currently unsupported: + // efi_boot_service_driver, efi_rom, efi_runtime_driver. + CmdArgs.push_back("-subsystem:efi_application"); + + // Default entry function name according to the TianoCore reference + // implementation is EfiMain. + // TODO: Provide a flag to override the entry function name. + CmdArgs.push_back("-entry:EfiMain"); + + // "Terminal Service Aware" flag is not needed for UEFI applications. + CmdArgs.push_back("-tsaware:no"); + + // EFI_APPLICATION to be linked as DLL by default. + CmdArgs.push_back("-dll"); + + if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) + CmdArgs.push_back("-debug"); + + Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + // This should ideally be handled by ToolChain::GetLinkerPath but we need + // to special case some linker paths. In the case of lld, we need to + // translate 'lld' into 'lld-link'. + StringRef Linker = + Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); + if (Linker.empty() || Linker == "lld") + Linker = "lld-link"; + + auto LinkerPath = TC.GetProgramPath(Linker.str().c_str()); + auto LinkCmd = std::make_unique( + JA, *this, ResponseFileSupport::AtFileUTF16(), + Args.MakeArgString(LinkerPath), CmdArgs, Inputs, Output); + C.addCommand(std::move(LinkCmd)); +} diff --git a/clang/lib/Driver/ToolChains/UEFI.h b/clang/lib/Driver/ToolChains/UEFI.h new file mode 100644 index 0000000000000..a126ac32db6c6 --- /dev/null +++ b/clang/lib/Driver/ToolChains/UEFI.h @@ -0,0 +1,59 @@ +//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang::driver { +namespace tools { +namespace uefi { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("uefi::Linker", "lld-link", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace uefi +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY UEFI : public ToolChain { +public: + UEFI(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildLinker() const override; + +public: + bool HasNativeLLVMSupport() const override { return true; } + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; + } + bool isPICDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return true; } +}; + +} // namespace toolchains +} // namespace clang::driver + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 6f09835bad3a8..f665ce2ad81eb 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -300,7 +300,7 @@ class AnnotatingParser { return false; } - bool parseParens(bool LookForDecls = false) { + bool parseParens(bool IsIf = false) { if (!CurrentToken) return false; assert(CurrentToken->Previous && "Unknown previous token"); @@ -468,24 +468,6 @@ class AnnotatingParser { OpeningParen.Previous && OpeningParen.Previous->is(tok::kw_for); FormatToken *PossibleObjCForInToken = nullptr; while (CurrentToken) { - // LookForDecls is set when "if (" has been seen. Check for - // 'identifier' '*' 'identifier' followed by not '=' -- this - // '*' has to be a binary operator but determineStarAmpUsage() will - // categorize it as an unary operator, so set the right type here. - if (LookForDecls && CurrentToken->Next) { - FormatToken *Prev = CurrentToken->getPreviousNonComment(); - if (Prev) { - FormatToken *PrevPrev = Prev->getPreviousNonComment(); - FormatToken *Next = CurrentToken->Next; - if (PrevPrev && PrevPrev->is(tok::identifier) && - PrevPrev->isNot(TT_TypeName) && Prev->isPointerOrReference() && - CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { - Prev->setType(TT_BinaryOperator); - LookForDecls = false; - } - } - } - if (CurrentToken->Previous->is(TT_PointerOrReference) && CurrentToken->Previous->Previous->isOneOf(tok::l_paren, tok::coloncolon)) { @@ -581,6 +563,15 @@ class AnnotatingParser { PossibleObjCForInToken = nullptr; } } + if (IsIf && CurrentToken->is(tok::semi)) { + for (auto *Tok = OpeningParen.Next; + Tok != CurrentToken && + !Tok->isOneOf(tok::equal, tok::l_paren, tok::l_brace); + Tok = Tok->Next) { + if (Tok->isPointerOrReference()) + Tok->setFinalizedType(TT_PointerOrReference); + } + } if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) { PossibleObjCForInToken = CurrentToken; PossibleObjCForInToken->setType(TT_ObjCForIn); @@ -1307,7 +1298,7 @@ class AnnotatingParser { // Multi-line string itself is a single annotated token. if (Tok->is(TT_TableGenMultiLineString)) return true; - switch (Tok->Tok.getKind()) { + switch (bool IsIf = false; Tok->Tok.getKind()) { case tok::plus: case tok::minus: if (!Tok->Previous && Line.MustBeDeclaration) @@ -1407,6 +1398,12 @@ class AnnotatingParser { } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->setType(TT_RangeBasedForLoopColon); + for (auto *Prev = Tok->Previous; + Prev && !Prev->isOneOf(tok::semi, tok::l_paren); + Prev = Prev->Previous) { + if (Prev->isPointerOrReference()) + Prev->setFinalizedType(TT_PointerOrReference); + } } else if (Contexts.back().ContextType == Context::C11GenericSelection) { Tok->setType(TT_GenericSelectionColon); } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { @@ -1461,11 +1458,12 @@ class AnnotatingParser { CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) { next(); } + IsIf = true; [[fallthrough]]; case tok::kw_while: if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); - if (!parseParens(/*LookForDecls=*/true)) + if (!parseParens(IsIf)) return false; } break; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index de6776b3f9da1..efd852593468a 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4484,6 +4484,15 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, } } else Diags.Report(diag::err_drv_hlsl_unsupported_target) << T.str(); + + if (Opts.LangStd < LangStandard::lang_hlsl202x) { + const LangStandard &Requested = + LangStandard::getLangStandardForKind(Opts.LangStd); + const LangStandard &Recommended = + LangStandard::getLangStandardForKind(LangStandard::lang_hlsl202x); + Diags.Report(diag::warn_hlsl_langstd_minimal) + << Requested.getName() << Recommended.getName(); + } } return Diags.getNumErrors() == NumErrorsBefore; diff --git a/clang/lib/Headers/hlsl.h b/clang/lib/Headers/hlsl.h index a9dce4503ddd9..6edfd949f2b97 100644 --- a/clang/lib/Headers/hlsl.h +++ b/clang/lib/Headers/hlsl.h @@ -9,7 +9,18 @@ #ifndef _HLSL_H_ #define _HLSL_H_ +#if defined(__clang__) +// Don't warn about any of the DXC compatibility warnings in the clang-only +// headers since these will never be used with DXC anyways. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Whlsl-dxc-compatability" +#endif + #include "hlsl/hlsl_basic_types.h" #include "hlsl/hlsl_intrinsics.h" +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + #endif //_HLSL_H_ diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h index 9801d86208159..8d5fd94133153 100644 --- a/clang/lib/Headers/hlsl/hlsl_detail.h +++ b/clang/lib/Headers/hlsl/hlsl_detail.h @@ -13,23 +13,23 @@ namespace hlsl { namespace __detail { -#define _HLSL_INLINE \ - __attribute__((__always_inline__, __nodebug__)) static inline - template struct enable_if {}; template struct enable_if { using Type = T; }; +template +using enable_if_t = typename enable_if::Type; + template -_HLSL_INLINE typename enable_if >::Type +constexpr enable_if_t> bit_cast(vector V) { return __builtin_bit_cast(vector, V); } template -_HLSL_INLINE typename enable_if::Type bit_cast(T F) { +constexpr enable_if_t bit_cast(T F) { return __builtin_bit_cast(U, F); } diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 6cd6a2caf1999..b139f9eb7d999 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -370,11 +370,11 @@ bool any(double4); /// \param Val The input value. template -_HLSL_INLINE vector asfloat(vector V) { +constexpr vector asfloat(vector V) { return __detail::bit_cast(V); } -template _HLSL_INLINE float asfloat(T F) { +template constexpr float asfloat(T F) { return __detail::bit_cast(F); } @@ -414,12 +414,11 @@ float4 asin(float4); /// \brief Interprets the bit pattern of x as an unsigned integer. /// \param Val The input value. -template -_HLSL_INLINE vector asuint(vector V) { +template constexpr vector asuint(vector V) { return __detail::bit_cast(V); } -template _HLSL_INLINE uint asuint(T F) { +template constexpr uint asuint(T F) { return __detail::bit_cast(F); } diff --git a/clang/lib/Headers/wasm_simd128.h b/clang/lib/Headers/wasm_simd128.h index 22f0e27ccf756..b1bef7097800b 100644 --- a/clang/lib/Headers/wasm_simd128.h +++ b/clang/lib/Headers/wasm_simd128.h @@ -982,12 +982,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_add(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_add_sat(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_sat_s_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_elementwise_add_sat((__i8x16)__a, (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_add_sat(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_sat_u_i8x16((__u8x16)__a, (__u8x16)__b); + return (v128_t)__builtin_elementwise_add_sat((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_sub(v128_t __a, @@ -1007,22 +1007,22 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_sub_sat(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_s_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_elementwise_min((__i8x16)__a, (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i8x16((__u8x16)__a, (__u8x16)__b); + return (v128_t)__builtin_elementwise_min((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_s_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_elementwise_max((__i8x16)__a, (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i8x16((__u8x16)__a, (__u8x16)__b); + return (v128_t)__builtin_elementwise_max((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_avgr(v128_t __a, @@ -1068,12 +1068,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_add(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_add_sat(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_sat_s_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_elementwise_add_sat((__i16x8)__a, (__i16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_add_sat(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_sat_u_i16x8((__u16x8)__a, (__u16x8)__b); + return (v128_t)__builtin_elementwise_add_sat((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_sub(v128_t __a, @@ -1098,22 +1098,22 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_mul(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_s_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_elementwise_min((__i16x8)__a, (__i16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i16x8((__u16x8)__a, (__u16x8)__b); + return (v128_t)__builtin_elementwise_min((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_s_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_elementwise_max((__i16x8)__a, (__i16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i16x8((__u16x8)__a, (__u16x8)__b); + return (v128_t)__builtin_elementwise_max((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_avgr(v128_t __a, @@ -1169,22 +1169,22 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_mul(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_s_i32x4((__i32x4)__a, (__i32x4)__b); + return (v128_t)__builtin_elementwise_min((__i32x4)__a, (__i32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i32x4((__u32x4)__a, (__u32x4)__b); + return (v128_t)__builtin_elementwise_min((__u32x4)__a, (__u32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_s_i32x4((__i32x4)__a, (__i32x4)__b); + return (v128_t)__builtin_elementwise_max((__i32x4)__a, (__i32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i32x4((__u32x4)__a, (__u32x4)__b); + return (v128_t)__builtin_elementwise_max((__u32x4)__a, (__u32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_dot_i16x8(v128_t __a, diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 6a1b32598bb4a..8b83418c897f8 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -585,8 +585,8 @@ static bool CheckConstraintSatisfaction( ArrayRef TemplateArgs = TemplateArgsLists.getNumSubstitutedLevels() > 0 - ? TemplateArgsLists.getOutermost() - : ArrayRef {}; + ? TemplateArgsLists.getInnermost() + : ArrayRef{}; Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), Sema::InstantiatingTemplate::ConstraintsCheck{}, const_cast(Template), TemplateArgs, TemplateIDRange); @@ -833,7 +833,6 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope( getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) return std::nullopt; @@ -909,15 +908,13 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, // Figure out the to-translation-unit depth for this function declaration for // the purpose of seeing if they differ by constraints. This isn't the same as // getTemplateDepth, because it includes already instantiated parents. -static unsigned -CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, - bool SkipForSpecialization = false) { +static unsigned CalculateTemplateDepthForConstraints(Sema &S, + const NamedDecl *ND) { MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( ND, ND->getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true, SkipForSpecialization); + /*ForConstraintInstantiation=*/true); return MLTAL.getNumLevels(); } @@ -956,8 +953,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, - /*SkipForSpecialization*/ false); + /*ForConstraintInstantiation=*/true); if (MLTAL.getNumSubstitutedLevels() == 0) return ConstrExpr; @@ -1063,16 +1059,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { assert(FD->getFriendObjectKind() && "Must be a friend!"); + FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate(); // The logic for non-templates is handled in ASTContext::isSameEntity, so we // don't have to bother checking 'DependsOnEnclosingTemplate' for a // non-function-template. - assert(FD->getDescribedFunctionTemplate() && - "Non-function templates don't need to be checked"); + assert(FTD && "Non-function templates don't need to be checked"); SmallVector ACs; - FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs); + FTD->getAssociatedConstraints(ACs); - unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD); + unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth(); for (const Expr *Constraint : ACs) if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth, Constraint)) @@ -1519,7 +1515,6 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(), /*Final=*/false, CSE->getTemplateArguments(), /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, @@ -1800,8 +1795,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, return false; } - unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true); - unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true); + unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1); + unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2); for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { if (Depth2 > Depth1) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 31bf50a32a83c..de8805e15bc75 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4505,10 +4505,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { adjustDeclContextForDeclaratorDecl(New, Old); // Ensure the template parameters are compatible. - if (NewTemplate && - !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), - /*Complain=*/true, TPL_TemplateMatch)) + if (NewTemplate && !TemplateParameterListsAreEqual( + NewTemplate, NewTemplate->getTemplateParameters(), + OldTemplate, OldTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) return New->setInvalidDecl(); // C++ [class.mem]p1: @@ -7655,7 +7655,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC, - IsPartialSpecialization); + IsPartialSpecialization, IsMemberSpecialization); if (Res.isInvalid()) return nullptr; NewVD = cast(Res.get()); @@ -7674,6 +7674,10 @@ NamedDecl *Sema::ActOnVariableDeclarator( VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, TemplateParams, NewVD); NewVD->setDescribedVarTemplate(NewTemplate); + // If we are providing an explicit specialization of a static variable + // template, make a note of that. + if (IsMemberSpecialization) + NewTemplate->setMemberSpecialization(); } // If this decl has an auto type in need of deduction, make a note of the @@ -8049,12 +8053,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( ? TPC_ClassTemplateMember : TPC_VarTemplate)) NewVD->setInvalidDecl(); - - // If we are providing an explicit specialization of a static variable - // template, make a note of that. - if (PrevVarTemplate && - PrevVarTemplate->getInstantiatedFromMemberTemplate()) - PrevVarTemplate->setMemberSpecialization(); } } @@ -9859,6 +9857,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD); FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); + if (isMemberSpecialization) + FunctionTemplate->setMemberSpecialization(); // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { @@ -12005,10 +12005,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // If this is an explicit specialization of a member that is a function // template, mark it as a member specialization. - if (IsMemberSpecialization && - NewTemplateDecl->getInstantiatedFromMemberTemplate()) { - NewTemplateDecl->setMemberSpecialization(); - assert(OldTemplateDecl->isMemberSpecialization()); + if (IsMemberSpecialization) { // Explicit specializations of a member template do not inherit deleted // status from the parent member template that they are specializing. if (OldFD->isDeleted()) { @@ -17067,8 +17064,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, DeclResult Result = CheckClassTemplate( S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, AS, ModulePrivateLoc, - /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, - TemplateParameterLists.data(), SkipBody); + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), + isMemberSpecialization, SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d8cdfcf8c6ec0..31cd6802a39fa 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17416,8 +17416,8 @@ DeclResult Sema::ActOnTemplatedFriendTag( return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), - FriendLoc, TempParamLists.size() - 1, - TempParamLists.data()) + FriendLoc, TempParamLists.drop_back(), + IsMemberSpecialization) .get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 807453400abdd..d8cd09b827293 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3441,16 +3441,11 @@ void SemaObjC::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, if (SemaRef.ExternalSource) ReadMethodPool(Method->getSelector()); - GlobalMethodPool::iterator Pos = MethodPool.find(Method->getSelector()); - if (Pos == MethodPool.end()) - Pos = MethodPool - .insert(std::make_pair(Method->getSelector(), - GlobalMethodPool::Lists())) - .first; + auto &Lists = MethodPool[Method->getSelector()]; Method->setDefined(impl); - ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; + ObjCMethodList &Entry = instance ? Lists.first : Lists.second; addMethodToGlobalList(&Entry, Method); } @@ -3654,7 +3649,7 @@ ObjCMethodDecl *SemaObjC::LookupImplementedMethodInGlobalPool(Selector Sel) { if (Pos == MethodPool.end()) return nullptr; - GlobalMethodPool::Lists &Methods = Pos->second; + auto &Methods = Pos->second; for (const ObjCMethodList *Method = &Methods.first; Method; Method = Method->getNext()) if (Method->getMethod() && diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2f7e9c754ce09..66df9c969256a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9868,7 +9868,9 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, // if necessary. CastKind scalarCast = CK_NoOp; - if (vectorEltTy->isIntegralType(S.Context)) { + if (vectorEltTy->isBooleanType() && scalarTy->isIntegralType(S.Context)) { + scalarCast = CK_IntegralToBoolean; + } else if (vectorEltTy->isIntegralType(S.Context)) { if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() || (scalarTy->isIntegerType() && S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0))) { diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index e1fc9cea1eb2b..ecbcc19413dc6 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -1101,51 +1101,6 @@ SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, return Result; - // switch (Clause.getClauseKind()) { - // case OpenACCClauseKind::PresentOrCopy: - // case OpenACCClauseKind::PCopy: - // Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name) - // << Clause.getClauseKind() << OpenACCClauseKind::Copy; - // LLVM_FALLTHROUGH; - // case OpenACCClauseKind::PresentOrCreate: - // case OpenACCClauseKind::PCreate: - // Diag(Clause.getBeginLoc(), diag::warn_acc_deprecated_alias_name) - // << Clause.getClauseKind() << OpenACCClauseKind::Create; - // LLVM_FALLTHROUGH; - // - // - // - // - // case OpenACCClauseKind::DType: - // - // - // - // - // - // - // - // - // case OpenACCClauseKind::Gang: - // case OpenACCClauseKind::Worker: - // case OpenACCClauseKind::Vector: { - // // OpenACC 3.3 2.9: - // // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' - // clause - // // appears. - // const auto *Itr = - // llvm::find_if(ExistingClauses, llvm::IsaPred); - // - // if (Itr != ExistingClauses.end()) { - // Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) - // << Clause.getClauseKind() << (*Itr)->getClauseKind(); - // Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); - // } - // // Not yet implemented, so immediately drop to the 'not yet implemented' - // // diagnostic. - // break; - // } - // */ - } /// OpenACC 3.3 section 2.5.15: diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index b052afede2cd6..16f4542d78571 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1793,8 +1793,9 @@ DeclResult Sema::CheckClassTemplate( CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, - TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) { + SourceLocation FriendLoc, + ArrayRef OuterTemplateParamLists, + bool IsMemberSpecialization, SkipBodyInfo *SkipBody) { assert(TemplateParams && TemplateParams->size() > 0 && "No template parameters"); assert(TUK != TagUseKind::Reference && @@ -1982,19 +1983,6 @@ DeclResult Sema::CheckClassTemplate( } if (PrevClassTemplate) { - // Ensure that the template parameter lists are compatible. Skip this check - // for a friend in a dependent context: the template parameter list itself - // could be dependent. - if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && - !TemplateParameterListsAreEqual( - TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext - : CurContext, - CurContext, KWLoc), - TemplateParams, PrevClassTemplate, - PrevClassTemplate->getTemplateParameters(), /*Complain=*/true, - TPL_TemplateMatch)) - return true; - // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -2009,30 +1997,6 @@ DeclResult Sema::CheckClassTemplate( Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); Kind = PrevRecordDecl->getTagKind(); } - - // Check for redefinition of this class template. - if (TUK == TagUseKind::Definition) { - if (TagDecl *Def = PrevRecordDecl->getDefinition()) { - // If we have a prior definition that is not visible, treat this as - // simply making that previous definition visible. - NamedDecl *Hidden = nullptr; - if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { - SkipBody->ShouldSkip = true; - SkipBody->Previous = Def; - auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); - assert(Tmpl && "original definition of a class template is not a " - "class template?"); - makeMergedDefinitionVisible(Hidden); - makeMergedDefinitionVisible(Tmpl); - } else { - Diag(NameLoc, diag::err_redefinition) << Name; - Diag(Def->getLocation(), diag::note_previous_definition); - // FIXME: Would it make sense to try to "forget" the previous - // definition, as part of error recovery? - return true; - } - } - } } else if (PrevDecl) { // C++ [temp]p5: // A class template shall not have the same name as any other @@ -2044,23 +2008,6 @@ DeclResult Sema::CheckClassTemplate( return true; } - // Check the template parameter list of this declaration, possibly - // merging in the template parameter list from the previous class - // template declaration. Skip this check for a friend in a dependent - // context, because the template parameter list might be dependent. - if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && - CheckTemplateParameterList( - TemplateParams, - PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate) - : nullptr, - (SS.isSet() && SemanticContext && SemanticContext->isRecord() && - SemanticContext->isDependentContext()) - ? TPC_ClassTemplateMember - : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate - : TPC_ClassTemplate, - SkipBody)) - Invalid = true; - if (SS.isSet()) { // If the name of the template was qualified, we must be defining the // template out-of-line. @@ -2087,10 +2034,8 @@ DeclResult Sema::CheckClassTemplate( PrevClassTemplate->getTemplatedDecl() : nullptr, /*DelayTypeCreation=*/true); SetNestedNameSpecifier(*this, NewClass, SS); - if (NumOuterTemplateParamLists > 0) - NewClass->setTemplateParameterListsInfo( - Context, - llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); + if (!OuterTemplateParamLists.empty()) + NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists); // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. @@ -2103,7 +2048,10 @@ DeclResult Sema::CheckClassTemplate( = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, NewClass); - + // If we are providing an explicit specialization of a member that is a + // class template, make a note of that. + if (IsMemberSpecialization) + NewTemplate->setMemberSpecialization(); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -2118,12 +2066,6 @@ DeclResult Sema::CheckClassTemplate( assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; - // If we are providing an explicit specialization of a member that is a - // class template, make a note of that. - if (PrevClassTemplate && - PrevClassTemplate->getInstantiatedFromMemberTemplate()) - PrevClassTemplate->setMemberSpecialization(); - // Set the access specifier. if (!Invalid && TUK != TagUseKind::Friend && NewTemplate->getDeclContext()->isRecord()) @@ -2133,8 +2075,62 @@ DeclResult Sema::CheckClassTemplate( NewClass->setLexicalDeclContext(CurContext); NewTemplate->setLexicalDeclContext(CurContext); - if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) - NewClass->startDefinition(); + // Ensure that the template parameter lists are compatible. Skip this check + // for a friend in a dependent context: the template parameter list itself + // could be dependent. + if (ShouldAddRedecl && PrevClassTemplate && + !TemplateParameterListsAreEqual( + NewTemplate, TemplateParams, PrevClassTemplate, + PrevClassTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) + return true; + + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous class + // template declaration. Skip this check for a friend in a dependent + // context, because the template parameter list might be dependent. + if (ShouldAddRedecl && + CheckTemplateParameterList( + TemplateParams, + PrevClassTemplate ? PrevClassTemplate->getTemplateParameters() + : nullptr, + (SS.isSet() && SemanticContext && SemanticContext->isRecord() && + SemanticContext->isDependentContext()) + ? TPC_ClassTemplateMember + : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate + : TPC_ClassTemplate, + SkipBody)) + Invalid = true; + + if (TUK == TagUseKind::Definition) { + if (PrevClassTemplate) { + // Check for redefinition of this class template. + if (TagDecl *Def = + PrevClassTemplate->getTemplatedDecl()->getDefinition()) { + // If we have a prior definition that is not visible, treat this as + // simply making that previous definition visible. + NamedDecl *Hidden = nullptr; + if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { + SkipBody->ShouldSkip = true; + SkipBody->Previous = Def; + auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); + assert(Tmpl && "original definition of a class template is not a " + "class template?"); + makeMergedDefinitionVisible(Hidden); + makeMergedDefinitionVisible(Tmpl); + } else { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // FIXME: Would it make sense to try to "forget" the previous + // definition, as part of error recovery? + return true; + } + } + } + + if (!SkipBody || !SkipBody->ShouldSkip) + NewClass->startDefinition(); + } ProcessDeclAttributeList(S, NewClass, Attr); ProcessAPINotes(NewClass); @@ -3974,7 +3970,8 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) { DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization) { + StorageClass SC, bool IsPartialSpecialization, + bool IsMemberSpecialization) { // D must be variable template id. assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId && "Variable template specialization is declared with a template id."); @@ -4092,17 +4089,16 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, CanonicalConverted); + // If we are providing an explicit specialization of a member variable + // template specialization, make a note of that. + if (IsMemberSpecialization) + Partial->setMemberSpecialization(); Partial->setTemplateArgsAsWritten(TemplateArgs); if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; - // If we are providing an explicit specialization of a member variable - // template specialization, make a note of that. - if (PrevPartial && PrevPartial->getInstantiatedFromMember()) - PrevPartial->setMemberSpecialization(); - CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for @@ -5617,9 +5613,7 @@ bool Sema::CheckTemplateArgumentList( MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( Template, NewContext, /*Final=*/false, CanonicalConverted, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConceptInstantiation=*/true); + /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true); if (EnsureTemplateArgumentListConstraints( Template, MLTAL, SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { @@ -8308,15 +8302,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization( Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) << /*class template*/ 0 << (TUK == TagUseKind::Definition) << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); - return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, - ClassTemplate->getIdentifier(), - TemplateNameLoc, - Attr, - TemplateParams, - AS_none, /*ModulePrivateLoc=*/SourceLocation(), - /*FriendLoc*/SourceLocation(), - TemplateParameterLists.size() - 1, - TemplateParameterLists.data()); + return CheckClassTemplate( + S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), + TemplateNameLoc, Attr, TemplateParams, AS_none, + /*ModulePrivateLoc=*/SourceLocation(), + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), + isMemberSpecialization); } // Create a new class template partial specialization declaration node. @@ -8326,6 +8317,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplatePartialSpecializationDecl::Create( Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted, CanonType, PrevPartial); + + // If we are providing an explicit specialization of a member class + // template specialization, make a note of that. + if (isMemberSpecialization) + Partial->setMemberSpecialization(); Partial->setTemplateArgsAsWritten(TemplateArgs); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { @@ -8337,11 +8333,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; - // If we are providing an explicit specialization of a member class - // template specialization, make a note of that. - if (PrevPartial && PrevPartial->getInstantiatedFromMember()) - PrevPartial->setMemberSpecialization(); - CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for @@ -11139,8 +11130,8 @@ class ExplicitSpecializationVisibilityChecker { template void checkTemplate(TemplDecl *TD) { - if (TD->isMemberSpecialization()) { - if (!CheckMemberSpecialization(TD)) + if (TD->getMostRecentDecl()->isMemberSpecialization()) { + if (!CheckMemberSpecialization(TD->getMostRecentDecl())) diagnose(TD->getMostRecentDecl(), false); } } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index cc095ae67ac40..ffe7225c9abd0 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3138,20 +3138,6 @@ template<> struct IsPartialSpecialization { static constexpr bool value = true; }; -template -static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { - return false; -} -template <> -bool DeducedArgsNeedReplacement( - VarTemplatePartialSpecializationDecl *Spec) { - return !Spec->isClassScopeExplicitSpecialization(); -} -template <> -bool DeducedArgsNeedReplacement( - ClassTemplatePartialSpecializationDecl *Spec) { - return !Spec->isClassScopeExplicitSpecialization(); -} template static TemplateDeductionResult @@ -3162,23 +3148,10 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); - std::optional> Innermost; - // If we don't need to replace the deduced template arguments, - // we can add them immediately as the inner-most argument list. - if (!DeducedArgsNeedReplacement(Template)) - Innermost = CanonicalDeducedArgs; - MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( - Template, Template->getDeclContext(), /*Final=*/false, Innermost, - /*RelativeToPrimary=*/true, /*Pattern=*/ - nullptr, /*ForConstraintInstantiation=*/true); - - // getTemplateInstantiationArgs picks up the non-deduced version of the - // template args when this is a variable template partial specialization and - // not class-scope explicit specialization, so replace with Deduced Args - // instead of adding to inner-most. - if (!Innermost) - MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs); + Template, Template->getDeclContext(), /*Final=*/false, + /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true, + /*ForConstraintInstantiation=*/true); if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, Info.getLocation(), diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 545da21183c3c..ca93c840f0321 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, } // Template arguments used to transform the template arguments in // DeducedResults. - SmallVector TemplateArgsForBuildingRC( + SmallVector InnerArgsForBuildingRC( F->getTemplateParameters()->size()); // Transform the transformed template args MultiLevelTemplateArgumentList Args; @@ -778,33 +778,30 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, NamedDecl *TP = F->getTemplateParameters()->getParam(Index); MultiLevelTemplateArgumentList Args; Args.setKind(TemplateSubstitutionKind::Rewrite); - Args.addOuterTemplateArguments(TemplateArgsForBuildingRC); + Args.addOuterTemplateArguments(InnerArgsForBuildingRC); // Rebuild the template parameter with updated depth and index. NamedDecl *NewParam = transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args, /*NewIndex=*/FirstUndeducedParamIdx, getDepthAndIndex(TP).first + AdjustDepth); FirstUndeducedParamIdx += 1; - assert(TemplateArgsForBuildingRC[Index].isNull()); - TemplateArgsForBuildingRC[Index] = - Context.getInjectedTemplateArg(NewParam); + assert(InnerArgsForBuildingRC[Index].isNull()); + InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam); continue; } TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); TemplateArgumentLoc Output; if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) { - assert(TemplateArgsForBuildingRC[Index].isNull() && + assert(InnerArgsForBuildingRC[Index].isNull() && "InstantiatedArgs must be null before setting"); - TemplateArgsForBuildingRC[Index] = Output.getArgument(); + InnerArgsForBuildingRC[Index] = Output.getArgument(); } } - // A list of template arguments for transforming the require-clause of F. - // It must contain the entire set of template argument lists. - MultiLevelTemplateArgumentList ArgsForBuildingRC; - ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); - ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC); + // A list of template arguments for transforming the require-clause using + // the transformed template arguments as the template argument list of F. + // // For 2), if the underlying deduction guide F is nested in a class template, // we need the entire template argument list, as the constraint AST in the // require-clause of F remains completely uninstantiated. @@ -827,25 +824,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, // - The occurrence of U in the function parameter is [depth:0, index:0] // - The template parameter of U is [depth:0, index:0] // - // We add the outer template arguments which is [int] to the multi-level arg - // list to ensure that the occurrence U in `C` will be replaced with int - // during the substitution. - // // NOTE: The underlying deduction guide F is instantiated -- either from an // explicitly-written deduction guide member, or from a constructor. - // getInstantiatedFromMemberTemplate() can only handle the former case, so we - // check the DeclContext kind. - if (F->getLexicalDeclContext()->getDeclKind() == - clang::Decl::ClassTemplateSpecialization) { - auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs( - F, F->getLexicalDeclContext(), - /*Final=*/false, /*Innermost=*/std::nullopt, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); - for (auto It : OuterLevelArgs) - ArgsForBuildingRC.addOuterTemplateArguments(It.Args); - } + MultiLevelTemplateArgumentList ArgsForBuildingRC = + SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(), + /*Final=*/false, + /*Innermost=*/InnerArgsForBuildingRC, + /*RelativeToPrimary=*/true, + /*ForConstraintInstantiation=*/true); + ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC); if (E.isInvalid()) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 55f38743e2768..7481c700019dc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -52,38 +52,6 @@ using namespace sema; //===----------------------------------------------------------------------===/ namespace { -namespace TemplateInstArgsHelpers { -struct Response { - const Decl *NextDecl = nullptr; - bool IsDone = false; - bool ClearRelativeToPrimary = true; - static Response Done() { - Response R; - R.IsDone = true; - return R; - } - static Response ChangeDecl(const Decl *ND) { - Response R; - R.NextDecl = ND; - return R; - } - static Response ChangeDecl(const DeclContext *Ctx) { - Response R; - R.NextDecl = Decl::castFromDeclContext(Ctx); - return R; - } - - static Response UseNextDecl(const Decl *CurDecl) { - return ChangeDecl(CurDecl->getDeclContext()); - } - - static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { - Response R = Response::UseNextDecl(CurDecl); - R.ClearRelativeToPrimary = false; - return R; - } -}; - // Retrieve the primary template for a lambda call operator. It's // unfortunate that we only have the mappings of call operators rather // than lambda classes. @@ -171,374 +139,397 @@ bool isLambdaEnclosedByTypeAliasDecl( .TraverseType(Underlying); } -// Add template arguments from a variable template instantiation. -Response -HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, - MultiLevelTemplateArgumentList &Result, - bool SkipForSpecialization) { - // For a class-scope explicit specialization, there are no template arguments - // at this level, but there may be enclosing template arguments. - if (VarTemplSpec->isClassScopeExplicitSpecialization()) - return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); - - // We're done when we hit an explicit specialization. - if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa(VarTemplSpec)) - return Response::Done(); - - // If this variable template specialization was instantiated from a - // specialized member that is a variable template, we're done. - assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); - llvm::PointerUnion - Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); - if (VarTemplatePartialSpecializationDecl *Partial = - Specialized.dyn_cast()) { - if (!SkipForSpecialization) - Result.addOuterTemplateArguments( - Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); - if (Partial->isMemberSpecialization()) - return Response::Done(); - } else { - VarTemplateDecl *Tmpl = Specialized.get(); - if (!SkipForSpecialization) - Result.addOuterTemplateArguments( - Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); - if (Tmpl->isMemberSpecialization()) - return Response::Done(); +struct TemplateInstantiationArgumentCollecter + : DeclVisitor { + Sema &S; + MultiLevelTemplateArgumentList &Result; + std::optional> Innermost; + bool RelativeToPrimary; + bool ForConstraintInstantiation; + + TemplateInstantiationArgumentCollecter( + Sema &S, MultiLevelTemplateArgumentList &Result, + std::optional> Innermost, + bool RelativeToPrimary, bool ForConstraintInstantiation) + : S(S), Result(Result), Innermost(Innermost), + RelativeToPrimary(RelativeToPrimary), + ForConstraintInstantiation(ForConstraintInstantiation) {} + + Decl *Done() { return nullptr; } + + Decl *ChangeDecl(const Decl *D) { + RelativeToPrimary = false; + return const_cast(D); } - return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); -} -// If we have a template template parameter with translation unit context, -// then we're performing substitution into a default template argument of -// this template template parameter before we've constructed the template -// that will own this template template parameter. In this case, we -// use empty template parameter lists for all of the outer templates -// to avoid performing any substitutions. -Response -HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, - MultiLevelTemplateArgumentList &Result) { - for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) - Result.addOuterTemplateArguments(std::nullopt); - return Response::Done(); -} + Decl *ChangeDecl(const DeclContext *DC) { + return ChangeDecl(Decl::castFromDeclContext(DC)); + } -Response HandlePartialClassTemplateSpec( - const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, - MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { - if (!SkipForSpecialization) - Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); - return Response::Done(); -} + Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); } -// Add template arguments from a class template instantiation. -Response -HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, - MultiLevelTemplateArgumentList &Result, - bool SkipForSpecialization) { - if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { - // We're done when we hit an explicit specialization. - if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa(ClassTemplSpec)) - return Response::Done(); + void AddInnermostTemplateArguments(const Decl *D) { + assert(Innermost); + Result.addOuterTemplateArguments(const_cast(D), *Innermost, + /*Final=*/false); + Innermost.reset(); + } - if (!SkipForSpecialization) - Result.addOuterTemplateArguments( - const_cast(ClassTemplSpec), - ClassTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); + void AddOuterTemplateArguments(const Decl *D, ArrayRef Args, + bool Final) { + Result.addOuterTemplateArguments(const_cast(D), Args, Final); + } - // If this class template specialization was instantiated from a - // specialized member that is a class template, we're done. - assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); - if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) - return Response::Done(); - - // If this was instantiated from a partial template specialization, we need - // to get the next level of declaration context from the partial - // specialization, as the ClassTemplateSpecializationDecl's - // DeclContext/LexicalDeclContext will be for the primary template. - if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial() - .dyn_cast()) - return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext()); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) { + if (Innermost) + AddInnermostTemplateArguments(TTPD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); + + for (unsigned Depth = TTPD->getDepth() + 1; Depth--;) + AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); + + return Done(); } - return Response::UseNextDecl(ClassTemplSpec); -} -Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, - MultiLevelTemplateArgumentList &Result, - const FunctionDecl *Pattern, bool RelativeToPrimary, - bool ForConstraintInstantiation, - bool ForDefaultArgumentSubstitution) { - // Add template arguments from a function template specialization. - if (!RelativeToPrimary && - Function->getTemplateSpecializationKindForInstantiation() == - TSK_ExplicitSpecialization) - return Response::Done(); - - if (!RelativeToPrimary && - Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { - // This is an implicit instantiation of an explicit specialization. We - // don't get any template arguments from this function but might get - // some from an enclosing template. - return Response::UseNextDecl(Function); - } else if (const TemplateArgumentList *TemplateArgs = - Function->getTemplateSpecializationArgs()) { - // Add the template arguments for this specialization. - Result.addOuterTemplateArguments(const_cast(Function), - TemplateArgs->asArray(), - /*Final=*/false); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "outer template not instantiated?"); + + if (Innermost) + AddInnermostTemplateArguments(FTD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(), + /*Final=*/false); + + if (FTD->isMemberSpecialization()) + return Done(); + + if (FTD->getFriendObjectKind()) + return ChangeDecl(FTD->getLexicalDeclContext()); + return UseNextDecl(FTD); + } - if (RelativeToPrimary && - (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization || - (Function->getFriendObjectKind() && - !Function->getPrimaryTemplate()->getFriendObjectKind()))) - return Response::UseNextDecl(Function); - - // If this function was instantiated from a specialized member that is - // a function template, we're done. - assert(Function->getPrimaryTemplate() && "No function template?"); - if (!ForDefaultArgumentSubstitution && - Function->getPrimaryTemplate()->isMemberSpecialization()) - return Response::Done(); - - // If this function is a generic lambda specialization, we are done. - if (!ForConstraintInstantiation && - isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) - return Response::Done(); - - } else if (Function->getDescribedFunctionTemplate()) { + Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "Outer template not instantiated?"); + "outer template not instantiated?"); + + if (Innermost) + AddInnermostTemplateArguments(VTD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(), + /*Final=*/false); + + if (VTD->isMemberSpecialization()) + return Done(); + + return UseNextDecl(VTD); } - // If this is a friend or local declaration and it declares an entity at - // namespace scope, take arguments from its lexical parent - // instead of its semantic parent, unless of course the pattern we're - // instantiating actually comes from the file's context! - if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && - Function->getNonTransparentDeclContext()->isFileContext() && - (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { - return Response::ChangeDecl(Function->getLexicalDeclContext()); + + Decl *VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *VTPSD) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "outer template not instantiated?"); + + if (Innermost) + AddInnermostTemplateArguments(VTPSD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(), + /*Final=*/false); + + if (VTPSD->isMemberSpecialization()) + return Done(); + + return UseNextDecl(VTPSD); } - if (ForConstraintInstantiation && Function->getFriendObjectKind()) - return Response::ChangeDecl(Function->getLexicalDeclContext()); - return Response::UseNextDecl(Function); -} + Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "outer template not instantiated?"); -Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, - MultiLevelTemplateArgumentList &Result) { - if (!isa(FTD->getDeclContext())) { - Result.addOuterTemplateArguments( - const_cast(FTD), - const_cast(FTD)->getInjectedTemplateArgs(), - /*Final=*/false); - - NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); - - while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { - if (NNS->isInstantiationDependent()) { - if (const auto *TSTy = Ty->getAs()) { - ArrayRef Arguments = TSTy->template_arguments(); - // Prefer template arguments from the injected-class-type if possible. - // For example, - // ```cpp - // template struct S { - // template void foo(); - // }; - // template template - // ^^^^^^^^^^^^^ InjectedTemplateArgs - // They're of kind TemplateArgument::Pack, not of - // TemplateArgument::Type. - // void S::foo() {} - // ^^^^^^^ - // TSTy->template_arguments() (which are of PackExpansionType) - // ``` - // This meets the contract in - // TreeTransform::TryExpandParameterPacks that the template arguments - // for unexpanded parameters should be of a Pack kind. - if (TSTy->isCurrentInstantiation()) { - auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); - if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) - Arguments = CTD->getInjectedTemplateArgs(); - else if (auto *Specialization = - dyn_cast(RD)) - Arguments = - Specialization->getTemplateInstantiationArgs().asArray(); - } - Result.addOuterTemplateArguments( - const_cast(FTD), Arguments, - /*Final=*/false); - } - } + if (Innermost) + AddInnermostTemplateArguments(CTD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(), + /*Final=*/false); - NNS = NNS->getPrefix(); - } + if (CTD->isMemberSpecialization()) + return Done(); + + if (CTD->getFriendObjectKind()) + return ChangeDecl(CTD->getLexicalDeclContext()); + return UseNextDecl(CTD); } - return Response::ChangeDecl(FTD->getLexicalDeclContext()); -} + Decl *VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *CTPSD) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "outer template not instantiated?"); -Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, - MultiLevelTemplateArgumentList &Result, - ASTContext &Context, - bool ForConstraintInstantiation) { - if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { + if (Innermost) + AddInnermostTemplateArguments(CTPSD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(), + /*Final=*/false); + + if (CTPSD->isMemberSpecialization()) + return Done(); + + return UseNextDecl(CTPSD); + } + + Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "Outer template not instantiated?"); - if (ClassTemplate->isMemberSpecialization()) - return Response::Done(); - if (ForConstraintInstantiation) - Result.addOuterTemplateArguments(const_cast(Rec), - ClassTemplate->getInjectedTemplateArgs(), - /*Final=*/false); + "outer template not instantiated?"); + if (Innermost) + AddInnermostTemplateArguments(TATD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(), + /*Final=*/false); + + return UseNextDecl(TATD); } - if (const MemberSpecializationInfo *MSInfo = - Rec->getMemberSpecializationInfo()) - if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return Response::Done(); - - bool IsFriend = Rec->getFriendObjectKind() || - (Rec->getDescribedClassTemplate() && - Rec->getDescribedClassTemplate()->getFriendObjectKind()); - if (ForConstraintInstantiation && IsFriend && - Rec->getNonTransparentDeclContext()->isFileContext()) { - return Response::ChangeDecl(Rec->getLexicalDeclContext()); + Decl *VisitConceptDecl(ConceptDecl *CD) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "outer template not instantiated?"); + if (Innermost) + AddInnermostTemplateArguments(CD); + + return UseNextDecl(CD); } - // This is to make sure we pick up the VarTemplateSpecializationDecl or the - // TypeAliasTemplateDecl that this lambda is defined inside of. - if (Rec->isLambda()) { - if (const Decl *LCD = Rec->getLambdaContextDecl()) - return Response::ChangeDecl(LCD); - // Retrieve the template arguments for a using alias declaration. - // This is necessary for constraint checking, since we always keep - // constraints relative to the primary template. - if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef); - ForConstraintInstantiation && TypeAlias) { - if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(), - TypeAlias.PrimaryTypeAliasDecl)) { - Result.addOuterTemplateArguments(TypeAlias.Template, - TypeAlias.AssociatedTemplateArguments, - /*Final=*/false); - // Visit the parent of the current type alias declaration rather than - // the lambda thereof. - // E.g., in the following example: - // struct S { - // template using T = decltype([] {} ()); - // }; - // void foo() { - // S::T var; - // } - // The instantiated lambda expression (which we're visiting at 'var') - // has a function DeclContext 'foo' rather than the Record DeclContext - // S. This seems to be an oversight to me that we may want to set a - // Sema Context from the CXXScopeSpec before substituting into T. - return Response::ChangeDecl(TypeAlias.Template->getDeclContext()); + Decl *VisitFunctionDecl(FunctionDecl *FD) { + assert(!FD->getDescribedFunctionTemplate() && + "not for templated declarations"); + + if (!RelativeToPrimary) { + // Add template arguments from a function template specialization. + if (const MemberSpecializationInfo *MSI = + FD->getMemberSpecializationInfo(); + MSI && + MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return Done(); + + // This is an implicit instantiation of an explicit specialization. We + // don't get any template arguments from this function but might get + // some from an enclosing template. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return UseNextDecl(FD); + } + + if (const TemplateArgumentList *TemplateArgs = + FD->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. + if (Innermost) + AddInnermostTemplateArguments(FD); + else + AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false); + + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization || + (FD->getFriendObjectKind() && + !FD->getPrimaryTemplate()->getFriendObjectKind())) + return UseNextDecl(FD); + + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(FD->getPrimaryTemplate() && "No function template?"); + if (FD->getPrimaryTemplate()->isMemberSpecialization()) + return Done(); + + // If this function is a generic lambda specialization, we are done. + if (!ForConstraintInstantiation && + isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) + return Done(); + } + + // If this is a friend or local declaration and it declares an entity at + // namespace scope, take arguments from its lexical parent + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! + if ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) && + FD->getNonTransparentDeclContext()->isFileContext()) { + return ChangeDecl(FD->getLexicalDeclContext()); + } + + if (ForConstraintInstantiation && FD->getFriendObjectKind()) + return ChangeDecl(FD->getLexicalDeclContext()); + return UseNextDecl(FD); + } + + Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) { + assert(!RD->getDescribedClassTemplate() && + "not for templated declarations"); + + if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo(); + MSI && + MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return Done(); + + if (ForConstraintInstantiation && RD->getFriendObjectKind() && + RD->getNonTransparentDeclContext()->isFileContext()) { + return ChangeDecl(RD->getLexicalDeclContext()); + } + + // This is to make sure we pick up the VarTemplateSpecializationDecl or the + // TypeAliasTemplateDecl that this lambda is defined inside of. + if (RD->isLambda()) { + if (Decl *LCD = RD->getLambdaContextDecl()) + return ChangeDecl(LCD); + // Retrieve the template arguments for a using alias declaration. + // This is necessary for constraint checking, since we always keep + // constraints relative to the primary template. + if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S); + ForConstraintInstantiation && TypeAlias) { + if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(), + TypeAlias.PrimaryTypeAliasDecl)) { + AddOuterTemplateArguments(TypeAlias.Template, + TypeAlias.AssociatedTemplateArguments, + /*Final=*/false); + // Visit the parent of the current type alias declaration rather than + // the lambda thereof. + // E.g., in the following example: + // struct S { + // template using T = decltype([] {} ()); + // }; + // void foo() { + // S::T var; + // } + // The instantiated lambda expression (which we're visiting at 'var') + // has a function DeclContext 'foo' rather than the Record DeclContext + // S. This seems to be an oversight to me that we may want to set a + // Sema Context from the CXXScopeSpec before substituting into T. + return ChangeDecl(TypeAlias.Template->getDeclContext()); + } } } + + return UseNextDecl(RD); } - return Response::UseNextDecl(Rec); -} + Decl * + VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) { + // For a class-scope explicit specialization, there are no template + // arguments at this level, but there may be enclosing template arguments. + if (CTSD->isClassScopeExplicitSpecialization()) + return UseNextDecl(CTSD); -Response HandleImplicitConceptSpecializationDecl( - const ImplicitConceptSpecializationDecl *CSD, - MultiLevelTemplateArgumentList &Result) { - Result.addOuterTemplateArguments( - const_cast(CSD), - CSD->getTemplateArguments(), - /*Final=*/false); - return Response::UseNextDecl(CSD); -} + // We're done when we hit an explicit specialization. + if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization) + return Done(); + + if (Innermost) + AddInnermostTemplateArguments(CTSD); + else + AddOuterTemplateArguments(CTSD, + CTSD->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(CTSD->getSpecializedTemplate() && "No class template?"); + llvm::PointerUnion + Specialized = CTSD->getSpecializedTemplateOrPartial(); + + if (auto *CTPSD = + Specialized.dyn_cast()) { + if (CTPSD->isMemberSpecialization()) + return Done(); + } else { + auto *CTD = Specialized.get(); + if (CTD->isMemberSpecialization()) + return Done(); + } + return UseNextDecl(CTSD); + } + + Decl * + VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) { + // For a class-scope explicit specialization, there are no template + // arguments at this level, but there may be enclosing template arguments. + if (VTSD->isClassScopeExplicitSpecialization()) + return UseNextDecl(VTSD); + + // We're done when we hit an explicit specialization. + if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization) + return Done(); + + if (Innermost) + AddInnermostTemplateArguments(VTSD); + else + AddOuterTemplateArguments(VTSD, + VTSD->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(VTSD->getSpecializedTemplate() && "No variable template?"); + llvm::PointerUnion + Specialized = VTSD->getSpecializedTemplateOrPartial(); + if (auto *VTPSD = + Specialized.dyn_cast()) { + if (VTPSD->isMemberSpecialization()) + return Done(); + } else { + auto *VTD = Specialized.get(); + if (VTD->isMemberSpecialization()) + return Done(); + } + return UseNextDecl(VTSD); + } + + Decl *VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *ICSD) { + AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(), + /*Final=*/false); + return UseNextDecl(ICSD); + } + + Decl *VisitDecl(Decl *D) { + if (D->isFileContextDecl()) + return Done(); + + if (isa(D)) + RelativeToPrimary = false; + + return UseNextDecl(D); + } + + Decl *Visit(Decl *D) { + if (TemplateDecl *TD = D->getDescribedTemplate()) + D = TD; + return DeclVisitor::Visit(D); + } +}; -Response HandleGenericDeclContext(const Decl *CurDecl) { - return Response::UseNextDecl(CurDecl); -} -} // namespace TemplateInstArgsHelpers } // namespace MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *ND, const DeclContext *DC, bool Final, std::optional> Innermost, bool RelativeToPrimary, - const FunctionDecl *Pattern, bool ForConstraintInstantiation, - bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) { + bool ForConstraintInstantiation) { assert((ND || DC) && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; - - using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; if (!CurDecl) CurDecl = Decl::castFromDeclContext(DC); - if (Innermost) { - Result.addOuterTemplateArguments(const_cast(ND), *Innermost, - Final); - // Populate placeholder template arguments for TemplateTemplateParmDecls. - // This is essential for the case e.g. - // - // template concept Concept = false; - // template