diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h index 65b9ba874368f392bd409054cf6729d3847fdb60..fcc578f35e322a97c5398825d2bfa9dc2c357728 100644 --- a/bolt/include/bolt/Profile/BoltAddressTranslation.h +++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h @@ -141,15 +141,13 @@ private: uint64_t FuncOutputAddress) const; /// Write the serialized address translation table for a function. - template - void writeMaps(std::map &Maps, uint64_t &PrevAddress, - raw_ostream &OS); + template void writeMaps(uint64_t &PrevAddress, raw_ostream &OS); /// Read the serialized address translation table for a function. /// Return a parse error if failed. template - void parseMaps(std::vector &HotFuncs, uint64_t &PrevAddress, - DataExtractor &DE, uint64_t &Offset, Error &Err); + void parseMaps(uint64_t &PrevAddress, DataExtractor &DE, uint64_t &Offset, + Error &Err); /// Returns the bitmask with set bits corresponding to indices of BRANCHENTRY /// entries in function address translation map. @@ -161,6 +159,9 @@ private: std::map Maps; + /// Ordered vector with addresses of hot functions. + std::vector HotFuncs; + /// Map a function to its basic blocks count std::unordered_map NumBasicBlocksMap; diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 36c42fced93d08bc9e9944d1a3eba6b5ae40d64f..ef3fba37817daa541f28528f62555dd2df8676f9 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -3684,9 +3684,8 @@ BinaryFunction::BasicBlockListType BinaryFunction::dfs() const { BinaryBasicBlock *BB = Stack.top(); Stack.pop(); - if (Visited.find(BB) != Visited.end()) + if (!Visited.insert(BB).second) continue; - Visited.insert(BB); DFS.push_back(BB); for (BinaryBasicBlock *SuccBB : BB->landing_pads()) { @@ -3879,11 +3878,8 @@ void BinaryFunction::disambiguateJumpTables( JumpTable *JT = getJumpTable(Inst); if (!JT) continue; - auto Iter = JumpTables.find(JT); - if (Iter == JumpTables.end()) { - JumpTables.insert(JT); + if (JumpTables.insert(JT).second) continue; - } // This instruction is an indirect jump using a jump table, but it is // using the same jump table of another jump. Try all our tricks to // extract the jump table symbol and make it point to a new, duplicated JT diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index 69cfd58a1df04bcaff7dd0893a81dec73f4a05cc..8d781fc5e04ff72b36de20d20c598eab4bee5233 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -57,11 +57,9 @@ getDWOName(llvm::DWARFUnit &CU, "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist."); if (DwarfOutputPath) { DWOName = std::string(sys::path::filename(DWOName)); - auto Iter = NameToIndexMap.find(DWOName); - if (Iter == NameToIndexMap.end()) - Iter = NameToIndexMap.insert({DWOName, 0}).first; - DWOName.append(std::to_string(Iter->second)); - ++Iter->second; + uint32_t &Index = NameToIndexMap[DWOName]; + DWOName.append(std::to_string(Index)); + ++Index; } DWOName.append(".dwo"); return DWOName; diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp index ebb3925749b4d2775818937e0e7be83ebcd32fb9..76766b05b9176071fcbaf77931fd39d8a42d3942 100644 --- a/bolt/lib/Passes/Instrumentation.cpp +++ b/bolt/lib/Passes/Instrumentation.cpp @@ -109,9 +109,8 @@ static bool hasAArch64ExclusiveMemop( BinaryBasicBlock *BB = BBQueue.front().first; bool IsLoad = BBQueue.front().second; BBQueue.pop(); - if (Visited.find(BB) != Visited.end()) + if (!Visited.insert(BB).second) continue; - Visited.insert(BB); for (const MCInst &Inst : *BB) { // Two loads one after another - skip whole function @@ -126,8 +125,7 @@ static bool hasAArch64ExclusiveMemop( if (BC.MIB->isAArch64ExclusiveLoad(Inst)) IsLoad = true; - if (IsLoad && BBToSkip.find(BB) == BBToSkip.end()) { - BBToSkip.insert(BB); + if (IsLoad && BBToSkip.insert(BB).second) { if (opts::Verbosity >= 2) { outs() << "BOLT-INSTRUMENTER: skip BB " << BB->getName() << " due to exclusive instruction in function " diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp index ec7e303c0f52e83dcae6bbfa80407afb649e3435..4d005f942699e10631a7e44b39ccc368e7c5f82f 100644 --- a/bolt/lib/Profile/BoltAddressTranslation.cpp +++ b/bolt/lib/Profile/BoltAddressTranslation.cpp @@ -143,8 +143,8 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { // Output addresses are delta-encoded uint64_t PrevAddress = 0; - writeMaps(Maps, PrevAddress, OS); - writeMaps(Maps, PrevAddress, OS); + writeMaps(PrevAddress, OS); + writeMaps(PrevAddress, OS); BC.outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n"; BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.getNumFunctions() @@ -182,8 +182,7 @@ size_t BoltAddressTranslation::getNumEqualOffsets(const MapTy &Map, } template -void BoltAddressTranslation::writeMaps(std::map &Maps, - uint64_t &PrevAddress, raw_ostream &OS) { +void BoltAddressTranslation::writeMaps(uint64_t &PrevAddress, raw_ostream &OS) { const uint32_t NumFuncs = llvm::count_if(llvm::make_first_range(Maps), [&](const uint64_t Address) { return Cold == ColdPartSource.count(Address); @@ -213,9 +212,9 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, : 0; uint32_t Skew = 0; if (Cold) { - auto HotEntryIt = Maps.find(ColdPartSource[Address]); - assert(HotEntryIt != Maps.end()); - size_t HotIndex = std::distance(Maps.begin(), HotEntryIt); + auto HotEntryIt = llvm::lower_bound(HotFuncs, ColdPartSource[Address]); + assert(HotEntryIt != HotFuncs.end()); + size_t HotIndex = std::distance(HotFuncs.begin(), HotEntryIt); encodeULEB128(HotIndex - PrevIndex, OS); PrevIndex = HotIndex; // Skew of all input offsets for cold fragments is simply the first input @@ -223,6 +222,7 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, Skew = Map.begin()->second >> 1; encodeULEB128(Skew, OS); } else { + HotFuncs.push_back(Address); // Function hash size_t BFHash = getBFHash(HotInputAddress); LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash)); @@ -311,17 +311,15 @@ std::error_code BoltAddressTranslation::parse(raw_ostream &OS, StringRef Buf) { return make_error_code(llvm::errc::io_error); Error Err(Error::success()); - std::vector HotFuncs; uint64_t PrevAddress = 0; - parseMaps(HotFuncs, PrevAddress, DE, Offset, Err); - parseMaps(HotFuncs, PrevAddress, DE, Offset, Err); + parseMaps(PrevAddress, DE, Offset, Err); + parseMaps(PrevAddress, DE, Offset, Err); OS << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n"; return errorToErrorCode(std::move(Err)); } template -void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, - uint64_t &PrevAddress, DataExtractor &DE, +void BoltAddressTranslation::parseMaps(uint64_t &PrevAddress, DataExtractor &DE, uint64_t &Offset, Error &Err) { const uint32_t NumFunctions = DE.getULEB128(&Offset, &Err); LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << (Cold ? " cold" : "") diff --git a/bolt/tools/driver/llvm-bolt.cpp b/bolt/tools/driver/llvm-bolt.cpp index 9b03524e9f18e8771f38a7926b3b9c50945d1153..a8d1ac6480893001917c84e7275c97dea2fa3cab 100644 --- a/bolt/tools/driver/llvm-bolt.cpp +++ b/bolt/tools/driver/llvm-bolt.cpp @@ -202,9 +202,9 @@ int main(int argc, char **argv) { ToolName = argv[0]; - if (llvm::sys::path::filename(ToolName) == "perf2bolt") + if (llvm::sys::path::filename(ToolName).starts_with("perf2bolt")) perf2boltMode(argc, argv); - else if (llvm::sys::path::filename(ToolName) == "llvm-boltdiff") + else if (llvm::sys::path::filename(ToolName).starts_with("llvm-boltdiff")) boltDiffMode(argc, argv); else boltMode(argc, argv); diff --git a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp index 6175fcdfd229c3a1409217786a95e44dc539034a..8eaf54fe0088a4d27d2153427ab24b6110eb1a90 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp @@ -165,7 +165,7 @@ void CrtpConstructorAccessibilityCheck::check( WithFriendHintIfNeeded( diag(Ctor->getLocation(), - "%0 contructor allows the CRTP to be %select{inherited " + "%0 constructor allows the CRTP to be %select{inherited " "from|constructed}1 as a regular template class; consider making " "it private%select{| and declaring the derived class as friend}2") << Access << IsPublic << NeedsFriend diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp index a30e63f9b0fd6a75231b71819b60430ff29a878d..628d30ce7f73fe382ed9585a7ee3078213eda120 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp @@ -70,7 +70,9 @@ SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name, Options.get("WarnOnSizeOfCompareToConstant", true)), WarnOnSizeOfPointerToAggregate( Options.get("WarnOnSizeOfPointerToAggregate", true)), - WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)) {} + WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)), + WarnOnOffsetDividedBySizeOf( + Options.get("WarnOnOffsetDividedBySizeOf", true)) {} void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant); @@ -82,6 +84,8 @@ void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "WarnOnSizeOfPointerToAggregate", WarnOnSizeOfPointerToAggregate); Options.store(Opts, "WarnOnSizeOfPointer", WarnOnSizeOfPointer); + Options.store(Opts, "WarnOnOffsetDividedBySizeOf", + WarnOnOffsetDividedBySizeOf); } void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) { @@ -307,7 +311,8 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) { offsetOfExpr())) .bind("sizeof-in-ptr-arithmetic-scale-expr"); const auto PtrArithmeticIntegerScaleExpr = binaryOperator( - hasAnyOperatorName("*", "/"), + WarnOnOffsetDividedBySizeOf ? binaryOperator(hasAnyOperatorName("*", "/")) + : binaryOperator(hasOperatorName("*")), // sizeof(...) * sizeof(...) and sizeof(...) / sizeof(...) is handled // by this check on another path. hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr)), diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h index 66d7c34cc9e94010d73e2a273069aa2b603e84ae..fbd62cb80fb2d02a715300f07d0010af0c2f9416 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h @@ -31,6 +31,7 @@ private: const bool WarnOnSizeOfCompareToConstant; const bool WarnOnSizeOfPointerToAggregate; const bool WarnOnSizeOfPointer; + const bool WarnOnOffsetDividedBySizeOf; }; } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp index 5b1b1cd152fffba36e4f328eab925c07c676b3bd..6df565c9a9d691db5c72067b4bcb54cf5e00bb23 100644 --- a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp @@ -137,11 +137,11 @@ static bool mayShadow(const NamedDecl *ND0, const ConfusableIdentifierCheck::ContextInfo * ConfusableIdentifierCheck::getContextInfo(const DeclContext *DC) { const DeclContext *PrimaryContext = DC->getPrimaryContext(); - auto It = ContextInfos.find(PrimaryContext); - if (It != ContextInfos.end()) + auto [It, Inserted] = ContextInfos.try_emplace(PrimaryContext); + if (!Inserted) return &It->second; - ContextInfo &Info = ContextInfos[PrimaryContext]; + ContextInfo &Info = It->second; Info.PrimaryContext = PrimaryContext; Info.NonTransparentContext = PrimaryContext; diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp index 89ee45faecd7f33e8f80189ee59fad02849695aa..5eb3267adb0799dd8fb02addc6b580ba242b7b1f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp @@ -8,6 +8,7 @@ #include "UseStartsEndsWithCheck.h" +#include "../utils/ASTUtils.h" #include "../utils/OptionsUtils.h" #include "clang/Lex/Lexer.h" @@ -16,6 +17,63 @@ using namespace clang::ast_matchers; namespace clang::tidy::modernize { +struct NotLengthExprForStringNode { + NotLengthExprForStringNode(std::string ID, DynTypedNode Node, + ASTContext *Context) + : ID(std::move(ID)), Node(std::move(Node)), Context(Context) {} + bool operator()(const internal::BoundNodesMap &Nodes) const { + // Match a string literal and an integer size or strlen() call. + if (const auto *StringLiteralNode = Nodes.getNodeAs(ID)) { + if (const auto *IntegerLiteralSizeNode = Node.get()) { + return StringLiteralNode->getLength() != + IntegerLiteralSizeNode->getValue().getZExtValue(); + } + + if (const auto *StrlenNode = Node.get()) { + if (StrlenNode->getDirectCallee()->getName() != "strlen" || + StrlenNode->getNumArgs() != 1) { + return true; + } + + if (const auto *StrlenArgNode = dyn_cast( + StrlenNode->getArg(0)->IgnoreParenImpCasts())) { + return StrlenArgNode->getLength() != StringLiteralNode->getLength(); + } + } + } + + // Match a string variable and a call to length() or size(). + if (const auto *ExprNode = Nodes.getNodeAs(ID)) { + if (const auto *MemberCallNode = Node.get()) { + const CXXMethodDecl *MethodDeclNode = MemberCallNode->getMethodDecl(); + const StringRef Name = MethodDeclNode->getName(); + if (!MethodDeclNode->isConst() || MethodDeclNode->getNumParams() != 0 || + (Name != "size" && Name != "length")) { + return true; + } + + if (const auto *OnNode = + dyn_cast(MemberCallNode->getImplicitObjectArgument())) { + return !utils::areStatementsIdentical(OnNode->IgnoreParenImpCasts(), + ExprNode->IgnoreParenImpCasts(), + *Context); + } + } + } + + return true; + } + +private: + std::string ID; + DynTypedNode Node; + ASTContext *Context; +}; + +AST_MATCHER_P(Expr, lengthExprForStringNode, std::string, ID) { + return Builder->removeBindings(NotLengthExprForStringNode( + ID, DynTypedNode::create(Node), &(Finder->getASTContext()))); +} UseStartsEndsWithCheck::UseStartsEndsWithCheck(StringRef Name, ClangTidyContext *Context) @@ -23,6 +81,7 @@ UseStartsEndsWithCheck::UseStartsEndsWithCheck(StringRef Name, void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) { const auto ZeroLiteral = integerLiteral(equals(0)); + const auto HasStartsWithMethodWithName = [](const std::string &Name) { return hasMethod( cxxMethodDecl(hasName(Name), isConst(), parameterCountIs(1)) @@ -32,119 +91,104 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) { anyOf(HasStartsWithMethodWithName("starts_with"), HasStartsWithMethodWithName("startsWith"), HasStartsWithMethodWithName("startswith")); - const auto ClassWithStartsWithFunction = cxxRecordDecl(anyOf( - HasStartsWithMethod, hasAnyBase(hasType(hasCanonicalType(hasDeclaration( - cxxRecordDecl(HasStartsWithMethod))))))); + const auto OnClassWithStartsWithFunction = + on(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl( + anyOf(HasStartsWithMethod, + hasAnyBase(hasType(hasCanonicalType( + hasDeclaration(cxxRecordDecl(HasStartsWithMethod))))))))))); + const auto HasEndsWithMethodWithName = [](const std::string &Name) { + return hasMethod( + cxxMethodDecl(hasName(Name), isConst(), parameterCountIs(1)) + .bind("ends_with_fun")); + }; + const auto HasEndsWithMethod = anyOf(HasEndsWithMethodWithName("ends_with"), + HasEndsWithMethodWithName("endsWith"), + HasEndsWithMethodWithName("endswith")); + const auto OnClassWithEndsWithFunction = + on(expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl( + anyOf(HasEndsWithMethod, + hasAnyBase(hasType(hasCanonicalType(hasDeclaration( + cxxRecordDecl(HasEndsWithMethod))))))))))) + .bind("haystack")); + + // Case 1: X.find(Y) [!=]= 0 -> starts_with. const auto FindExpr = cxxMemberCallExpr( - // A method call with no second argument or the second argument is zero... anyOf(argumentCountIs(1), hasArgument(1, ZeroLiteral)), - // ... named find... callee(cxxMethodDecl(hasName("find")).bind("find_fun")), - // ... on a class with a starts_with function. - on(hasType( - hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))), - // Bind search expression. - hasArgument(0, expr().bind("search_expr"))); + OnClassWithStartsWithFunction, hasArgument(0, expr().bind("needle"))); + // Case 2: X.rfind(Y, 0) [!=]= 0 -> starts_with. const auto RFindExpr = cxxMemberCallExpr( - // A method call with a second argument of zero... hasArgument(1, ZeroLiteral), - // ... named rfind... callee(cxxMethodDecl(hasName("rfind")).bind("find_fun")), - // ... on a class with a starts_with function. - on(hasType( - hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))), - // Bind search expression. - hasArgument(0, expr().bind("search_expr"))); - - // Match a string literal and an integer or strlen() call matching the length. - const auto HasStringLiteralAndLengthArgs = [](const auto StringArgIndex, - const auto LengthArgIndex) { - return allOf( - hasArgument(StringArgIndex, stringLiteral().bind("string_literal_arg")), - hasArgument(LengthArgIndex, - anyOf(integerLiteral().bind("integer_literal_size_arg"), - callExpr(callee(functionDecl(parameterCountIs(1), - hasName("strlen"))), - hasArgument(0, stringLiteral().bind( - "strlen_arg")))))); - }; - - // Match a string variable and a call to length() or size(). - const auto HasStringVariableAndSizeCallArgs = [](const auto StringArgIndex, - const auto LengthArgIndex) { - return allOf( - hasArgument(StringArgIndex, declRefExpr(hasDeclaration( - decl().bind("string_var_decl")))), - hasArgument(LengthArgIndex, - cxxMemberCallExpr( - callee(cxxMethodDecl(isConst(), parameterCountIs(0), - hasAnyName("size", "length"))), - on(declRefExpr( - to(decl(equalsBoundNode("string_var_decl")))))))); - }; - - // Match either one of the two cases above. - const auto HasStringAndLengthArgs = - [HasStringLiteralAndLengthArgs, HasStringVariableAndSizeCallArgs]( - const auto StringArgIndex, const auto LengthArgIndex) { - return anyOf( - HasStringLiteralAndLengthArgs(StringArgIndex, LengthArgIndex), - HasStringVariableAndSizeCallArgs(StringArgIndex, LengthArgIndex)); - }; + OnClassWithStartsWithFunction, hasArgument(0, expr().bind("needle"))); + // Case 3: X.compare(0, LEN(Y), Y) [!=]= 0 -> starts_with. const auto CompareExpr = cxxMemberCallExpr( - // A method call with three arguments... - argumentCountIs(3), - // ... where the first argument is zero... - hasArgument(0, ZeroLiteral), - // ... named compare... + argumentCountIs(3), hasArgument(0, ZeroLiteral), callee(cxxMethodDecl(hasName("compare")).bind("find_fun")), - // ... on a class with a starts_with function... - on(hasType( - hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))), - // ... where the third argument is some string and the second a length. - HasStringAndLengthArgs(2, 1), - // Bind search expression. - hasArgument(2, expr().bind("search_expr"))); + OnClassWithStartsWithFunction, hasArgument(2, expr().bind("needle")), + hasArgument(1, lengthExprForStringNode("needle"))); + // Case 4: X.compare(LEN(X) - LEN(Y), LEN(Y), Y) [!=]= 0 -> ends_with. + const auto CompareEndsWithExpr = cxxMemberCallExpr( + argumentCountIs(3), + callee(cxxMethodDecl(hasName("compare")).bind("find_fun")), + OnClassWithEndsWithFunction, hasArgument(2, expr().bind("needle")), + hasArgument(1, lengthExprForStringNode("needle")), + hasArgument(0, + binaryOperator(hasOperatorName("-"), + hasLHS(lengthExprForStringNode("haystack")), + hasRHS(lengthExprForStringNode("needle"))))); + + // All cases comparing to 0. Finder->addMatcher( - // Match [=!]= with a zero on one side and (r?)find|compare on the other. binaryOperator( hasAnyOperatorName("==", "!="), - hasOperands(cxxMemberCallExpr(anyOf(FindExpr, RFindExpr, CompareExpr)) + hasOperands(cxxMemberCallExpr(anyOf(FindExpr, RFindExpr, CompareExpr, + CompareEndsWithExpr)) .bind("find_expr"), ZeroLiteral)) .bind("expr"), this); + + // Case 5: X.rfind(Y) [!=]= LEN(X) - LEN(Y) -> ends_with. + Finder->addMatcher( + binaryOperator( + hasAnyOperatorName("==", "!="), + hasOperands( + cxxMemberCallExpr( + anyOf( + argumentCountIs(1), + allOf(argumentCountIs(2), + hasArgument( + 1, + anyOf(declRefExpr(to(varDecl(hasName("npos")))), + memberExpr(member(hasName("npos"))))))), + callee(cxxMethodDecl(hasName("rfind")).bind("find_fun")), + OnClassWithEndsWithFunction, + hasArgument(0, expr().bind("needle"))) + .bind("find_expr"), + binaryOperator(hasOperatorName("-"), + hasLHS(lengthExprForStringNode("haystack")), + hasRHS(lengthExprForStringNode("needle"))))) + .bind("expr"), + this); } void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) { const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr"); const auto *FindExpr = Result.Nodes.getNodeAs("find_expr"); const auto *FindFun = Result.Nodes.getNodeAs("find_fun"); - const auto *SearchExpr = Result.Nodes.getNodeAs("search_expr"); + const auto *SearchExpr = Result.Nodes.getNodeAs("needle"); const auto *StartsWithFunction = Result.Nodes.getNodeAs("starts_with_fun"); - - const auto *StringLiteralArg = - Result.Nodes.getNodeAs("string_literal_arg"); - const auto *IntegerLiteralSizeArg = - Result.Nodes.getNodeAs("integer_literal_size_arg"); - const auto *StrlenArg = Result.Nodes.getNodeAs("strlen_arg"); - - // Filter out compare cases where the length does not match string literal. - if (StringLiteralArg && IntegerLiteralSizeArg && - StringLiteralArg->getLength() != - IntegerLiteralSizeArg->getValue().getZExtValue()) { - return; - } - - if (StringLiteralArg && StrlenArg && - StringLiteralArg->getLength() != StrlenArg->getLength()) { - return; - } + const auto *EndsWithFunction = + Result.Nodes.getNodeAs("ends_with_fun"); + assert(bool(StartsWithFunction) != bool(EndsWithFunction)); + const CXXMethodDecl *ReplacementFunction = + StartsWithFunction ? StartsWithFunction : EndsWithFunction; if (ComparisonExpr->getBeginLoc().isMacroID()) { return; @@ -154,9 +198,9 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) { auto Diagnostic = diag(FindExpr->getExprLoc(), "use %0 instead of %1() %select{==|!=}2 0") - << StartsWithFunction->getName() << FindFun->getName() << Neg; + << ReplacementFunction->getName() << FindFun->getName() << Neg; - // Remove possible arguments after search expression and ' [!=]= 0' suffix. + // Remove possible arguments after search expression and ' [!=]= .+' suffix. Diagnostic << FixItHint::CreateReplacement( CharSourceRange::getTokenRange( Lexer::getLocForEndOfToken(SearchExpr->getEndLoc(), 0, @@ -164,16 +208,16 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) { ComparisonExpr->getEndLoc()), ")"); - // Remove possible '0 [!=]= ' prefix. + // Remove possible '.+ [!=]= ' prefix. Diagnostic << FixItHint::CreateRemoval(CharSourceRange::getCharRange( ComparisonExpr->getBeginLoc(), FindExpr->getBeginLoc())); - // Replace method name by 'starts_with'. + // Replace method name by '(starts|ends)_with'. // Remove possible arguments before search expression. Diagnostic << FixItHint::CreateReplacement( CharSourceRange::getCharRange(FindExpr->getExprLoc(), SearchExpr->getBeginLoc()), - (StartsWithFunction->getName() + "(").str()); + (ReplacementFunction->getName() + "(").str()); // Add possible negation '!'. if (Neg) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.h index 840191f321493fe49e440b4bb7bbfc5407c64b3b..17c2999bda84cd0e936e2989828871a5552f666f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.h @@ -14,7 +14,7 @@ namespace clang::tidy::modernize { /// Checks for common roundabout ways to express ``starts_with`` and -/// ``ends_with`` and suggests replacing with ``starts_with`` when the method is +/// ``ends_with`` and suggests replacing with the simpler method when it is /// available. Notably, this will work with ``std::string`` and /// ``std::string_view``. /// diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index 828f13805a69802689cbe91d7af8a1c6a893ab5a..3f63eec2c51a8c34c5d151b0dc554630643ca2b4 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -1135,6 +1135,9 @@ StyleKind IdentifierNamingCheck::findStyleKind( if (isa(D) && NamingStyles[SK_TypeAlias]) return SK_TypeAlias; + if (isa(D) && NamingStyles[SK_Namespace]) + return SK_Namespace; + if (const auto *Decl = dyn_cast(D)) { if (Decl->isAnonymousNamespace()) return SK_Invalid; diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 333fc10f17d7b43731ab7043ebf481d569c87ca3..f3eee1c6335f9889a446db7024977a85d2c43182 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -144,8 +144,13 @@ getQualification(ASTContext &Context, const DeclContext *DestContext, // since we stored inner-most parent first. std::string Result; llvm::raw_string_ostream OS(Result); - for (const auto *Parent : llvm::reverse(Parents)) + for (const auto *Parent : llvm::reverse(Parents)) { + if (Parent != *Parents.rbegin() && Parent->isDependent() && + Parent->getAsRecordDecl() && + Parent->getAsRecordDecl()->getDescribedClassTemplate()) + OS << "template "; Parent->print(OS, Context.getPrintingPolicy()); + } return OS.str(); } diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp index 75f8668e7bef06077f52b3b5404f3dba3ac15cd5..b537417bd10568cadde99d9b4d664adaaca701b3 100644 --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -75,8 +75,8 @@ public: IDs.push_back(HID); } } - Out->MainFileIncludesBySpelling.try_emplace(Inc.Written) - .first->second.push_back(Out->MainFileIncludes.size() - 1); + Out->MainFileIncludesBySpelling[Inc.Written].push_back( + Out->MainFileIncludes.size() - 1); } // Record include graph (not just for main-file includes) diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index f94cadeffaa298ab4bd5d6a583d604913dc34116..b34aba603b53065eb6a37ecba5e49065311222ee 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -2282,8 +2282,7 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) { elog("incomingCalls failed to convert location: {0}", Loc.takeError()); return; } - auto It = CallsIn.try_emplace(R.Container, std::vector{}).first; - It->second.push_back(Loc->range); + CallsIn[R.Container].push_back(Loc->range); ContainerLookup.IDs.insert(R.Container); }); diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index f43f2417df8fcef8cc686f65e09eb18a89523c6a..591a8b245260eab6c43a1bb7e385d3733e65623d 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -128,7 +128,28 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD, SM.getBufferData(SM.getMainFileID()), Replacements); if (!QualifiedFunc) return QualifiedFunc.takeError(); - return QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1); + + std::string TemplatePrefix; + if (auto *MD = llvm::dyn_cast(FD)) { + for (const CXXRecordDecl *Parent = MD->getParent(); Parent; + Parent = + llvm::dyn_cast_or_null(Parent->getParent())) { + if (const TemplateParameterList *Params = + Parent->getDescribedTemplateParams()) { + std::string S; + llvm::raw_string_ostream Stream(S); + Params->print(Stream, FD->getASTContext()); + if (!S.empty()) + *S.rbegin() = '\n'; // Replace space with newline + TemplatePrefix.insert(0, S); + } + } + } + + auto Source = QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1); + if (!TemplatePrefix.empty()) + Source.insert(0, TemplatePrefix); + return Source; } // Returns replacements to delete tokens with kind `Kind` in the range @@ -212,9 +233,13 @@ getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext, } } const NamedDecl *ND = Ref.Targets.front(); - const std::string Qualifier = + std::string Qualifier = getQualification(AST, TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), ND); + if (ND->getDeclContext()->isDependentContext() && + llvm::isa(ND)) { + Qualifier.insert(0, "typename "); + } if (auto Err = DeclarationCleanups.add( tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier))) Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); @@ -407,10 +432,23 @@ public: return !SameFile; } - // Bail out in templated classes, as it is hard to spell the class name, - // i.e if the template parameter is unnamed. - if (MD->getParent()->isTemplated()) - return false; + for (const CXXRecordDecl *Parent = MD->getParent(); Parent; + Parent = + llvm::dyn_cast_or_null(Parent->getParent())) { + if (const TemplateParameterList *Params = + Parent->getDescribedTemplateParams()) { + + // Class template member functions must be defined in the + // same file. + SameFile = true; + + // Bail out if the template parameter is unnamed. + for (NamedDecl *P : *Params) { + if (!P->getIdentifier()) + return false; + } + } + } // The refactoring is meaningless for unnamed classes and namespaces, // unless we're outlining in the same file diff --git a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp index 906ff33db8734414fc08b8e82170ec2afa2b380d..6a9e90c3bfa70fc55a61e4bafcc83ab20017c59b 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp @@ -105,8 +105,8 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) { F^oo(const Foo&) = delete; };)cpp"); - // Not available within templated classes, as it is hard to spell class name - // out-of-line in such cases. + // Not available within templated classes with unnamed parameters, as it is + // hard to spell class name out-of-line in such cases. EXPECT_UNAVAILABLE(R"cpp( template struct Foo { void fo^o(){} }; )cpp"); @@ -154,7 +154,6 @@ TEST_F(DefineOutlineTest, FailsWithoutSource) { } TEST_F(DefineOutlineTest, ApplyTest) { - llvm::StringMap EditedFiles; ExtraFiles["Test.cpp"] = ""; FileName = "Test.hpp"; @@ -229,17 +228,18 @@ TEST_F(DefineOutlineTest, ApplyTest) { // Ctor initializer with attribute. { R"cpp( - class Foo { - F^oo(int z) __attribute__((weak)) : bar(2){} + template class Foo { + F^oo(T z) __attribute__((weak)) : bar(2){} int bar; };)cpp", R"cpp( - class Foo { - Foo(int z) __attribute__((weak)) ; + template class Foo { + Foo(T z) __attribute__((weak)) ; int bar; - };)cpp", - "Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n", - }, + };template +Foo::Foo(T z) __attribute__((weak)) : bar(2){} +)cpp", + ""}, // Virt specifiers. { R"cpp( @@ -369,7 +369,31 @@ TEST_F(DefineOutlineTest, ApplyTest) { };)cpp", " void A::foo(int) {}\n", }, - // Destrctors + // Complex class template + { + R"cpp( + template struct O1 { + template struct O2 { + enum E { E1, E2 }; + struct I { + E f^oo(T, U..., V, E) { return E1; } + }; + }; + };)cpp", + R"cpp( + template struct O1 { + template struct O2 { + enum E { E1, E2 }; + struct I { + E foo(T, U..., V, E) ; + }; + }; + };template +template +typename O1::template O2::E O1::template O2::I::foo(T, U..., V, E) { return E1; } +)cpp", + ""}, + // Destructors { "class A { ~A^(){} };", "class A { ~A(); };", @@ -378,9 +402,14 @@ TEST_F(DefineOutlineTest, ApplyTest) { }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Test); + llvm::StringMap EditedFiles; EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader); - EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents( - testPath("Test.cpp"), Case.ExpectedSource))); + if (Case.ExpectedSource.empty()) { + EXPECT_TRUE(EditedFiles.empty()); + } else { + EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents( + testPath("Test.cpp"), Case.ExpectedSource))); + } } } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3f7bcde1eb3014fc7389bca420f29fc1fc21683e..95be0a89cd6c93a5ba88d76e3e9131f378b45638 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -88,6 +88,8 @@ Objective-C Miscellaneous ^^^^^^^^^^^^^ +- The DefineOutline tweak now handles member functions of class templates. + Improvements to clang-doc ------------------------- @@ -156,7 +158,7 @@ Changes in existing checks - Improved :doc:`bugprone-sizeof-expression ` check to find suspicious usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or - subtracting from a pointer. + subtracting from a pointer directly or when used to scale a numeric value. - Improved :doc:`bugprone-unchecked-optional-access ` to support @@ -202,6 +204,10 @@ Changes in existing checks ` check to also recognize ``NULL``/``__null`` (but not ``0``) when used with a templated type. +- Improved :doc:`modernize-use-starts-ends-with + ` check to handle two cases + that can be replaced with ``ends_with`` + - Improved :doc:`modernize-use-std-format ` check to support replacing member function calls too and to only expand macros starting with ``PRI`` @@ -238,6 +244,10 @@ Changes in existing checks ` check to remove `->`, when redundant `get()` is removed. +- Improved :doc:`readability-identifier-naming + ` check to + validate ``namespace`` aliases. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst index 89c88d2740dba29ea1257d56ed5559a54c4d495e..29edb26ed7aa20e368dca56349390a45270d1a7f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst @@ -221,6 +221,17 @@ and the result is typically unintended, often out of bounds. ``Ptr + sizeof(T)`` will offset the pointer by ``sizeof(T)`` elements, effectively exponentiating the scaling factor to the power of 2. +Similarly, multiplying or dividing a numeric value with the ``sizeof`` of an +element or the whole buffer is suspicious, because the dimensional connection +between the numeric value and the actual ``sizeof`` result can not always be +deduced. +While scaling an integer up (multiplying) with ``sizeof`` is likely **always** +an issue, a scaling down (division) is not always inherently dangerous, in case +the developer is aware that the division happens between an appropriate number +of _bytes_ and a ``sizeof`` value. +Turning :option:`WarnOnOffsetDividedBySizeOf` off will restrict the +warnings to the multiplication case. + This case also checks suspicious ``alignof`` and ``offsetof`` usages in pointer arithmetic, as both return the "size" in bytes and not elements, potentially resulting in doubly-scaled offsets. @@ -299,3 +310,9 @@ Options ``sizeof`` is an expression that produces a pointer (except for a few idiomatic expressions that are probably intentional and correct). This detects occurrences of CWE 467. Default is `false`. + +.. option:: WarnOnOffsetDividedBySizeOf + + When `true`, the check will warn on pointer arithmetic where the + element count is obtained from a division with ``sizeof(...)``, + e.g., ``Ptr + Bytes / sizeof(*T)``. Default is `true`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst index 34237ede30a30b51f4c35703d7a2151171c356c4..721e927e29849f47520569d12891f6da5351627a 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst @@ -4,8 +4,8 @@ modernize-use-starts-ends-with ============================== Checks for common roundabout ways to express ``starts_with`` and ``ends_with`` -and suggests replacing with ``starts_with`` when the method is available. -Notably, this will work with ``std::string`` and ``std::string_view``. +and suggests replacing with the simpler method when it is available. Notably, +this will work with ``std::string`` and ``std::string_view``. .. code-block:: c++ @@ -13,6 +13,12 @@ Notably, this will work with ``std::string`` and ``std::string_view``. if (s.find("prefix") == 0) { /* do something */ } if (s.rfind("prefix", 0) == 0) { /* do something */ } if (s.compare(0, strlen("prefix"), "prefix") == 0) { /* do something */ } + if (s.compare(s.size() - strlen("suffix"), strlen("suffix"), "suffix") == 0) { + /* do something */ + } + if (s.rfind("suffix") == (s.length() - 6)) { + /* do something */ + } becomes @@ -22,3 +28,5 @@ becomes if (s.starts_with("prefix")) { /* do something */ } if (s.starts_with("prefix")) { /* do something */ } if (s.starts_with("prefix")) { /* do something */ } + if (s.ends_with("suffix")) { /* do something */ } + if (s.ends_with("suffix")) { /* do something */ } diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string index 0c160bc182b6ebdf4ddce7f460ad38c8fd8a99a4..a0e8ebbb267cd0b8a8a0bea3d10c949245b5eb7a 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string @@ -64,6 +64,10 @@ struct basic_string { constexpr bool starts_with(C ch) const noexcept; constexpr bool starts_with(const C* s) const; + constexpr bool ends_with(std::basic_string_view sv) const noexcept; + constexpr bool ends_with(C ch) const noexcept; + constexpr bool ends_with(const C* s) const; + _Type& operator[](size_type); const _Type& operator[](size_type) const; @@ -108,6 +112,10 @@ struct basic_string_view { constexpr bool starts_with(C ch) const noexcept; constexpr bool starts_with(const C* s) const; + constexpr bool ends_with(basic_string_view sv) const noexcept; + constexpr bool ends_with(C ch) const noexcept; + constexpr bool ends_with(const C* s) const; + constexpr int compare(basic_string_view sv) const noexcept; static constexpr size_t npos = -1; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/crtp-constructor-accessibility.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/crtp-constructor-accessibility.cpp index cb41923df157cf83a0c6d2539fab5cb57c787988..f33b8457cc8af528a5e73900083d8176bf981510 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/crtp-constructor-accessibility.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/crtp-constructor-accessibility.cpp @@ -26,7 +26,7 @@ template class CRTP { public: CRTP() = default; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public constructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public: // CHECK-FIXES: friend T; }; @@ -39,7 +39,7 @@ template class CRTP { public: CRTP(int) {} - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public constructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public: // CHECK-FIXES: friend T; }; @@ -52,10 +52,10 @@ template class CRTP { public: CRTP(int) {} - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public constructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}public: CRTP(float) {} - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public constructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}public: // CHECK-FIXES: friend T; @@ -70,13 +70,13 @@ template class CRTP { protected: CRTP(int) {} - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected constructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP(int) {}{{[[:space:]]*}}protected: CRTP() = default; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected constructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}protected: CRTP(float) {} - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected contructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: protected constructor allows the CRTP to be inherited from as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP(float) {}{{[[:space:]]*}}protected: // CHECK-FIXES: friend T; @@ -101,7 +101,7 @@ namespace struct_default_ctor { template struct CRTP { CRTP() = default; - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public contructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: public constructor allows the CRTP to be constructed as a regular template class; consider making it private and declaring the derived class as friend [bugprone-crtp-constructor-accessibility] // CHECK-FIXES: private:{{[[:space:]]*}}CRTP() = default;{{[[:space:]]*}}public: // CHECK-FIXES: friend T; }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-no-division.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-no-division.c new file mode 100644 index 0000000000000000000000000000000000000000..b0cfb8d1cfa456407e4cb0c7900e3ec6734246f0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-no-division.c @@ -0,0 +1,14 @@ +// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-sizeof-expression.WarnOnOffsetDividedBySizeOf: false \ +// RUN: }}' + +typedef __SIZE_TYPE__ size_t; + +void situational14(int *Buffer, size_t BufferSize) { + int *P = &Buffer[0]; + while (P < Buffer + BufferSize / sizeof(*Buffer)) { + // NO-WARNING: This test opted out of "P +- N */ sizeof(...)" warnings. + ++P; + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c index 360ce00a6889d71275dd6c6f0db3c651747972d9..712141c5f266aad562868230f31d4833fb00aeb2 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c @@ -352,21 +352,30 @@ void good13(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; - while (P < (Buffer + sizeof(Buffer) / sizeof(int))) { + while (P < Buffer + sizeof(Buffer) / sizeof(int)) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom (as long as the types don't change). ++P; } - while (P < (Buffer + sizeof(Buffer) / sizeof(Buffer[0]))) { + while (P < Buffer + sizeof(Buffer) / sizeof(Buffer[0])) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom. ++P; } - while (P < (Buffer + sizeof(Buffer) / sizeof(*P))) { + while (P < Buffer + sizeof(Buffer) / sizeof(*P)) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom. ++P; } } + +void situational14(int *Buffer, size_t BufferSize) { + int *P = &Buffer[0]; + while (P < Buffer + BufferSize / sizeof(*Buffer)) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator + // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} + ++P; + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp index c5b2c86befd1fec8c42c9f980367d07de51b4c69..798af260a3b66cd21e940204dde418fd29eb6136 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp @@ -208,6 +208,62 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss, // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with // CHECK-FIXES: !s.starts_with(sv); + s.compare(s.size() - 6, 6, "suffix") == 0; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with("suffix"); + + s.compare(s.size() - 6, strlen("abcdef"), "suffix") == 0; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with("suffix"); + + std::string suffix = "suffix"; + s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind("suffix") == s.size() - 6; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with("suffix"); + + s.rfind("suffix") == s.size() - strlen("suffix"); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with("suffix"); + + s.rfind(suffix) == s.size() - suffix.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind(suffix, std::string::npos) == s.size() - suffix.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind(suffix) == (s.size() - suffix.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind(suffix, s.npos) == (s.size() - suffix.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind(suffix, s.npos) == (((s.size()) - (suffix.size()))); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + s.rfind(suffix) != s.size() - suffix.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: !s.ends_with(suffix); + + (s.size() - suffix.size()) == s.rfind(suffix); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: s.ends_with(suffix); + + struct S { + std::string s; + } t; + t.s.rfind(suffix) == (t.s.size() - suffix.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with + // CHECK-FIXES: t.s.ends_with(suffix); + // Expressions that don't trigger the check are here. #define EQ(x, y) ((x) == (y)) EQ(s.find("a"), 0); @@ -219,4 +275,5 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss, STARTS_WITH_COMPARE(s, s) == 0; s.compare(0, 1, "ab") == 0; + s.rfind(suffix, 1) == s.size() - suffix.size(); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp index 99149fe86aceecf662ead7f674103230bb263630..be5ba54513c672e064ed259e599cb739ea32718f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp @@ -101,6 +101,10 @@ inline namespace InlineNamespace { // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for inline namespace 'InlineNamespace' // CHECK-FIXES: {{^}}inline namespace inline_namespace {{{$}} +namespace FOO_ALIAS = FOO_NS; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for namespace 'FOO_ALIAS' [readability-identifier-naming] +// CHECK-FIXES: {{^}}namespace foo_alias = FOO_NS;{{$}} + SYSTEM_NS::structure g_s1; // NO warnings or fixes expected as SYSTEM_NS and structure are declared in a header file diff --git a/clang/bindings/python/tests/CMakeLists.txt b/clang/bindings/python/tests/CMakeLists.txt index 2543cf739463d93ceb169e97b26354e2eb0c61b2..a0ddabc21bb411b392b7c846308fbf9b3eaaf411 100644 --- a/clang/bindings/python/tests/CMakeLists.txt +++ b/clang/bindings/python/tests/CMakeLists.txt @@ -47,6 +47,19 @@ if(${LLVM_NATIVE_ARCH} MATCHES "^(AArch64|Hexagon|Sparc|SystemZ)$") set(RUN_PYTHON_TESTS FALSE) endif() +# Tests will fail if cross-compiling for a different target, as tests will try +# to use the host Python3_EXECUTABLE and make FFI calls to functions in target +# libraries. +if(CMAKE_CROSSCOMPILING) + # FIXME: Consider a solution that allows better control over these tests in + # a crosscompiling scenario. e.g. registering them with lit to allow them to + # be explicitly skipped via appropriate LIT_ARGS, or adding a mechanism to + # allow specifying a python interpreter compiled for the target that could + # be executed using qemu-user. + message(WARNING "check-clang-python not added to check-all as these tests fail in a cross-build setup") + set(RUN_PYTHON_TESTS FALSE) +endif() + if(RUN_PYTHON_TESTS) set_property(GLOBAL APPEND PROPERTY LLVM_ALL_ADDITIONAL_TEST_TARGETS check-clang-python) diff --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake index 5327b5d2f08928820ecae68a70fca1e921b5ca23..091aec98e93ca337ec5b000b7eb3ea8427a261a9 100644 --- a/clang/cmake/modules/AddClang.cmake +++ b/clang/cmake/modules/AddClang.cmake @@ -108,6 +108,17 @@ macro(add_clang_library name) endif() llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs}) + if(MSVC AND NOT CLANG_LINK_CLANG_DYLIB) + # Make sure all consumers also turn off visibility macros so there not trying to dllimport symbols. + target_compile_definitions(${name} PUBLIC CLANG_BUILD_STATIC) + if(TARGET "obj.${name}") + target_compile_definitions("obj.${name}" PUBLIC CLANG_BUILD_STATIC) + endif() + elseif(NOT ARG_SHARED AND NOT ARG_STATIC) + # Clang component libraries linked in to clang-cpp are declared without SHARED or STATIC + target_compile_definitions("obj.${name}" PUBLIC CLANG_EXPORTS) + endif() + set(libs ${name}) if(ARG_SHARED AND ARG_STATIC) list(APPEND libs ${name}_static) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index a9bfb4c4a0fcb2ca6ef42be2eca61e3560d01f87..8add0a53e5be136c83b14af36ffc0033135e942d 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5406,22 +5406,46 @@ the configuration (without a prefix: ``Auto``). .. _ReflowComments: -**ReflowComments** (``Boolean``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - If ``true``, clang-format will attempt to re-flow comments. That is it - will touch a comment and *reflow* long comments into new lines, trying to - obey the ``ColumnLimit``. +**ReflowComments** (``ReflowCommentsStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ ` + Comment reformatting style. - .. code-block:: c++ + Possible values: + + * ``RCS_Never`` (in configuration: ``Never``) + Leave comments untouched. + + .. code-block:: c++ + + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + * and a misaligned second line */ + + * ``RCS_IndentOnly`` (in configuration: ``IndentOnly``) + Only apply indentation rules, moving comments left or right, without + changing formatting inside the comments. + + .. code-block:: c++ + + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + * and a misaligned second line */ + + * ``RCS_Always`` (in configuration: ``Always``) + Apply indentation rules and reflow long comments into new lines, trying + to obey the ``ColumnLimit``. + + .. code-block:: c++ + + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + // information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + * information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + * information and a misaligned second line */ - false: - // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ - true: - // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - // information - /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - * information */ .. _RemoveBracesLLVM: diff --git a/clang/docs/ClangPlugins.rst b/clang/docs/ClangPlugins.rst index 001e66e434efb15e44b045e6296b43808b9f3960..92e41fb5877fe8b449020b3cd23a55ac7794ec25 100644 --- a/clang/docs/ClangPlugins.rst +++ b/clang/docs/ClangPlugins.rst @@ -92,11 +92,6 @@ The members of ``ParsedAttrInfo`` that a plugin attribute must define are: attribute, each of which consists of an attribute syntax and how the attribute name is spelled for that syntax. If the syntax allows a scope then the spelling must be "scope::attr" if a scope is present or "::attr" if not. - * ``handleDeclAttribute``, which is the function that applies the attribute to - a declaration. It is responsible for checking that the attribute's arguments - are valid, and typically applies the attribute by adding an ``Attr`` to the - ``Decl``. It returns either ``AttributeApplied``, to indicate that the - attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't. The members of ``ParsedAttrInfo`` that may need to be defined, depending on the attribute, are: @@ -105,6 +100,18 @@ attribute, are: arguments to the attribute. * ``diagAppertainsToDecl``, which checks if the attribute has been used on the right kind of declaration and issues a diagnostic if not. + * ``handleDeclAttribute``, which is the function that applies the attribute to + a declaration. It is responsible for checking that the attribute's arguments + are valid, and typically applies the attribute by adding an ``Attr`` to the + ``Decl``. It returns either ``AttributeApplied``, to indicate that the + attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't. + * ``diagAppertainsToStmt``, which checks if the attribute has been used on the + right kind of statement and issues a diagnostic if not. + * ``handleStmtAttribute``, which is the function that applies the attribute to + a statement. It is responsible for checking that the attribute's arguments + are valid, and typically applies the attribute by adding an ``Attr`` to the + ``Stmt``. It returns either ``AttributeApplied``, to indicate that the + attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't. * ``diagLangOpts``, which checks if the attribute is permitted for the current language mode and issues a diagnostic if not. * ``existsInTarget``, which checks if the attribute is permitted for the given diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index fe41742a25c64236fa984d2e9320084115b74b15..10232ff41da15a704fc1cbb775256f7fc5e1ec48 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -5883,3 +5883,26 @@ specify the starting offset to begin embedding from. The resources is treated as being empty if the specified offset is larger than the number of bytes in the resource. The offset will be applied *before* any ``limit`` parameters are applied. + +Union and aggregate initialization in C +======================================= + +In C23 (N2900), when an object is initialized from initializer ``= {}``, all +elements of arrays, all members of structs, and the first members of unions are +empty-initialized recursively. In addition, all padding bits are initialized to +zero. + +Clang guarantees the following behaviors: + +* ``1:`` Clang supports initializer ``= {}`` mentioned above in all C + standards. + +* ``2:`` When unions are initialized from initializer ``= {}``, bytes outside + of the first members of unions are also initialized to zero. + +* ``3:`` When unions, structures and arrays are initialized from initializer + ``= { initializer-list }``, all members not explicitly initialized in + the initializer list are empty-initialized recursively. In addition, all + padding bits are initialized to zero. + +Currently, the above extension only applies to C source code, not C++. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index df165b9125250581250a4d9c614230cfe883df38..817e3abef8d5669cd29601cef58c31c0febaf73f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -99,6 +99,20 @@ C++ Specific Potentially Breaking Changes // Was error, now evaluates to false. constexpr bool b = f() == g(); +- The warning ``-Wdeprecated-literal-operator`` is now on by default, as this is + something that WG21 has shown interest in removing from the language. The + result is that anyone who is compiling with ``-Werror`` should see this + diagnostic. To fix this diagnostic, simply removing the space character from + between the ``operator""`` and the user defined literal name will make the + source no longer deprecated. This is consistent with `CWG2521 _`. + + .. code-block:: c++ + + // Now diagnoses by default. + unsigned operator"" _udl_name(unsigned long long); + // Fixed version: + unsigned operator""_udl_name(unsigned long long); + ABI Changes in This Version --------------------------- @@ -177,10 +191,6 @@ C++23 Feature Support C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -C++17 Feature Support -^^^^^^^^^^^^^^^^^^^^^ -- The implementation of the relaxed template template argument matching rules is - more complete and reliable, and should provide more accurate diagnostics. Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -207,8 +217,7 @@ Resolutions to C++ Defect Reports (`CWG2351: void{} `_). - Clang now has improved resolution to CWG2398, allowing class templates to have - default arguments deduced when partial ordering, and better backwards compatibility - in overload resolution. + default arguments deduced when partial ordering. - Clang now allows comparing unequal object pointers that have been cast to ``void *`` in constant expressions. These comparisons always worked in non-constant expressions. @@ -220,6 +229,10 @@ Resolutions to C++ Defect Reports - Clang now allows trailing requires clause on explicit deduction guides. (`CWG2707: Deduction guides cannot have a trailing requires-clause `_). +- Clang now diagnoses a space in the first production of a ``literal-operator-id`` + by default. + (`CWG2521: User-defined literals and reserved identifiers `_). + C Language Changes ------------------ @@ -237,6 +250,8 @@ Non-comprehensive list of changes in this release - The floating point comparison builtins (``__builtin_isgreater``, ``__builtin_isgreaterequal``, ``__builtin_isless``, etc.) and ``__builtin_signbit`` can now be used in constant expressions. +- Plugins can now define custom attributes that apply to statements + as well as declarations. New Compiler Flags ------------------ @@ -339,10 +354,6 @@ Improvements to Clang's diagnostics - Clang now diagnoses when the result of a [[nodiscard]] function is discarded after being cast in C. Fixes #GH104391. -- Clang now properly explains the reason a template template argument failed to - match a template template parameter, in terms of the C++17 relaxed matching rules - instead of the old ones. - - Don't emit duplicated dangling diagnostics. (#GH93386). - Improved diagnostic when trying to befriend a concept. (#GH45182). @@ -387,6 +398,10 @@ Improvements to Clang's diagnostics - The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``, instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being suboptimal in some way the error fails to mention (#GH111550). + +- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the + name was a reserved name, which we improperly allowed to suppress the + diagnostic. Improvements to Clang's time-trace ---------------------------------- @@ -452,8 +467,6 @@ Bug Fixes to C++ Support - Correctly check constraints of explicit instantiations of member functions. (#GH46029) - When performing partial ordering of function templates, clang now checks that the deduction was consistent. Fixes (#GH18291). -- Fixes to several issues in partial ordering of template template parameters, which - were documented in the test suite. - Fixed an assertion failure about a constraint of a friend function template references to a value with greater template depth than the friend function template. (#GH98258) - Clang now rebuilds the template parameters of out-of-line declarations and specializations in the context @@ -491,9 +504,19 @@ Bug Fixes to C++ Support in certain friend declarations. (#GH93099) - Clang now instantiates the correct lambda call operator when a lambda's class type is merged across modules. (#GH110401) +- 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) - Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460) - Fixed an assertion failure when invoking recovery call expressions with explicit attributes - and undeclared templates. (#GH107047, #GH49093) + and undeclared templates. (#GH107047), (#GH49093) +- Clang no longer crashes when a lambda contains an invalid block declaration that contains an unexpanded + parameter pack. (#GH109148) +- Fixed overload handling for object parameters with top-level cv-qualifiers in explicit member functions (#GH100394) +- Fixed a bug in lambda captures where ``constexpr`` class-type objects were not properly considered ODR-used in + certain situations. (#GH47400), (#GH90896) +- Fix erroneous templated array size calculation leading to crashes in generated code. (#GH41441) +- During the lookup for a base class name, non-type names are ignored. (#GH16855) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -601,6 +624,8 @@ CUDA/HIP Language Changes CUDA Support ^^^^^^^^^^^^ +- Clang now supports CUDA SDK up to 12.6 +- Added support for sm_100 AIX Support ^^^^^^^^^^^ @@ -614,6 +639,8 @@ WebAssembly Support AVR Support ^^^^^^^^^^^ +- Reject C/C++ compilation for avr1 devices which have no SRAM. + DWARF Support in Clang ---------------------- @@ -636,12 +663,17 @@ AST Matchers - Fixed a crash when traverse lambda expr with invalid captures. (#GH106444) +- Ensure ``hasName`` matches template specializations across inline namespaces, + making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent. + clang-format ------------ - Adds ``BreakBinaryOperations`` option. - Adds ``TemplateNames`` option. - Adds ``AlignFunctionDeclarations`` option to ``AlignConsecutiveDeclarations``. +- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments + without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``. libclang -------- diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp index 9d6cf9ae36c6a6e31fd8544e7cf200a17f23dcea..3b90724ad222052ce74c5ec0152f05fd26c7bb14 100644 --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -94,6 +94,54 @@ struct ExampleAttrInfo : public ParsedAttrInfo { } return AttributeApplied; } + + bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr, + const Stmt *St) const override { + // This attribute appertains to for loop statements only. + if (!isa(St)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) + << Attr << Attr.isRegularKeywordAttribute() << "for loop statements"; + return false; + } + return true; + } + + AttrHandling handleStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &Attr, + class Attr *&Result) const override { + // We make some rules here: + // 1. Only accept at most 3 arguments here. + // 2. The first argument must be a string literal if it exists. + if (Attr.getNumArgs() > 3) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "'example' attribute only accepts at most three arguments"); + S.Diag(Attr.getLoc(), ID); + return AttributeNotApplied; + } + // If there are arguments, the first argument should be a string literal. + if (Attr.getNumArgs() > 0) { + auto *Arg0 = Attr.getArgAsExpr(0); + StringLiteral *Literal = + dyn_cast(Arg0->IgnoreParenCasts()); + if (!Literal) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, "first argument to the 'example' " + "attribute must be a string literal"); + S.Diag(Attr.getLoc(), ID); + return AttributeNotApplied; + } + SmallVector ArgsBuf; + for (unsigned i = 0; i < Attr.getNumArgs(); i++) { + ArgsBuf.push_back(Attr.getArgAsExpr(i)); + } + Result = AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(), + ArgsBuf.size(), Attr.getRange()); + } else { + Result = AnnotateAttr::Create(S.Context, "example", nullptr, 0, + Attr.getRange()); + } + return AttributeApplied; + } }; } // namespace diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 1a8507cfbf9872335d8147c8b3fcc55dcf3f6e12..e96275e5f2e07370ad7e9a680bb4c40d113e6e8e 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -133,7 +133,8 @@ ExprDependence computeDependence(ArrayInitLoopExpr *E); ExprDependence computeDependence(ImplicitValueInitExpr *E); ExprDependence computeDependence(InitListExpr *E); ExprDependence computeDependence(ExtVectorElementExpr *E); -ExprDependence computeDependence(BlockExpr *E); +ExprDependence computeDependence(BlockExpr *E, + bool ContainsUnexpandedParameterPack); ExprDependence computeDependence(AsTypeExpr *E); ExprDependence computeDependence(DeclRefExpr *E, const ASTContext &Ctx); ExprDependence computeDependence(RecoveryExpr *E); diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 687715a22e9fd312e25b0ae2d07ccdfd780105da..141f58c4600af0be3c555d8c92add43d86597f00 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -781,15 +781,11 @@ protected: 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 @@ protected: }; /// 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,22 @@ public: /// template<> template /// struct X::Inner { /* ... */ }; /// \endcode - bool isMemberSpecialization() const { - return getCommonPtr()->InstantiatedFromMember.getInt(); + bool isMemberSpecialization() const { return Common.getInt(); } + + /// Determines whether any redeclaration of this template was + /// a specialization of a member template. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (D->isMemberSpecialization()) + return true; + } + return false; } /// 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 +913,12 @@ public: /// 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 +1997,8 @@ public: /// 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 +2010,8 @@ public: /// 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,19 +2199,23 @@ public: /// 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); + /// Determines whether any redeclaration of this this class template partial + /// specialization was a specialization of a member partial specialization. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (cast(D) + ->isMemberSpecialization()) + return true; + } + return false; } + /// Note that this member template is a specialization. + 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 /// this partial specialization, which is an InjectedClassNameType. @@ -2268,10 +2284,6 @@ protected: return static_cast(RedeclarableTemplateDecl::getCommonPtr()); } - void setCommonPtr(Common *C) { - RedeclarableTemplateDecl::Common = C; - } - public: friend class ASTDeclReader; @@ -2754,6 +2766,8 @@ public: /// 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 +2779,8 @@ public: /// 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,19 +2965,24 @@ public: /// 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); + /// Determines whether any redeclaration of this this variable template + /// partial specialization was a specialization of a member partial + /// specialization. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (cast(D) + ->isMemberSpecialization()) + return true; + } + return false; } + /// Note that this member template is a specialization. + void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } + SourceRange getSourceRange() const override LLVM_READONLY; void Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 607bf313c4d95e52384278be45277bb87d0ac2c4..cbe62411d11bffe543b582e397a0494e23c80bd8 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6413,9 +6413,9 @@ class BlockExpr : public Expr { protected: BlockDecl *TheBlock; public: - BlockExpr(BlockDecl *BD, QualType ty) + BlockExpr(BlockDecl *BD, QualType ty, bool ContainsUnexpandedParameterPack) : Expr(BlockExprClass, ty, VK_PRValue, OK_Ordinary), TheBlock(BD) { - setDependence(computeDependence(this)); + setDependence(computeDependence(this, ContainsUnexpandedParameterPack)); } /// Build an empty block expression. diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index e4f2e07222a338ff12f9279d8152ab0f69d096bd..e8b8f477f91ae7cab511ec6d32881d765b51e65c 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -119,32 +119,6 @@ public: } }; -// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so -// this provides a basic, do-nothing implementation. We still need to add this -// type to the visitors/etc, as well as get it to take its proper arguments. -class OpenACCGangClause : public OpenACCClause { -protected: - OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc) - : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { - llvm_unreachable("Not yet implemented"); - } - -public: - static bool classof(const OpenACCClause *C) { - return C->getClauseKind() == OpenACCClauseKind::Gang; - } - - static OpenACCGangClause * - Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); - - child_range children() { - return child_range(child_iterator(), child_iterator()); - } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } -}; - // Not yet implemented, but the type name is necessary for 'seq' diagnostics, so // this provides a basic, do-nothing implementation. We still need to add this // type to the visitors/etc, as well as get it to take its proper arguments. @@ -157,7 +131,7 @@ protected: public: static bool classof(const OpenACCClause *C) { - return C->getClauseKind() == OpenACCClauseKind::Gang; + return C->getClauseKind() == OpenACCClauseKind::Vector; } static OpenACCVectorClause * @@ -171,32 +145,6 @@ public: } }; -// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so -// this provides a basic, do-nothing implementation. We still need to add this -// type to the visitors/etc, as well as get it to take its proper arguments. -class OpenACCWorkerClause : public OpenACCClause { -protected: - OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc) - : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { - llvm_unreachable("Not yet implemented"); - } - -public: - static bool classof(const OpenACCClause *C) { - return C->getClauseKind() == OpenACCClauseKind::Gang; - } - - static OpenACCWorkerClause * - Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); - - child_range children() { - return child_range(child_iterator(), child_iterator()); - } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } -}; - /// Represents a clause that has a list of parameters. class OpenACCClauseWithParams : public OpenACCClause { /// Location of the '('. @@ -535,6 +483,54 @@ public: Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; }; }; +class OpenACCGangClause final + : public OpenACCClauseWithExprs, + public llvm::TrailingObjects { +protected: + OpenACCGangClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef GangKinds, + ArrayRef IntExprs, SourceLocation EndLoc); + + OpenACCGangKind getGangKind(unsigned I) const { + return getTrailingObjects()[I]; + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Gang; + } + + size_t numTrailingObjects(OverloadToken) const { + return getNumExprs(); + } + + unsigned getNumExprs() const { return getExprs().size(); } + std::pair getExpr(unsigned I) const { + return {getGangKind(I), getExprs()[I]}; + } + + static OpenACCGangClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, + SourceLocation LParenLoc, ArrayRef GangKinds, + ArrayRef IntExprs, SourceLocation EndLoc); +}; + +class OpenACCWorkerClause : public OpenACCClauseWithSingleIntExpr { +protected: + OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + Expr *IntExpr, SourceLocation EndLoc); + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Worker; + } + + static OpenACCWorkerClause *Create(const ASTContext &Ctx, + SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *IntExpr, + SourceLocation EndLoc); +}; + class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr { OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, SourceLocation EndLoc); diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 332ac3c6a004a95678f117f31ddad80d0dc7527e..91818776b770cf2f10a0d90cf1b485ee2b204309 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -55,15 +55,17 @@ public: /// This type is intended to be small and suitable for passing by value. /// It is very frequently copied. struct PrintingPolicy { + enum SuppressInlineNamespaceMode : uint8_t { None, Redundant, All }; + /// Create a default printing policy for the specified language. PrintingPolicy(const LangOptions &LO) : Indentation(2), SuppressSpecifiers(false), SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), - SuppressInlineNamespace(true), SuppressElaboration(false), - SuppressInitializers(false), ConstantArraySizeAsWritten(false), - AnonymousTagLocations(true), SuppressStrongLifetime(false), - SuppressLifetimeQualifiers(false), + SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant), + SuppressElaboration(false), SuppressInitializers(false), + ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), + SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus), @@ -141,10 +143,12 @@ struct PrintingPolicy { unsigned SuppressUnwrittenScope : 1; /// Suppress printing parts of scope specifiers that correspond - /// to inline namespaces, where the name is unambiguous with the specifier + /// to inline namespaces. + /// If Redudant, where the name is unambiguous with the specifier removed. + /// If All, even if the name is ambiguous with the specifier /// removed. - LLVM_PREFERRED_TYPE(bool) - unsigned SuppressInlineNamespace : 1; + LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode) + unsigned SuppressInlineNamespace : 2; /// Ignore qualifiers and tag keywords as specified by elaborated type sugar, /// instead letting the underlying type print as normal. diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 7068473a0e12ac4f12373e700271bf2cee66d342..bda8a48be92bda81fe596f6410f651e9b8733947 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate { let Prototype = "T(T, T)"; } +def FmaximumNumF16F128 : Builtin, F16F128MathTemplate { + let Spellings = ["__builtin_fmaximum_num"]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; + let Prototype = "T(T, T)"; +} + +def FminimumNumF16F128 : Builtin, F16F128MathTemplate { + let Spellings = ["__builtin_fminimum_num"]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; + let Prototype = "T(T, T)"; +} + def Atan2F128 : Builtin { let Spellings = ["__builtin_atan2f128"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; @@ -1186,13 +1198,13 @@ def AllowRuntimeCheck : Builtin { def ShuffleVector : Builtin { let Spellings = ["__builtin_shufflevector"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } def ConvertVector : Builtin { let Spellings = ["__builtin_convertvector"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } @@ -3728,6 +3740,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> { let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } +def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> { + let Spellings = ["fmaximum_num"]; + let Attributes = [NoThrow, Const]; + let Prototype = "T(T, T)"; + let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; +} + +def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> { + let Spellings = ["fminimum_num"]; + let Attributes = [NoThrow, Const]; + let Prototype = "T(T, T)"; + let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; +} + def Hypot : FPMathTemplate, LibBuiltin<"math.h"> { let Spellings = ["hypot"]; let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def index 6b7bce5bc00d4f3bf57eb549054210161d12033d..969dd9e41ebfa3a0021ea31c331969a97b36c290 100644 --- a/clang/include/clang/Basic/BuiltinsNVPTX.def +++ b/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -27,8 +27,10 @@ #pragma push_macro("SM_89") #pragma push_macro("SM_90") #pragma push_macro("SM_90a") +#pragma push_macro("SM_100") +#define SM_100 "sm_100" #define SM_90a "sm_90a" -#define SM_90 "sm_90|" SM_90a +#define SM_90 "sm_90|" SM_90a "|" SM_100 #define SM_89 "sm_89|" SM_90 #define SM_87 "sm_87|" SM_89 #define SM_86 "sm_86|" SM_87 @@ -63,7 +65,9 @@ #pragma push_macro("PTX83") #pragma push_macro("PTX84") #pragma push_macro("PTX85") -#define PTX85 "ptx85" +#pragma push_macro("PTX86") +#define PTX86 "ptx86" +#define PTX85 "ptx85|" PTX86 #define PTX84 "ptx84|" PTX85 #define PTX83 "ptx83|" PTX84 #define PTX82 "ptx82|" PTX83 @@ -1086,6 +1090,7 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78)) #pragma pop_macro("SM_89") #pragma pop_macro("SM_90") #pragma pop_macro("SM_90a") +#pragma pop_macro("SM_100") #pragma pop_macro("PTX42") #pragma pop_macro("PTX60") #pragma pop_macro("PTX61") @@ -1108,3 +1113,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78)) #pragma pop_macro("PTX83") #pragma pop_macro("PTX84") #pragma pop_macro("PTX85") +#pragma pop_macro("PTX86") diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 83699f8897f6630d4015667dac6961d7bf0e0bad..a18e62620dd5d0b72e6499638c98237f9b61b4b5 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -43,9 +43,10 @@ enum class CudaVersion { CUDA_123, CUDA_124, CUDA_125, + CUDA_126, FULLY_SUPPORTED = CUDA_123, PARTIALLY_SUPPORTED = - CUDA_125, // Partially supported. Proceed with a warning. + CUDA_126, // Partially supported. Proceed with a warning. NEW = 10000, // Too new. Issue a warning, but allow using it. }; const char *CudaVersionToString(CudaVersion V); @@ -78,6 +79,7 @@ enum class OffloadArch { SM_89, SM_90, SM_90a, + SM_100, GFX600, GFX601, GFX602, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ae08a9160d3cef8e8b3de87f5900813fdacc7544..7c702358287aa20e8200e7d94c06dc6116ca020b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -250,7 +250,12 @@ def ext_designated_init_brace_elision : ExtWarn< // Declarations. def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; -def ext_imaginary_constant : Extension< +def warn_c23_compat_imaginary_constant : Warning< + "imaginary constants are incompatible with C standards before C2y">, + DefaultIgnore, InGroup; +def ext_c2y_imaginary_constant : Extension< + "imaginary constants are a C2y extension">, InGroup; +def ext_gnu_imaginary_constant : Extension< "imaginary constants are a GNU extension">, InGroup; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; @@ -439,7 +444,7 @@ def warn_reserved_extern_symbol: Warning< InGroup, DefaultIgnore; def warn_deprecated_literal_operator_id: Warning< "identifier %0 preceded by whitespace in a literal operator declaration " - "is deprecated">, InGroup, DefaultIgnore; + "is deprecated">, InGroup; def warn_reserved_module_name : Warning< "%0 is a reserved name for a module">, InGroup; def warn_import_implementation_partition_unit_in_interface_unit : Warning< @@ -5262,13 +5267,6 @@ def note_template_arg_refers_here_func : Note< def err_template_arg_template_params_mismatch : Error< "template template argument has different template parameters than its " "corresponding template template parameter">; -def note_template_arg_template_params_mismatch : Note< - "template template argument has different template parameters than its " - "corresponding template template parameter">; -def err_non_deduced_mismatch : Error< - "could not match %diff{$ against $|types}0,1">; -def err_inconsistent_deduction : Error< - "conflicting deduction %diff{$ against $|types}0,1 for parameter">; def err_template_arg_not_integral_or_enumeral : Error< "non-type template argument of type %0 must have an integral or enumeration" " type">; @@ -12609,6 +12607,7 @@ def err_acc_duplicate_clause_disallowed : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' " "directive">; def note_acc_previous_clause_here : Note<"previous clause is here">; +def note_acc_previous_expr_here : Note<"previous expression is here">; def err_acc_branch_in_out_compute_construct : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 " "OpenACC Compute Construct">; @@ -12715,6 +12714,25 @@ def err_acc_insufficient_loops def err_acc_intervening_code : Error<"inner loops must be tightly nested inside a '%0' clause on " "a 'loop' construct">; +def err_acc_gang_multiple_elt + : Error<"OpenACC 'gang' clause may have at most one %select{unnamed or " + "'num'|'dim'|'static'}0 argument">; +def err_acc_int_arg_invalid + : Error<"'%1' argument on '%0' clause is not permitted on a%select{n " + "orphaned|||}2 'loop' construct %select{|associated with a " + "'parallel' compute construct|associated with a 'kernels' compute " + "construct|associated with a 'serial' compute construct}2">; +def err_acc_gang_dim_value + : Error<"argument to 'gang' clause dimension must be %select{a constant " + "expression|1, 2, or 3: evaluated to %1}0">; +def err_acc_num_arg_conflict + : Error<"'num' argument to '%0' clause not allowed on a 'loop' construct " + "associated with a 'kernels' construct that has a " + "'%select{num_gangs|num_workers}1' " + "clause">; +def err_acc_clause_in_clause_region + : Error<"loop with a '%0' clause may not exist in the region of a '%1' " + "clause%select{| on a 'kernels' compute construct}2">; // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index a380e5ae69c41820b835106d0d21cee884207449..4c0b56dc13e62555c36c66547007daf91a2f854a 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -42,6 +42,7 @@ VISIT_CLAUSE(DevicePtr) VISIT_CLAUSE(DeviceType) CLAUSE_ALIAS(DType, DeviceType, false) VISIT_CLAUSE(FirstPrivate) +VISIT_CLAUSE(Gang) VISIT_CLAUSE(If) VISIT_CLAUSE(Independent) VISIT_CLAUSE(NoCreate) @@ -55,6 +56,7 @@ VISIT_CLAUSE(Seq) VISIT_CLAUSE(Tile) VISIT_CLAUSE(VectorLength) VISIT_CLAUSE(Wait) +VISIT_CLAUSE(Worker) #undef VISIT_CLAUSE #undef CLAUSE_ALIAS diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 7b9d619a8aec6d5b6764493db13cef5937f9fc2c..4310c28bc935e8719a8a73e7a76cb3b5a91da34a 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -22,7 +22,7 @@ namespace clang { // Represents the Construct/Directive kind of a pragma directive. Note the // OpenACC standard is inconsistent between calling these Construct vs // Directive, but we're calling it a Directive to be consistent with OpenMP. -enum class OpenACCDirectiveKind { +enum class OpenACCDirectiveKind : uint8_t { // Compute Constructs. Parallel, Serial, @@ -152,7 +152,7 @@ inline bool isOpenACCComputeDirectiveKind(OpenACCDirectiveKind K) { K == OpenACCDirectiveKind::Kernels; } -enum class OpenACCAtomicKind { +enum class OpenACCAtomicKind : uint8_t { Read, Write, Update, @@ -161,7 +161,7 @@ enum class OpenACCAtomicKind { }; /// Represents the kind of an OpenACC clause. -enum class OpenACCClauseKind { +enum class OpenACCClauseKind : uint8_t { /// 'finalize' clause, allowed on 'exit data' directive. Finalize, /// 'if_present' clause, allowed on 'host_data' and 'update' directives. @@ -459,7 +459,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, return printOpenACCClauseKind(Out, K); } -enum class OpenACCDefaultClauseKind { +enum class OpenACCDefaultClauseKind : uint8_t { /// 'none' option. None, /// 'present' option. @@ -492,7 +492,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, return printOpenACCDefaultClauseKind(Out, K); } -enum class OpenACCReductionOperator { +enum class OpenACCReductionOperator : uint8_t { /// '+'. Addition, /// '*'. @@ -550,6 +550,36 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCReductionOperator Op) { return printOpenACCReductionOperator(Out, Op); } + +enum class OpenACCGangKind : uint8_t { + /// num: + Num, + /// dim: + Dim, + /// static: + Static +}; + +template +inline StreamTy &printOpenACCGangKind(StreamTy &Out, OpenACCGangKind GK) { + switch (GK) { + case OpenACCGangKind::Num: + return Out << "num"; + case OpenACCGangKind::Dim: + return Out << "dim"; + case OpenACCGangKind::Static: + return Out << "static"; + } + llvm_unreachable("unknown gang kind"); +} +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, + OpenACCGangKind Op) { + return printOpenACCGangKind(Out, Op); +} +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, + OpenACCGangKind Op) { + return printOpenACCGangKind(Out, Op); +} } // namespace clang #endif // LLVM_CLANG_BASIC_OPENACCKINDS_H diff --git a/clang/include/clang/Basic/ParsedAttrInfo.h b/clang/include/clang/Basic/ParsedAttrInfo.h index 537d8f3391d5898705317fd5637c450ec8c00625..fab5c6f1377d270b1c2ec84593c2f6f273a9f7f9 100644 --- a/clang/include/clang/Basic/ParsedAttrInfo.h +++ b/clang/include/clang/Basic/ParsedAttrInfo.h @@ -24,6 +24,7 @@ namespace clang { +class Attr; class Decl; class LangOptions; class ParsedAttr; @@ -154,6 +155,15 @@ public: const ParsedAttr &Attr) const { return NotHandled; } + /// If this ParsedAttrInfo knows how to handle this ParsedAttr applied to this + /// Stmt then do so (referencing the resulting Attr in Result) and return + /// either AttributeApplied if it was applied or AttributeNotApplied if it + /// wasn't. Otherwise return NotHandled. + virtual AttrHandling handleStmtAttribute(Sema &S, Stmt *St, + const ParsedAttr &Attr, + class Attr *&Result) const { + return NotHandled; + } static const ParsedAttrInfo &get(const AttributeCommonInfo &A); static ArrayRef getAllBuiltin(); diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b18965dd7fe1aab62f8e4b26141d449429e57817..5c2204a3c4d3180ed0c41e735969da32709a4d76 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2002,16 +2002,18 @@ 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 clang + DocBrief<[{Generate a section named ".GCC.command.line" containing the 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; + Group, + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; def fno_record_command_line : Flag<["-"], "fno-record-command-line">, - Group; + Group, + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; def : Flag<["-"], "frecord-gcc-switches">, Alias; def : Flag<["-"], "fno-record-gcc-switches">, Alias; def fcommon : Flag<["-"], "fcommon">, Group, @@ -7173,6 +7175,9 @@ 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] @@ -7193,9 +7198,6 @@ 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/Format/Format.h b/clang/include/clang/Format/Format.h index 3d3e4330902a300b8ebee568713973e1b4c8f05f..a0762b088b68ef3d94e1415b742370a4b2bd5103 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3847,24 +3847,43 @@ struct FormatStyle { ReferenceAlignmentStyle ReferenceAlignment; // clang-format off - /// If ``true``, clang-format will attempt to re-flow comments. That is it - /// will touch a comment and *reflow* long comments into new lines, trying to - /// obey the ``ColumnLimit``. - /// \code - /// false: - /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ - /// - /// true: - /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - /// // information - /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - /// * information */ - /// \endcode - /// \version 3.8 - bool ReflowComments; + /// \brief Types of comment reflow style. + enum ReflowCommentsStyle : int8_t { + /// Leave comments untouched. + /// \code + /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /// * and a misaligned second line */ + /// \endcode + RCS_Never, + /// Only apply indentation rules, moving comments left or right, without + /// changing formatting inside the comments. + /// \code + /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /// * and a misaligned second line */ + /// \endcode + RCS_IndentOnly, + /// Apply indentation rules and reflow long comments into new lines, trying + /// to obey the ``ColumnLimit``. + /// \code + /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + /// // information + /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + /// * information */ + /// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + /// * information and a misaligned second line */ + /// \endcode + RCS_Always + }; // clang-format on + /// \brief Comment reformatting style. + /// \version 3.8 + ReflowCommentsStyle ReflowComments; + /// Remove optional braces of control statements (``if``, ``else``, ``for``, /// and ``while``) in C++ according to the LLVM coding style. /// \warning diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f21a63a6c3f2e6fe6044f0d1cdaf451a8f5c9c58..acd1da7fa9c39d3dc1f7d5703c32281900ee1f90 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3838,9 +3838,15 @@ private: bool ParseOpenACCSizeExprList(OpenACCClauseKind CK, llvm::SmallVectorImpl &SizeExprs); /// Parses a 'gang-arg-list', used for the 'gang' clause. - bool ParseOpenACCGangArgList(SourceLocation GangLoc); - /// Parses a 'gang-arg', used for the 'gang' clause. - bool ParseOpenACCGangArg(SourceLocation GangLoc); + bool ParseOpenACCGangArgList(SourceLocation GangLoc, + llvm::SmallVectorImpl &GKs, + llvm::SmallVectorImpl &IntExprs); + + using OpenACCGangArgRes = std::pair; + /// Parses a 'gang-arg', used for the 'gang' clause. Returns a pair of the + /// ExprResult (which contains the validity of the expression), plus the gang + /// kind for the current argument. + OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc); /// Parses a 'condition' expr, ensuring it results in a ExprResult ParseOpenACCConditionExpr(); diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index d38278c5041118fa71db6d65b70a0575d5a8ab3f..c716a25bb673b8b36a743004d6901771f2a89454 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -925,11 +925,6 @@ class Sema; bool TookAddressOfOverload : 1; - /// Have we matched any packs on the parameter side, versus any non-packs on - /// the argument side, in a context where the opposite matching is also - /// allowed? - bool HasMatchedPackOnParmToNonPackOnArg : 1; - /// True if the candidate was found using ADL. CallExpr::ADLCallKind IsADLCandidate : 1; @@ -1004,9 +999,8 @@ class Sema; friend class OverloadCandidateSet; OverloadCandidate() : IsSurrogate(false), IgnoreObjectArgument(false), - TookAddressOfOverload(false), - HasMatchedPackOnParmToNonPackOnArg(false), - IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {} + TookAddressOfOverload(false), IsADLCandidate(CallExpr::NotADL), + RewriteKind(CRK_None) {} }; /// OverloadCandidateSet - A set of overload candidates, used in C++ diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 700e361ef83f13c0265ab54c0a1e2161fdb425eb..958d65055fa9b2a6718592cec6324274fb3af810 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -724,10 +724,16 @@ public: /// is deduced (e.g. a lambda or block with omitted return type). bool HasImplicitReturnType = false; + /// Whether this contains an unexpanded parameter pack. + bool ContainsUnexpandedParameterPack = false; + /// ReturnType - The target type of return statements in this context, /// or null if unknown. QualType ReturnType; + /// Packs introduced by this, if any. + SmallVector LocalPacks; + void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested, SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType, bool Invalid) { @@ -895,12 +901,6 @@ public: /// Whether any of the capture expressions requires cleanups. CleanupInfo Cleanup; - /// Whether the lambda contains an unexpanded parameter pack. - bool ContainsUnexpandedParameterPack = false; - - /// Packs introduced by this lambda, if any. - SmallVector LocalPacks; - /// Source range covering the explicit template parameter list (if it exists). SourceRange ExplicitTemplateParamsRange; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f8118ca64ad3f2218d122ff2cb3d5da4cd9a1c81..0faa5aed4eec3bc8bb36d4a6f83694179304f5a9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -702,10 +702,10 @@ public: /// Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); - /// Get the innermost lambda enclosing the current location, if any. This - /// looks through intervening non-lambda scopes such as local functions and - /// blocks. - sema::LambdaScopeInfo *getEnclosingLambda() const; + /// Get the innermost lambda or block enclosing the current location, if any. + /// This looks through intervening non-lambda, non-block scopes such as local + /// functions. + sema::CapturingScopeInfo *getEnclosingLambdaOrBlock() const; /// Retrieve the current lambda scope info, if any. /// \param IgnoreNonLambdaCapturingScope true if should find the top-most @@ -872,8 +872,6 @@ public: /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; - bool WarnedStackExhausted = false; - void incrementMSManglingNumber() const { return CurScope->incrementMSManglingNumber(); } @@ -1185,6 +1183,8 @@ private: std::optional> CachedDarwinSDKInfo; bool WarnedDarwinSDKInfoMissing = false; + bool WarnedStackExhausted = false; + Sema(const Sema &) = delete; void operator=(const Sema &) = delete; @@ -10134,8 +10134,7 @@ public: ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = std::nullopt, OverloadCandidateParamOrder PO = {}, - bool AggregateCandidateDeduction = false, - bool HasMatchedPackOnParmToNonPackOnArg = false); + bool AggregateCandidateDeduction = false); /// Add all of the function declarations in the given function set to /// the overload candidate set. @@ -10170,8 +10169,7 @@ public: bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = std::nullopt, - OverloadCandidateParamOrder PO = {}, - bool HasMatchedPackOnParmToNonPackOnArg = false); + OverloadCandidateParamOrder PO = {}); /// Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member @@ -10217,8 +10215,7 @@ public: CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, - bool AllowExplicit, bool AllowResultConversion = true, - bool HasMatchedPackOnParmToNonPackOnArg = false); + bool AllowExplicit, bool AllowResultConversion = true); /// Adds a conversion function template specialization /// candidate to the overload set, using template argument deduction @@ -11330,9 +11327,9 @@ public: 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. @@ -11371,7 +11368,8 @@ public: 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 @@ -11641,8 +11639,7 @@ public: SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, - CheckTemplateArgumentKind CTAK, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg); + CheckTemplateArgumentKind CTAK); /// Check that the given template arguments can be provided to /// the given template, converting the arguments along the way. @@ -11689,8 +11686,7 @@ public: SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions = true, - bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false, - bool *MatchedPackOnParmToNonPackOnArg = nullptr); + bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false); bool CheckTemplateTypeArgument( TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, @@ -11724,9 +11720,7 @@ public: /// It returns true if an error occurred, and false otherwise. bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, - TemplateArgumentLoc &Arg, - bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg); + TemplateArgumentLoc &Arg, bool IsDeduced); void NoteTemplateLocation(const NamedDecl &Decl, std::optional ParamRange = {}); @@ -12237,8 +12231,8 @@ public: SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, - SmallVectorImpl const *OriginalCallArgs, - bool PartialOverloading, bool PartialOrdering, + SmallVectorImpl const *OriginalCallArgs = nullptr, + bool PartialOverloading = false, llvm::function_ref CheckNonDependent = [] { return false; }); /// Perform template argument deduction from a function call @@ -12272,8 +12266,7 @@ public: TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading, bool AggregateDeductionCandidate, - bool PartialOrdering, QualType ObjectType, - Expr::Classification ObjectClassification, + QualType ObjectType, Expr::Classification ObjectClassification, llvm::function_ref)> CheckNonDependent); /// Deduce template arguments when taking the address of a function @@ -12426,9 +12419,8 @@ public: sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg, - const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, - bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg); + TemplateParameterList *PParam, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced); /// Mark which template parameters are used in a given expression. /// @@ -12737,9 +12729,6 @@ public: /// We are instantiating a type alias template declaration. TypeAliasTemplateInstantiation, - - /// We are performing partial ordering for template template parameters. - PartialOrderingTTP, } Kind; /// Was the enclosing context a non-instantiation SFINAE context? @@ -12961,12 +12950,6 @@ public: TemplateDecl *Entity, BuildingDeductionGuidesTag, SourceRange InstantiationRange = SourceRange()); - struct PartialOrderingTTP {}; - /// \brief Note that we are partial ordering template template parameters. - InstantiatingTemplate(Sema &SemaRef, SourceLocation ArgLoc, - PartialOrderingTTP, TemplateDecl *PArg, - SourceRange InstantiationRange = SourceRange()); - /// Note that we have finished instantiating this template. void Clear(); @@ -13027,28 +13010,14 @@ public: /// 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. @@ -13427,8 +13396,7 @@ public: bool InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, bool Complain = true, - bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false); + TemplateSpecializationKind TSK, bool Complain = true); /// Instantiates the definitions of all of the member /// of the given class, which is an instantiation of a class template diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 97386d2378b7583b2a2fda290b7e9dac4e4e0a87..e253610a84b0bf5c4da13c29c9a01f4aba59f867 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -38,9 +38,20 @@ private: /// haven't had their 'parent' compute construct set yet. Entires will only be /// made to this list in the case where we know the loop isn't an orphan. llvm::SmallVector ParentlessLoopConstructs; - /// Whether we are inside of a compute construct, and should add loops to the - /// above collection. - bool InsideComputeConstruct = false; + + struct ComputeConstructInfo { + /// Which type of compute construct we are inside of, which we can use to + /// determine whether we should add loops to the above collection. We can + /// also use it to diagnose loop construct clauses. + OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid; + // If we have an active compute construct, stores the list of clauses we've + // prepared for it, so that we can diagnose limitations on child constructs. + ArrayRef Clauses; + } ActiveComputeConstructInfo; + + bool isInComputeConstruct() const { + return ActiveComputeConstructInfo.Kind != OpenACCDirectiveKind::Invalid; + } /// Certain clauses care about the same things that aren't specific to the /// individual clause, but can be shared by a few, so store them here. All @@ -99,6 +110,20 @@ private: } TileInfo; public: + ComputeConstructInfo &getActiveComputeConstructInfo() { + return ActiveComputeConstructInfo; + } + + /// If there is a current 'active' loop construct with a 'gang' clause on a + /// 'kernel' construct, this will have the source location for it. This + /// permits us to implement the restriction of no further 'gang' clauses. + SourceLocation LoopGangClauseOnKernelLoc; + /// If there is a current 'active' loop construct with a 'worker' clause on it + /// (on any sort of construct), this has the source location for it. This + /// permits us to implement the restriction of no further 'gang' or 'worker' + /// clauses. + SourceLocation LoopWorkerClauseLoc; + // Redeclaration of the version in OpenACCClause.h. using DeviceTypeArgument = std::pair; @@ -149,9 +174,14 @@ public: Expr *LoopCount; }; + struct GangDetails { + SmallVector GangKinds; + SmallVector IntExprs; + }; + std::variant + ReductionDetails, CollapseDetails, GangDetails> Details = std::monostate{}; public: @@ -199,11 +229,15 @@ public: ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Tile || + ClauseKind == OpenACCClauseKind::Worker || + ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); // 'async' and 'wait' have an optional IntExpr, so be tolerant of that. if ((ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::Worker || + ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::Wait) && std::holds_alternative(Details)) return 0; @@ -245,9 +279,20 @@ public: ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Tile || + ClauseKind == OpenACCClauseKind::Gang || + ClauseKind == OpenACCClauseKind::Worker || + ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); + if (ClauseKind == OpenACCClauseKind::Gang) { + // There might not be any gang int exprs, as this is an optional + // argument. + if (std::holds_alternative(Details)) + return {}; + return std::get(Details).IntExprs; + } + return std::get(Details).IntExprs; } @@ -259,6 +304,16 @@ public: return std::get(Details).Op; } + ArrayRef getGangKinds() const { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed clause kind does not have gang kind"); + // The args on gang are optional, so this might not actually hold + // anything. + if (std::holds_alternative(Details)) + return {}; + return std::get(Details).GangKinds; + } + ArrayRef getVarList() { assert((ClauseKind == OpenACCClauseKind::Private || ClauseKind == OpenACCClauseKind::NoCreate || @@ -357,6 +412,8 @@ public: ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Tile || + ClauseKind == OpenACCClauseKind::Worker || + ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); Details = IntExprDetails{{IntExprs.begin(), IntExprs.end()}}; @@ -366,11 +423,32 @@ public: ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Tile || + ClauseKind == OpenACCClauseKind::Worker || + ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); Details = IntExprDetails{std::move(IntExprs)}; } + void setGangDetails(ArrayRef GKs, + ArrayRef IntExprs) { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed Clause kind does not have gang details"); + assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?"); + + Details = GangDetails{{GKs.begin(), GKs.end()}, + {IntExprs.begin(), IntExprs.end()}}; + } + + void setGangDetails(llvm::SmallVector &&GKs, + llvm::SmallVector &&IntExprs) { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed Clause kind does not have gang details"); + assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?"); + + Details = GangDetails{std::move(GKs), std::move(IntExprs)}; + } + void setVarListDetails(ArrayRef VarList, bool IsReadOnly, bool IsZero) { assert((ClauseKind == OpenACCClauseKind::Private || @@ -545,10 +623,12 @@ public: SourceLocation RBLoc); /// Checks the loop depth value for a collapse clause. ExprResult CheckCollapseLoopCount(Expr *LoopCount); - /// Checks a single size expr for a tile clause. 'gang' could possibly call - /// this, but has slightly stricter rules as to valid values. + /// Checks a single size expr for a tile clause. ExprResult CheckTileSizeExpr(Expr *SizeExpr); + // Check a single expression on a gang clause. + ExprResult CheckGangExpr(OpenACCGangKind GK, Expr *E); + ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); @@ -595,8 +675,10 @@ public: /// Loop needing its parent construct. class AssociatedStmtRAII { SemaOpenACC &SemaRef; - bool WasInsideComputeConstruct; + ComputeConstructInfo OldActiveComputeConstructInfo; OpenACCDirectiveKind DirKind; + SourceLocation OldLoopGangClauseOnKernelLoc; + SourceLocation OldLoopWorkerClauseLoc; llvm::SmallVector ParentlessLoopConstructs; LoopInConstructRAII LoopRAII; diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index fe27290efdbfc591a7308fba5d90902db6532175..6872d04cc4dfb9bf02caf931a1f5f5f30a93d3b0 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -411,10 +411,10 @@ enum class TemplateSubstitutionKind : char { /// lookup will search our outer scope. bool CombineWithOuterScope; - /// Whether this scope is being used to instantiate a lambda expression, - /// in which case it should be reused for instantiating the lambda's - /// FunctionProtoType. - bool InstantiatingLambda = false; + /// Whether this scope is being used to instantiate a lambda or block + /// expression, in which case it should be reused for instantiating the + /// lambda's FunctionProtoType. + bool InstantiatingLambdaOrBlock = false; /// If non-NULL, the template parameter pack that has been /// partially substituted per C++0x [temp.arg.explicit]p9. @@ -431,10 +431,10 @@ enum class TemplateSubstitutionKind : char { public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, - bool InstantiatingLambda = false) + bool InstantiatingLambdaOrBlock = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), CombineWithOuterScope(CombineWithOuterScope), - InstantiatingLambda(InstantiatingLambda) { + InstantiatingLambdaOrBlock(InstantiatingLambdaOrBlock) { SemaRef.CurrentInstantiationScope = this; } @@ -561,8 +561,8 @@ enum class TemplateSubstitutionKind : char { /// Determine whether D is a pack expansion created in this scope. bool isLocalPackExpansion(const Decl *D); - /// Determine whether this scope is for instantiating a lambda. - bool isLambda() const { return InstantiatingLambda; } + /// Determine whether this scope is for instantiating a lambda or block. + bool isLambdaOrBlock() const { return InstantiatingLambdaOrBlock; } }; class TemplateDeclInstantiator diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index 9c12eef5c42a064f4df08ae827fb3b89dd3c8433..28b014fd84e4b35a641f925080cf4551208e9870 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -51,11 +51,6 @@ class TemplateDeductionInfo { /// Have we suppressed an error during deduction? bool HasSFINAEDiagnostic = false; - /// Have we matched any packs on the parameter side, versus any non-packs on - /// the argument side, in a context where the opposite matching is also - /// allowed? - bool MatchedPackOnParmToNonPackOnArg = false; - /// The template parameter depth for which we're performing deduction. unsigned DeducedDepth; @@ -92,14 +87,6 @@ public: return DeducedDepth; } - bool hasMatchedPackOnParmToNonPackOnArg() const { - return MatchedPackOnParmToNonPackOnArg; - } - - void setMatchedPackOnParmToNonPackOnArg() { - MatchedPackOnParmToNonPackOnArg = true; - } - /// Get the number of explicitly-specified arguments. unsigned getNumExplicitArgs() const { return ExplicitArgs; diff --git a/clang/include/clang/Support/Compiler.h b/clang/include/clang/Support/Compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..c35815e106d2e2323f78e31840d2af3ae4dabf05 --- /dev/null +++ b/clang/include/clang/Support/Compiler.h @@ -0,0 +1,63 @@ +//===-- clang/Support/Compiler.h - Compiler abstraction support -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines explicit visibility macros used to export symbols from +// clang-cpp +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SUPPORT_COMPILER_H +#define CLANG_SUPPORT_COMPILER_H + +#include "llvm/Support/Compiler.h" + +/// CLANG_ABI is the main export/visibility macro to mark something as +/// explicitly exported when clang is built as a shared library with everything +/// else that is unannotated having hidden visibility. +/// +/// CLANG_EXPORT_TEMPLATE is used on explicit template instantiations in source +/// files that were declared extern in a header. This macro is only set as a +/// compiler export attribute on windows, on other platforms it does nothing. +/// +/// CLANG_TEMPLATE_ABI is for annotating extern template declarations in headers +/// for both functions and classes. On windows its turned in to dllimport for +/// library consumers, for other platforms its a default visibility attribute. +#ifndef CLANG_ABI_GENERATING_ANNOTATIONS +// Marker to add to classes or functions in public headers that should not have +// export macros added to them by the clang tool +#define CLANG_ABI_NOT_EXPORTED +// Some libraries like those for tablegen are linked in to tools that used +// in the build so can't depend on the llvm shared library. If export macros +// were left enabled when building these we would get duplicate or +// missing symbol linker errors on windows. +#if defined(CLANG_BUILD_STATIC) +#define CLANG_ABI +#define CLANG_TEMPLATE_ABI +#define CLANG_EXPORT_TEMPLATE +#elif defined(_WIN32) && !defined(__MINGW32__) +#if defined(CLANG_EXPORTS) +#define CLANG_ABI __declspec(dllexport) +#define CLANG_TEMPLATE_ABI +#define CLANG_EXPORT_TEMPLATE __declspec(dllexport) +#else +#define CLANG_ABI __declspec(dllimport) +#define CLANG_TEMPLATE_ABI __declspec(dllimport) +#define CLANG_EXPORT_TEMPLATE +#endif +#elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX) +#define CLANG_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT +#define CLANG_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT +#define CLANG_EXPORT_TEMPLATE +#elif defined(__MACH__) || defined(__WASM__) +#define CLANG_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT +#define CLANG_TEMPLATE_ABI +#define CLANG_EXPORT_TEMPLATE +#endif +#endif + +#endif diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 0a3b38b0dc6e5730889b558191bbbabcb10e321a..8ca63bf64aa0ef996c7134d6eaacdb518b690bc3 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2869,6 +2869,11 @@ bool Compiler::VisitPredefinedExpr(const PredefinedExpr *E) { if (DiscardResult) return true; + if (!Initializing) { + unsigned StringIndex = P.createGlobalString(E->getFunctionName(), E); + return this->emitGetPtrGlobal(StringIndex, E); + } + return this->delegate(E->getFunctionName()); } @@ -3411,6 +3416,9 @@ bool Compiler::VisitCXXDeleteExpr(const CXXDeleteExpr *E) { template bool Compiler::VisitBlockExpr(const BlockExpr *E) { + if (DiscardResult) + return true; + const Function *Func = nullptr; if (auto F = Compiler(Ctx, P).compileObjCBlock(E)) Func = F; @@ -3537,8 +3545,8 @@ bool Compiler::VisitConvertVectorExpr(const ConvertVectorExpr *E) { QualType ElemType = VT->getElementType(); PrimType ElemT = classifyPrim(ElemType); const Expr *Src = E->getSrcExpr(); - PrimType SrcElemT = - classifyPrim(Src->getType()->castAs()->getElementType()); + QualType SrcType = Src->getType(); + PrimType SrcElemT = classifyVectorElementType(SrcType); unsigned SrcOffset = this->allocateLocalPrimitive(Src, PT_Ptr, true, false); if (!this->visit(Src)) @@ -3551,9 +3559,15 @@ bool Compiler::VisitConvertVectorExpr(const ConvertVectorExpr *E) { return false; if (!this->emitArrayElemPop(SrcElemT, I, E)) return false; + + // Cast to the desired result element type. if (SrcElemT != ElemT) { if (!this->emitPrimCast(SrcElemT, ElemT, ElemType, E)) return false; + } else if (ElemType->isFloatingType() && SrcType != ElemType) { + const auto *TargetSemantics = &Ctx.getFloatSemantics(ElemType); + if (!this->emitCastFP(TargetSemantics, getRoundingMode(E), E)) + return false; } if (!this->emitInitElem(ElemT, I, E)) return false; diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 74e9e1cf62937298009d6728c30548577c6cf0e0..65c7b4e5306d7203c284a5e1d3e0ee5cb74fae50 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -38,7 +38,6 @@ static T getParam(const InterpFrame *Frame, unsigned Index) { return Frame->getParam(Offset); } -// static APSInt getAPSIntParam(InterpStack &Stk, size_t Offset = 0) { static APSInt getAPSIntParam(const InterpFrame *Frame, unsigned Index) { APSInt R; unsigned Offset = Frame->getFunction()->getParamOffset(Index); @@ -334,39 +333,48 @@ static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, } static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, - const InterpFrame *Frame, const Function *F) { + const InterpFrame *Frame, const Function *F, + bool IsNumBuiltin) { const Floating &LHS = getParam(Frame, 0); const Floating &RHS = getParam(Frame, 1); Floating Result; - // When comparing zeroes, return -0.0 if one of the zeroes is negative. - if (LHS.isZero() && RHS.isZero() && RHS.isNegative()) - Result = RHS; - else if (LHS.isNan() || RHS < LHS) - Result = RHS; - else - Result = LHS; + if (IsNumBuiltin) { + Result = llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat()); + } else { + // When comparing zeroes, return -0.0 if one of the zeroes is negative. + if (LHS.isZero() && RHS.isZero() && RHS.isNegative()) + Result = RHS; + else if (LHS.isNan() || RHS < LHS) + Result = RHS; + else + Result = LHS; + } S.Stk.push(Result); return true; } static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, - const InterpFrame *Frame, - const Function *Func) { + const InterpFrame *Frame, const Function *Func, + bool IsNumBuiltin) { const Floating &LHS = getParam(Frame, 0); const Floating &RHS = getParam(Frame, 1); Floating Result; - // When comparing zeroes, return +0.0 if one of the zeroes is positive. - if (LHS.isZero() && RHS.isZero() && LHS.isNegative()) - Result = RHS; - else if (LHS.isNan() || RHS > LHS) - Result = RHS; - else - Result = LHS; + if (IsNumBuiltin) { + Result = llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat()); + } else { + // When comparing zeroes, return +0.0 if one of the zeroes is positive. + if (LHS.isZero() && RHS.isZero() && LHS.isNegative()) + Result = RHS; + else if (LHS.isNan() || RHS > LHS) + Result = RHS; + else + Result = LHS; + } S.Stk.push(Result); return true; @@ -1162,6 +1170,71 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, return false; } +/// __builtin_assume_aligned(Ptr, Alignment[, ExtraOffset]) +static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + assert(Call->getNumArgs() == 2 || Call->getNumArgs() == 3); + + // Might be called with function pointers in C. + std::optional PtrT = S.Ctx.classify(Call->getArg(0)); + if (PtrT != PT_Ptr) + return false; + + unsigned ArgSize = callArgSize(S, Call); + const Pointer &Ptr = S.Stk.peek(ArgSize); + std::optional ExtraOffset; + APSInt Alignment; + if (Call->getNumArgs() == 2) { + Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1))); + } else { + PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1)); + PrimType ExtraOffsetT = *S.Ctx.classify(Call->getArg(2)); + Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)), + align(primSize(AlignmentT)) + + align(primSize(ExtraOffsetT))); + ExtraOffset = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2))); + } + + CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue()); + + // If there is a base object, then it must have the correct alignment. + if (Ptr.isBlockPointer()) { + CharUnits BaseAlignment; + if (const auto *VD = Ptr.getDeclDesc()->asValueDecl()) + BaseAlignment = S.getASTContext().getDeclAlign(VD); + else if (const auto *E = Ptr.getDeclDesc()->asExpr()) + BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf); + + if (BaseAlignment < Align) { + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 0 << BaseAlignment.getQuantity() << Align.getQuantity(); + return false; + } + } + + APValue AV = Ptr.toAPValue(S.getASTContext()); + CharUnits AVOffset = AV.getLValueOffset(); + if (ExtraOffset) + AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue()); + if (AVOffset.alignTo(Align) != AVOffset) { + if (Ptr.isBlockPointer()) + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 1 << AVOffset.getQuantity() << Align.getQuantity(); + else + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_value_insufficient_alignment) + << AVOffset.getQuantity() << Align.getQuantity(); + return false; + } + + S.Stk.push(Ptr); + return true; +} + static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, @@ -1637,7 +1710,16 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_fminl: case Builtin::BI__builtin_fminf16: case Builtin::BI__builtin_fminf128: - if (!interp__builtin_fmin(S, OpPC, Frame, F)) + if (!interp__builtin_fmin(S, OpPC, Frame, F, /*IsNumBuiltin=*/false)) + return false; + break; + + case Builtin::BI__builtin_fminimum_num: + case Builtin::BI__builtin_fminimum_numf: + case Builtin::BI__builtin_fminimum_numl: + case Builtin::BI__builtin_fminimum_numf16: + case Builtin::BI__builtin_fminimum_numf128: + if (!interp__builtin_fmin(S, OpPC, Frame, F, /*IsNumBuiltin=*/true)) return false; break; @@ -1646,7 +1728,16 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_fmaxl: case Builtin::BI__builtin_fmaxf16: case Builtin::BI__builtin_fmaxf128: - if (!interp__builtin_fmax(S, OpPC, Frame, F)) + if (!interp__builtin_fmax(S, OpPC, Frame, F, /*IsNumBuiltin=*/false)) + return false; + break; + + case Builtin::BI__builtin_fmaximum_num: + case Builtin::BI__builtin_fmaximum_numf: + case Builtin::BI__builtin_fmaximum_numl: + case Builtin::BI__builtin_fmaximum_numf16: + case Builtin::BI__builtin_fmaximum_numf128: + if (!interp__builtin_fmax(S, OpPC, Frame, F, /*IsNumBuiltin=*/true)) return false; break; @@ -1905,6 +1996,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_assume_aligned: + if (!interp__builtin_assume_aligned(S, OpPC, Frame, F, Call)) + return false; + break; + case clang::X86::BI__builtin_ia32_bextr_u32: case clang::X86::BI__builtin_ia32_bextr_u64: case clang::X86::BI__builtin_ia32_bextri_u32: diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 23245a66b578ae45696975a4ffdf0c3892ff122d..cd2665f755d7cbaf9c3e84240760c3345e4e66df 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -33,7 +33,7 @@ const void *Program::getNativePointer(unsigned Idx) { return NativePointers[Idx]; } -unsigned Program::createGlobalString(const StringLiteral *S) { +unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { const size_t CharWidth = S->getCharByteWidth(); const size_t BitWidth = CharWidth * Ctx.getCharBit(); @@ -52,12 +52,15 @@ unsigned Program::createGlobalString(const StringLiteral *S) { llvm_unreachable("unsupported character width"); } + if (!Base) + Base = S; + // Create a descriptor for the string. - Descriptor *Desc = - allocateDescriptor(S, CharType, Descriptor::GlobalMD, S->getLength() + 1, - /*isConst=*/true, - /*isTemporary=*/false, - /*isMutable=*/false); + Descriptor *Desc = allocateDescriptor(Base, CharType, Descriptor::GlobalMD, + S->getLength() + 1, + /*isConst=*/true, + /*isTemporary=*/false, + /*isMutable=*/false); // Allocate storage for the string. // The byte length does not include the null terminator. diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index be84c40714a60bca8479938134bfb5ea741a6ed2..f676672fb7ced5a6824dd8ca80db72b53057f5cb 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -64,7 +64,8 @@ public: const void *getNativePointer(unsigned Idx); /// Emits a string literal among global data. - unsigned createGlobalString(const StringLiteral *S); + unsigned createGlobalString(const StringLiteral *S, + const Expr *Base = nullptr); /// Returns a pointer to a global. Pointer getPtrGlobal(unsigned Idx) const; diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 8c79df8317a2ec18d0bf2a6e85fba1bb62078c57..e37ebec0851951087f1e960ad1739102ecb0e2a1 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -252,10 +252,13 @@ ExprDependence clang::computeDependence(ExtVectorElementExpr *E) { return E->getBase()->getDependence(); } -ExprDependence clang::computeDependence(BlockExpr *E) { +ExprDependence clang::computeDependence(BlockExpr *E, + bool ContainsUnexpandedParameterPack) { auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (E->getBlockDecl()->isDependentContext()) D |= ExprDependence::Instantiation; + if (ContainsUnexpandedParameterPack) + D |= ExprDependence::UnexpandedPack; return D; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index a70a5efb8ca01fef1fb90b4381978236eed9ae9f..8affa7cf619f9fcc07b89d2242e9e5a791be887a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1737,9 +1737,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, continue; // Suppress inline namespace if it doesn't make the result ambiguous. - if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope && - cast(Ctx)->isRedundantInlineQualifierFor(NameInScope)) - continue; + if (Ctx->isInlineNamespace() && NameInScope) { + bool isRedundant = + cast(Ctx)->isRedundantInlineQualifierFor(NameInScope); + if (P.SuppressInlineNamespace == + PrintingPolicy::SuppressInlineNamespaceMode::All || + (P.SuppressInlineNamespace == + PrintingPolicy::SuppressInlineNamespaceMode::Redundant && + isRedundant)) { + continue; + } + } // Skip non-named contexts such as linkage specifications and ExportDecls. const NamedDecl *ND = dyn_cast(Ctx); @@ -2696,21 +2704,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { auto From = VDTemplSpec->getInstantiatedFrom(); if (auto *VTD = From.dyn_cast()) { - while (!VTD->isMemberSpecialization()) { - auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); - if (!NewVTD) + while (!VTD->hasMemberSpecialization()) { + if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) + VTD = NewVTD; + else break; - VTD = NewVTD; } return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (auto *VTPSD = From.dyn_cast()) { - while (!VTPSD->isMemberSpecialization()) { - auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); - if (!NewVTPSD) + while (!VTPSD->hasMemberSpecialization()) { + if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) + VTPSD = NewVTPSD; + else break; - VTPSD = NewVTPSD; } return getDefinitionOrSelf(VTPSD); } @@ -2719,15 +2727,14 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { // If this is the pattern of a variable template, find where it was // instantiated from. FIXME: Is this necessary? - if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) { - while (!VarTemplate->isMemberSpecialization()) { - auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); - if (!NewVT) + if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) { + while (!VTD->hasMemberSpecialization()) { + if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) + VTD = NewVTD; + else break; - VarTemplate = NewVT; } - - return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); + return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (VD == this) @@ -4142,11 +4149,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const { if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { // If we hit a point where the user provided a specialization of this // template, we're done looking. - while (!ForDefinition || !Primary->isMemberSpecialization()) { - auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); - if (!NewPrimary) + while (!ForDefinition || !Primary->hasMemberSpecialization()) { + if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate()) + Primary = NewPrimary; + else break; - Primary = NewPrimary; } return getDefinitionOrSelf(Primary->getTemplatedDecl()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1364ccc745ba01627b8c87e8125529aca11a0244..407ec14bbc00d554048f3b4880247b37c6308032 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2023,19 +2023,21 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { - if (NewCTD->isMemberSpecialization()) + while (!CTD->hasMemberSpecialization()) { + if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) + CTD = NewCTD; + else break; - CTD = NewCTD; } return GetDefinitionOrSelf(CTD->getTemplatedDecl()); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { - if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->hasMemberSpecialization()) { + if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) + CTPSD = NewCTPSD; + else break; - CTPSD = NewCTPSD; } return GetDefinitionOrSelf(CTPSD); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 6fe817c5ef1c6b44b33465fc607c7b3466386529..d9b67b7bedf5a5d9a800ffbc4752b0d47e877da9 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/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h index efe8ee986d29b3da7915bae6c320889b14c5fd47..401ae629c86bfdedef4fa3be1860313c29d84fdd 100644 --- a/clang/lib/AST/ExprConstShared.h +++ b/clang/lib/AST/ExprConstShared.h @@ -14,12 +14,17 @@ #ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H #define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H +#include "clang/Basic/TypeTraits.h" + namespace llvm { class APFloat; } namespace clang { class QualType; class LangOptions; +class ASTContext; +class CharUnits; +class Expr; } // namespace clang using namespace clang; /// Values returned by __builtin_classify_type, chosen to match the values @@ -66,4 +71,7 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C, llvm::APFloat D, llvm::APFloat &ResR, llvm::APFloat &ResI); +CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, + UnaryExprOrTypeTrait ExprKind); + #endif diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4d5af96093cfeb684f3fb61535de239e5a7d4299..51956c631786b533c7ca87c9a4aa01cafbebdf7e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9620,7 +9620,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { return ExprEvaluatorBaseTy::VisitCastExpr(E); } -static CharUnits GetAlignOfType(EvalInfo &Info, QualType T, +static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T, UnaryExprOrTypeTrait ExprKind) { // C++ [expr.alignof]p3: // When alignof is applied to a reference type, the result is the @@ -9631,23 +9631,22 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T, return CharUnits::One(); const bool AlignOfReturnsPreferred = - Info.Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7; + Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7; // __alignof is defined to return the preferred alignment. // Before 8, clang returned the preferred alignment for alignof and _Alignof // as well. if (ExprKind == UETT_PreferredAlignOf || AlignOfReturnsPreferred) - return Info.Ctx.toCharUnitsFromBits( - Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); + return Ctx.toCharUnitsFromBits(Ctx.getPreferredTypeAlign(T.getTypePtr())); // alignof and _Alignof are defined to return the ABI alignment. else if (ExprKind == UETT_AlignOf) - return Info.Ctx.getTypeAlignInChars(T.getTypePtr()); + return Ctx.getTypeAlignInChars(T.getTypePtr()); else llvm_unreachable("GetAlignOfType on a non-alignment ExprKind"); } -static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E, - UnaryExprOrTypeTrait ExprKind) { +CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, + UnaryExprOrTypeTrait ExprKind) { E = E->IgnoreParens(); // The kinds of expressions that we have special-case logic here for @@ -9657,22 +9656,22 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E, // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast(E)) - return Info.Ctx.getDeclAlign(DRE->getDecl(), - /*RefAsPointee*/true); + return Ctx.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/ true); if (const MemberExpr *ME = dyn_cast(E)) - return Info.Ctx.getDeclAlign(ME->getMemberDecl(), - /*RefAsPointee*/true); + return Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/ true); - return GetAlignOfType(Info, E->getType(), ExprKind); + return GetAlignOfType(Ctx, E->getType(), ExprKind); } static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) { if (const auto *VD = Value.Base.dyn_cast()) return Info.Ctx.getDeclAlign(VD); if (const auto *E = Value.Base.dyn_cast()) - return GetAlignOfExpr(Info, E, UETT_AlignOf); - return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf); + return GetAlignOfExpr(Info.Ctx, E, UETT_AlignOf); + return GetAlignOfType(Info.Ctx, Value.Base.getTypeInfoType(), UETT_AlignOf); } /// Evaluate the value of the alignment argument to __builtin_align_{up,down}, @@ -9768,11 +9767,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (BaseAlignment < Align) { Result.Designator.setInvalid(); - // FIXME: Add support to Diagnostic for long / long long. - CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 0 - << (unsigned)BaseAlignment.getQuantity() - << (unsigned)Align.getQuantity(); + CCEDiag(E->getArg(0), diag::note_constexpr_baa_insufficient_alignment) + << 0 << BaseAlignment.getQuantity() << Align.getQuantity(); return false; } } @@ -9783,11 +9779,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, (OffsetResult.Base ? CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 1 + diag::note_constexpr_baa_insufficient_alignment) + << 1 : CCEDiag(E->getArg(0), diag::note_constexpr_baa_value_insufficient_alignment)) - << (int)OffsetResult.Offset.getQuantity() - << (unsigned)Align.getQuantity(); + << OffsetResult.Offset.getQuantity() << Align.getQuantity(); return false; } @@ -14478,11 +14474,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( case UETT_PreferredAlignOf: case UETT_AlignOf: { if (E->isArgumentType()) - return Success(GetAlignOfType(Info, E->getArgumentType(), E->getKind()), - E); + return Success( + GetAlignOfType(Info.Ctx, E->getArgumentType(), E->getKind()), E); else - return Success(GetAlignOfExpr(Info, E->getArgumentExpr(), E->getKind()), - E); + return Success( + GetAlignOfExpr(Info.Ctx, E->getArgumentExpr(), E->getKind()), E); } case UETT_PtrAuthTypeDiscriminator: { @@ -15314,6 +15310,32 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result = RHS; return true; } + + case Builtin::BI__builtin_fmaximum_num: + case Builtin::BI__builtin_fmaximum_numf: + case Builtin::BI__builtin_fmaximum_numl: + case Builtin::BI__builtin_fmaximum_numf16: + case Builtin::BI__builtin_fmaximum_numf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + Result = maximumnum(Result, RHS); + return true; + } + + case Builtin::BI__builtin_fminimum_num: + case Builtin::BI__builtin_fminimum_numf: + case Builtin::BI__builtin_fminimum_numl: + case Builtin::BI__builtin_fminimum_numf16: + case Builtin::BI__builtin_fminimum_numf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + Result = minimumnum(Result, RHS); + return true; + } } } diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp index 2ed0ce1c79c5bd37de6097d02178a3487e49ff58..1dafed837a35603f55f12a7572ae6a336bbba39b 100644 --- a/clang/lib/AST/InheritViz.cpp +++ b/clang/lib/AST/InheritViz.cpp @@ -63,12 +63,11 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); if (FromVirtual) { - if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end()) + if (!KnownVirtualBases.insert(CanonType).second) return; // We haven't seen this virtual base before, so display it and // its bases. - KnownVirtualBases.insert(CanonType); } // Declare the node itself. diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 0b34ed6189593e8d29b2335efdaaf955f587f943..638252fd811f1de33758c4724e498ac577be0ff4 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -26,7 +26,7 @@ bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) { return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) || OpenACCTileClause::classof(C) || OpenACCClauseWithSingleIntExpr::classof(C) || - OpenACCClauseWithVarList::classof(C); + OpenACCGangClause::classof(C) || OpenACCClauseWithVarList::classof(C); } bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) { return OpenACCPrivateClause::classof(C) || @@ -44,7 +44,8 @@ bool OpenACCClauseWithCondition::classof(const OpenACCClause *C) { bool OpenACCClauseWithSingleIntExpr::classof(const OpenACCClause *C) { return OpenACCNumWorkersClause::classof(C) || OpenACCVectorLengthClause::classof(C) || - OpenACCCollapseClause::classof(C) || OpenACCAsyncClause::classof(C); + OpenACCWorkerClause::classof(C) || OpenACCCollapseClause::classof(C) || + OpenACCAsyncClause::classof(C); } OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C, OpenACCDefaultClauseKind K, @@ -125,6 +126,21 @@ OpenACCNumWorkersClause::OpenACCNumWorkersClause(SourceLocation BeginLoc, "Condition expression type not scalar/dependent"); } +OpenACCGangClause::OpenACCGangClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef GangKinds, + ArrayRef IntExprs, + SourceLocation EndLoc) + : OpenACCClauseWithExprs(OpenACCClauseKind::Gang, BeginLoc, LParenLoc, + EndLoc) { + assert(GangKinds.size() == IntExprs.size() && "Mismatch exprs/kind?"); + std::uninitialized_copy(IntExprs.begin(), IntExprs.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), IntExprs.size())); + std::uninitialized_copy(GangKinds.begin(), GangKinds.end(), + getTrailingObjects()); +} + OpenACCNumWorkersClause * OpenACCNumWorkersClause::Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, @@ -376,18 +392,36 @@ OpenACCSeqClause *OpenACCSeqClause::Create(const ASTContext &C, return new (Mem) OpenACCSeqClause(BeginLoc, EndLoc); } -OpenACCGangClause *OpenACCGangClause::Create(const ASTContext &C, - SourceLocation BeginLoc, - SourceLocation EndLoc) { - void *Mem = C.Allocate(sizeof(OpenACCGangClause)); - return new (Mem) OpenACCGangClause(BeginLoc, EndLoc); +OpenACCGangClause * +OpenACCGangClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef GangKinds, + ArrayRef IntExprs, SourceLocation EndLoc) { + void *Mem = + C.Allocate(OpenACCGangClause::totalSizeToAlloc( + IntExprs.size(), GangKinds.size())); + return new (Mem) + OpenACCGangClause(BeginLoc, LParenLoc, GangKinds, IntExprs, EndLoc); +} + +OpenACCWorkerClause::OpenACCWorkerClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + Expr *IntExpr, SourceLocation EndLoc) + : OpenACCClauseWithSingleIntExpr(OpenACCClauseKind::Worker, BeginLoc, + LParenLoc, IntExpr, EndLoc) { + assert((!IntExpr || IntExpr->isInstantiationDependent() || + IntExpr->getType()->isIntegerType()) && + "Int expression type not scalar/dependent"); } OpenACCWorkerClause *OpenACCWorkerClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, + Expr *IntExpr, SourceLocation EndLoc) { - void *Mem = C.Allocate(sizeof(OpenACCWorkerClause)); - return new (Mem) OpenACCWorkerClause(BeginLoc, EndLoc); + void *Mem = + C.Allocate(sizeof(OpenACCWorkerClause), alignof(OpenACCWorkerClause)); + return new (Mem) OpenACCWorkerClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } OpenACCVectorClause *OpenACCVectorClause::Create(const ASTContext &C, @@ -600,3 +634,31 @@ void OpenACCClausePrinter::VisitCollapseClause(const OpenACCCollapseClause &C) { printExpr(C.getLoopCount()); OS << ")"; } + +void OpenACCClausePrinter::VisitGangClause(const OpenACCGangClause &C) { + OS << "gang"; + + if (C.getNumExprs() > 0) { + OS << "("; + bool first = true; + for (unsigned I = 0; I < C.getNumExprs(); ++I) { + if (!first) + OS << ", "; + first = false; + + OS << C.getExpr(I).first << ": "; + printExpr(C.getExpr(I).second); + } + OS << ")"; + } +} + +void OpenACCClausePrinter::VisitWorkerClause(const OpenACCWorkerClause &C) { + OS << "worker"; + + if (C.hasIntExpr()) { + OS << "(num: "; + printExpr(C.getIntExpr()); + OS << ")"; + } +} diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index ce9157f3003130559f926d53c7ca73a8eedc4174..ae36c27342b35085d63968754be392d1c5d6b2df 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2700,6 +2700,12 @@ void OpenACCClauseProfiler::VisitAsyncClause(const OpenACCAsyncClause &Clause) { Profiler.VisitStmt(Clause.getIntExpr()); } +void OpenACCClauseProfiler::VisitWorkerClause( + const OpenACCWorkerClause &Clause) { + if (Clause.hasIntExpr()) + Profiler.VisitStmt(Clause.getIntExpr()); +} + void OpenACCClauseProfiler::VisitWaitClause(const OpenACCWaitClause &Clause) { if (Clause.hasDevNumExpr()) Profiler.VisitStmt(Clause.getDevNumExpr()); @@ -2717,6 +2723,12 @@ void OpenACCClauseProfiler::VisitIndependentClause( void OpenACCClauseProfiler::VisitSeqClause(const OpenACCSeqClause &Clause) {} +void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) { + for (unsigned I = 0; I < Clause.getNumExprs(); ++I) { + Profiler.VisitStmt(Clause.getExpr(I).second); + } +} + void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { for (auto *E : Clause.getVarList()) diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 1f307d087431e388fccb7c3566c8ff897bbc6511..57d420f87ef31d8fd10f2ce08fded6b27fb46169 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -420,11 +420,23 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::Self: case OpenACCClauseKind::Seq: case OpenACCClauseKind::Tile: + case OpenACCClauseKind::Worker: case OpenACCClauseKind::VectorLength: // The condition expression will be printed as a part of the 'children', // but print 'clause' here so it is clear what is happening from the dump. OS << " clause"; break; + case OpenACCClauseKind::Gang: { + OS << " clause"; + // print the list of all GangKinds, so that there is some sort of + // relationship to the expressions listed afterwards. + auto *GC = cast(C); + + for (unsigned I = 0; I < GC->getNumExprs(); ++I) { + OS << " " << GC->getExpr(I).first; + } + break; + } case OpenACCClauseKind::Collapse: OS << " clause"; if (cast(C)->hasForce()) diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index b3e811b007e96e5487994c4ca0aa7c3b060f6ba7..164b5dcf615b85ad6d8acaac022bf95fdbf4c204 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1462,7 +1462,9 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, // Only suppress an inline namespace if the name has the same lookup // results in the enclosing namespace. - if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope && + if (Policy.SuppressInlineNamespace != + PrintingPolicy::SuppressInlineNamespaceMode::None && + NS->isInline() && NameInScope && NS->isRedundantInlineQualifierFor(NameInScope)) return AppendScope(DC->getParent(), OS, NameInScope); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 06309d327896b312ea21df40896ce9d762ec85ca..46dd44e6f2b24f4ffb33c606dffd9fb0b60580c4 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -655,7 +655,9 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy(); Policy.SuppressUnwrittenScope = SkipUnwritten; - Policy.SuppressInlineNamespace = SkipUnwritten; + Policy.SuppressInlineNamespace = + SkipUnwritten ? PrintingPolicy::SuppressInlineNamespaceMode::All + : PrintingPolicy::SuppressInlineNamespaceMode::None; Node.printQualifiedName(OS, Policy); const StringRef FullName = OS.str(); diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index faf3878f064d20d70c7f2b7f1671f2690bc26f67..08989b6c2c03f98582993405e8fd48f91748eac8 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -43,6 +43,7 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = { CUDA_ENTRY(12, 3), CUDA_ENTRY(12, 4), CUDA_ENTRY(12, 5), + CUDA_ENTRY(12, 6), {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits::max())}, {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. }; @@ -96,6 +97,7 @@ static const OffloadArchToStringMap arch_names[] = { SM(89), // Ada Lovelace SM(90), // Hopper SM(90a), // Hopper + SM(100), // Blackwell GFX(600), // gfx600 GFX(601), // gfx601 GFX(602), // gfx602 @@ -221,6 +223,9 @@ CudaVersion MinVersionForOffloadArch(OffloadArch A) { return CudaVersion::CUDA_118; case OffloadArch::SM_90a: return CudaVersion::CUDA_120; + case OffloadArch::SM_100: + return CudaVersion::NEW; // TODO: use specific CUDA version once it's + // public. default: llvm_unreachable("invalid enum"); } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index a9500a15c16ac4b0d82b6b27d566e5510d202d82..5c8ff377067801a82069504460d930c1dc19109e 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -409,6 +409,9 @@ ReservedLiteralSuffixIdStatus IdentifierInfo::isReservedLiteralSuffixId() const { StringRef Name = getName(); + // Note: the diag::warn_deprecated_literal_operator_id diagnostic depends on + // this being the first check we do, so if this order changes, we have to fix + // that as well. if (Name[0] != '_') return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore; diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index c56b8d9a4485086fdbeafc72a08b0891ce6dd4f7..c87300bf2d60e0407851c395ef294baae1d476a5 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -313,7 +313,9 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, switch (Triple.getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIT64: case llvm::Triple::GNUEABIHF: + case llvm::Triple::GNUEABIHFT64: case llvm::Triple::MuslEABI: case llvm::Triple::MuslEABIHF: case llvm::Triple::OpenHOS: diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 43b653dc52ce0d78b135c28f100a83f0d09c6bea..88a0dbde52d52baa130b11e82f360068ef44fe00 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -281,6 +281,8 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case OffloadArch::SM_90: case OffloadArch::SM_90a: return "900"; + case OffloadArch::SM_100: + return "1000"; } llvm_unreachable("unhandled OffloadArch"); }(); diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index a83d6464e789d6fcae38b025079cfa260b14d391..75f53e96ce28f6c572a283929cb2ebb0443af5bf 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -337,6 +337,10 @@ protected: Builder.defineMacro("_GNU_SOURCE"); if (this->HasFloat128) Builder.defineMacro("__FLOAT128__"); + if (Triple.isTime64ABI()) { + Builder.defineMacro("_FILE_OFFSET_BITS", "64"); + Builder.defineMacro("_TIME_BITS", "64"); + } } public: diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 672b87d6b43e5b571b20d499829984633b29951f..d939b373b9982e948247e52313aef08658deb49b 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -102,7 +102,7 @@ bool RISCVTargetInfo::validateAsmConstraint( return true; case 'v': // A vector register. - if (Name[1] == 'r' || Name[1] == 'm') { + if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') { Info.setAllowsRegister(); Name += 1; return true; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index db50913c753af5598a2f934affb6096f422fb1a8..c67ee3c581963fcca78b707c00b13a3a15ee17d7 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2871,6 +2871,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Intrinsic::minnum, Intrinsic::experimental_constrained_minnum)); + case Builtin::BIfmaximum_num: + case Builtin::BIfmaximum_numf: + case Builtin::BIfmaximum_numl: + case Builtin::BI__builtin_fmaximum_num: + case Builtin::BI__builtin_fmaximum_numf: + case Builtin::BI__builtin_fmaximum_numf16: + case Builtin::BI__builtin_fmaximum_numl: + case Builtin::BI__builtin_fmaximum_numf128: + return RValue::get( + emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::maximumnum)); + + case Builtin::BIfminimum_num: + case Builtin::BIfminimum_numf: + case Builtin::BIfminimum_numl: + case Builtin::BI__builtin_fminimum_num: + case Builtin::BI__builtin_fminimum_numf: + case Builtin::BI__builtin_fminimum_numf16: + case Builtin::BI__builtin_fminimum_numl: + case Builtin::BI__builtin_fminimum_numf128: + return RValue::get( + emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::minimumnum)); + // fmod() is a special-case. It maps to the frem instruction rather than an // LLVM intrinsic. case Builtin::BIfmod: @@ -13650,7 +13672,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue()); // Built the IR for the preserve_field_info intrinsic. - llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration( + llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info, {FieldAddr->getType()}); return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind}); @@ -13672,10 +13694,10 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, llvm::Function *FnDecl; if (BuiltinID == BPF::BI__builtin_btf_type_id) - FnDecl = llvm::Intrinsic::getDeclaration( + FnDecl = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id, {}); else - FnDecl = llvm::Intrinsic::getDeclaration( + FnDecl = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_type_info, {}); CallInst *Fn = Builder.CreateCall(FnDecl, {SeqNumVal, FlagValue}); Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); @@ -13710,7 +13732,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue()); Value *SeqNumVal = ConstantInt::get(Int32Ty, BuiltinSeqNum++); - llvm::Function *IntrinsicFn = llvm::Intrinsic::getDeclaration( + llvm::Function *IntrinsicFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_enum_value, {}); CallInst *Fn = Builder.CreateCall(IntrinsicFn, {SeqNumVal, EnumStrVal, FlagValue}); @@ -18884,7 +18906,7 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { // for the DirectX intrinsic and the demangled builtin name switch (CGM.getTarget().getTriple().getArch()) { case llvm::Triple::dxil: - return EmitRuntimeCall(Intrinsic::getDeclaration( + return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration( &CGM.getModule(), Intrinsic::dx_wave_getlaneindex)); case llvm::Triple::spirv: return EmitRuntimeCall(CGM.CreateRuntimeFunction( @@ -18897,7 +18919,8 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { } case Builtin::BI__builtin_hlsl_wave_is_first_lane: { Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic(); - return EmitRuntimeCall(Intrinsic::getDeclaration(&CGM.getModule(), ID)); + return EmitRuntimeCall( + Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID)); } case Builtin::BI__builtin_hlsl_elementwise_sign: { auto *Arg0 = E->getArg(0); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 609957b75d6e7e2ae56e9771d43dbe180ef612f7..06015a9e541ea24a03db0f19bb1419bf5c079b2d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -287,7 +287,8 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.SplitTemplateClosers = true; } - PP.SuppressInlineNamespace = false; + PP.SuppressInlineNamespace = + PrintingPolicy::SuppressInlineNamespaceMode::None; PP.PrintCanonicalTypes = true; PP.UsePreferredNames = false; PP.AlwaysIncludeTypeForTemplateArgument = true; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 563f728e29d78194cff8661e46299afce0d0ce01..1d0660292cecc1e40279ffe01377048afc27b19c 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1945,7 +1945,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { replaceUndef(CGM, isPattern, constant)); } - if (D.getType()->isBitIntType() && + if (constant && D.getType()->isBitIntType() && CGM.getTypes().typeRequiresSplitIntoByteArray(D.getType())) { // Constants for long _BitInt types are split into individual bytes. // Try to fold these back into an integer constant so it can be stored @@ -2509,8 +2509,8 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, llvm::Function *CodeGenModule::getLLVMLifetimeStartFn() { if (LifetimeStartFn) return LifetimeStartFn; - LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy); + LifetimeStartFn = llvm::Intrinsic::getOrInsertDeclaration( + &getModule(), llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy); return LifetimeStartFn; } @@ -2518,8 +2518,8 @@ llvm::Function *CodeGenModule::getLLVMLifetimeStartFn() { llvm::Function *CodeGenModule::getLLVMLifetimeEndFn() { if (LifetimeEndFn) return LifetimeEndFn; - LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy); + LifetimeEndFn = llvm::Intrinsic::getOrInsertDeclaration( + &getModule(), llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy); return LifetimeEndFn; } diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index bb2ed237ee9f35f4c3c5a41c69a52a958e7c513d..44a45413dbc45afdc39c0e9a197cbcbf71ee8ffa 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1843,7 +1843,7 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); int FrameEscapeIdx = InsertPair.first->second; // call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N) - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); RecoverCall = Builder.CreateCall( FrameRecoverFn, {ParentCGF.CurFn, ParentFP, @@ -1942,7 +1942,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, // %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..) // %2 = load ptr, ptr %1, align 8 // ==> %2 is the frame-pointer of outermost host function - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); ParentFP = Builder.CreateCall( FrameRecoverFn, {ParentCGF.CurFn, ParentFP, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index bb120917665b3f88a38a4e9fcb0dec166ffd0ae4..161dd7e4138a7621fbeed3c0444d58d4a21835b7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1528,7 +1528,12 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { /// LValue CodeGenFunction::EmitLValue(const Expr *E, KnownNonNull_t IsKnownNonNull) { - LValue LV = EmitLValueHelper(E, IsKnownNonNull); + // Running with sufficient stack space to avoid deeply nested expressions + // cause a stack overflow. + LValue LV; + CGM.runWithSufficientStackSpace( + E->getExprLoc(), [&] { LV = EmitLValueHelper(E, IsKnownNonNull); }); + if (IsKnownNonNull && !LV.isKnownNonNull()) LV.setKnownNonNull(); return LV; diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 3c680edc6000830c39294148d390d840b09aae4b..e998cd79198a5cbdb7c13d356ed721879c504a10 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -12,6 +12,7 @@ #include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -64,6 +65,9 @@ class AggExprEmitter : public StmtVisitor { void withReturnValueSlot(const Expr *E, llvm::function_ref Fn); + void DoZeroInitPadding(uint64_t &PaddingStart, uint64_t PaddingEnd, + const FieldDecl *NextField); + public: AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, bool IsResultUnused) : CGF(cgf), Builder(CGF.Builder), Dest(Dest), @@ -1698,6 +1702,9 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // Prepare a 'this' for CXXDefaultInitExprs. CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress()); + const bool ZeroInitPadding = + CGF.CGM.shouldZeroInitPadding() && !Dest.isZeroed(); + if (record->isUnion()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. @@ -1722,16 +1729,27 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( if (NumInitElements) { // Store the initializer into the field EmitInitializationToLValue(InitExprs[0], FieldLoc); + if (ZeroInitPadding) { + uint64_t TotalSize = CGF.getContext().toBits( + Dest.getPreferredSize(CGF.getContext(), DestLV.getType())); + uint64_t FieldSize = CGF.getContext().getTypeSize(FieldLoc.getType()); + DoZeroInitPadding(FieldSize, TotalSize, nullptr); + } } else { // Default-initialize to null. - EmitNullInitializationToLValue(FieldLoc); + if (ZeroInitPadding) + EmitNullInitializationToLValue(DestLV); + else + EmitNullInitializationToLValue(FieldLoc); } - return; } // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. + const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(record); + uint64_t PaddingStart = 0; + for (const auto *field : record->fields()) { // We're done once we hit the flexible array member. if (field->getType()->isIncompleteArrayType()) @@ -1748,6 +1766,9 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.getTypes().isZeroInitializable(ExprToVisit->getType())) break; + if (ZeroInitPadding) + DoZeroInitPadding(PaddingStart, + Layout.getFieldOffset(field->getFieldIndex()), field); LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field); // We never generate write-barries for initialized fields. @@ -1774,6 +1795,54 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( } } } + if (ZeroInitPadding) { + uint64_t TotalSize = CGF.getContext().toBits( + Dest.getPreferredSize(CGF.getContext(), DestLV.getType())); + DoZeroInitPadding(PaddingStart, TotalSize, nullptr); + } +} + +void AggExprEmitter::DoZeroInitPadding(uint64_t &PaddingStart, + uint64_t PaddingEnd, + const FieldDecl *NextField) { + + auto InitBytes = [&](uint64_t StartBit, uint64_t EndBit) { + CharUnits Start = CGF.getContext().toCharUnitsFromBits(StartBit); + CharUnits End = CGF.getContext().toCharUnitsFromBits(EndBit); + Address Addr = Dest.getAddress().withElementType(CGF.CharTy); + if (!Start.isZero()) + Addr = Builder.CreateConstGEP(Addr, Start.getQuantity()); + llvm::Constant *SizeVal = Builder.getInt64((End - Start).getQuantity()); + CGF.Builder.CreateMemSet(Addr, Builder.getInt8(0), SizeVal, false); + }; + + if (NextField != nullptr && NextField->isBitField()) { + // For bitfield, zero init StorageSize before storing the bits. So we don't + // need to handle big/little endian. + const CGRecordLayout &RL = + CGF.getTypes().getCGRecordLayout(NextField->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(NextField); + uint64_t StorageStart = CGF.getContext().toBits(Info.StorageOffset); + if (StorageStart + Info.StorageSize > PaddingStart) { + if (StorageStart > PaddingStart) + InitBytes(PaddingStart, StorageStart); + Address Addr = Dest.getAddress(); + if (!Info.StorageOffset.isZero()) + Addr = Builder.CreateConstGEP(Addr.withElementType(CGF.CharTy), + Info.StorageOffset.getQuantity()); + Addr = Addr.withElementType( + llvm::Type::getIntNTy(CGF.getLLVMContext(), Info.StorageSize)); + Builder.CreateStore(Builder.getIntN(Info.StorageSize, 0), Addr); + PaddingStart = StorageStart + Info.StorageSize; + } + return; + } + + if (PaddingStart < PaddingEnd) + InitBytes(PaddingStart, PaddingEnd); + if (NextField != nullptr) + PaddingStart = + PaddingEnd + CGF.getContext().getTypeSize(NextField->getType()); } void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index dd65080a8404467811f2026b4c078fde6e866ba3..655fc3dc954c8199da545ae8aae2c59efecf3bc8 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -42,6 +42,16 @@ using namespace CodeGen; namespace { class ConstExprEmitter; +llvm::Constant *getPadding(const CodeGenModule &CGM, CharUnits PadSize) { + llvm::Type *Ty = CGM.CharTy; + if (PadSize > CharUnits::One()) + Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity()); + if (CGM.shouldZeroInitPadding()) { + return llvm::Constant::getNullValue(Ty); + } + return llvm::UndefValue::get(Ty); +} + struct ConstantAggregateBuilderUtils { CodeGenModule &CGM; @@ -61,10 +71,7 @@ struct ConstantAggregateBuilderUtils { } llvm::Constant *getPadding(CharUnits PadSize) const { - llvm::Type *Ty = CGM.CharTy; - if (PadSize > CharUnits::One()) - Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity()); - return llvm::UndefValue::get(Ty); + return ::getPadding(CGM, PadSize); } llvm::Constant *getZeroes(CharUnits ZeroSize) const { @@ -591,6 +598,11 @@ private: bool Build(const InitListExpr *ILE, bool AllowOverwrite); bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase, const CXXRecordDecl *VTableClass, CharUnits BaseOffset); + bool DoZeroInitPadding(const ASTRecordLayout &Layout, unsigned FieldNo, + const FieldDecl &Field, bool AllowOverwrite, + CharUnits &SizeSoFar, bool &ZeroFieldSize); + bool DoZeroInitPadding(const ASTRecordLayout &Layout, bool AllowOverwrite, + CharUnits SizeSoFar); llvm::Constant *Finalize(QualType Ty); }; @@ -715,6 +727,10 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { if (CXXRD->getNumBases()) return false; + const bool ZeroInitPadding = CGM.shouldZeroInitPadding(); + bool ZeroFieldSize = false; + CharUnits SizeSoFar = CharUnits::Zero(); + for (FieldDecl *Field : RD->fields()) { ++FieldNo; @@ -732,8 +748,13 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { const Expr *Init = nullptr; if (ElementNo < ILE->getNumInits()) Init = ILE->getInit(ElementNo++); - if (isa_and_nonnull(Init)) + if (isa_and_nonnull(Init)) { + if (ZeroInitPadding && + !DoZeroInitPadding(Layout, FieldNo, *Field, AllowOverwrite, SizeSoFar, + ZeroFieldSize)) + return false; continue; + } // Zero-sized fields are not emitted, but their initializers may still // prevent emission of this struct as a constant. @@ -743,6 +764,11 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { continue; } + if (ZeroInitPadding && + !DoZeroInitPadding(Layout, FieldNo, *Field, AllowOverwrite, SizeSoFar, + ZeroFieldSize)) + return false; + // When emitting a DesignatedInitUpdateExpr, a nested InitListExpr // represents additional overwriting of our current constant value, and not // a new constant to emit independently. @@ -768,6 +794,10 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { if (!EltInit) return false; + if (ZeroInitPadding && ZeroFieldSize) + SizeSoFar += CharUnits::fromQuantity( + CGM.getDataLayout().getTypeAllocSize(EltInit->getType())); + if (!Field->isBitField()) { // Handle non-bitfield members. if (!AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit, @@ -785,6 +815,9 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { } } + if (ZeroInitPadding && !DoZeroInitPadding(Layout, AllowOverwrite, SizeSoFar)) + return false; + return true; } @@ -849,6 +882,9 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, unsigned FieldNo = 0; uint64_t OffsetBits = CGM.getContext().toBits(Offset); + const bool ZeroInitPadding = CGM.shouldZeroInitPadding(); + bool ZeroFieldSize = false; + CharUnits SizeSoFar = CharUnits::Zero(); bool AllowOverwrite = false; for (RecordDecl::field_iterator Field = RD->field_begin(), @@ -870,6 +906,15 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, if (!EltInit) return false; + if (ZeroInitPadding) { + if (!DoZeroInitPadding(Layout, FieldNo, **Field, AllowOverwrite, + SizeSoFar, ZeroFieldSize)) + return false; + if (ZeroFieldSize) + SizeSoFar += CharUnits::fromQuantity( + CGM.getDataLayout().getTypeAllocSize(EltInit->getType())); + } + if (!Field->isBitField()) { // Handle non-bitfield members. if (!AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits, @@ -886,7 +931,49 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, return false; } } + if (ZeroInitPadding && !DoZeroInitPadding(Layout, AllowOverwrite, SizeSoFar)) + return false; + + return true; +} + +bool ConstStructBuilder::DoZeroInitPadding( + const ASTRecordLayout &Layout, unsigned FieldNo, const FieldDecl &Field, + bool AllowOverwrite, CharUnits &SizeSoFar, bool &ZeroFieldSize) { + uint64_t StartBitOffset = Layout.getFieldOffset(FieldNo); + CharUnits StartOffset = CGM.getContext().toCharUnitsFromBits(StartBitOffset); + if (SizeSoFar < StartOffset) + if (!AppendBytes(SizeSoFar, getPadding(CGM, StartOffset - SizeSoFar), + AllowOverwrite)) + return false; + + if (!Field.isBitField()) { + CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field.getType()); + SizeSoFar = StartOffset + FieldSize; + ZeroFieldSize = FieldSize.isZero(); + } else { + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field.getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(&Field); + uint64_t EndBitOffset = StartBitOffset + Info.Size; + SizeSoFar = CGM.getContext().toCharUnitsFromBits(EndBitOffset); + if (EndBitOffset % CGM.getContext().getCharWidth() != 0) { + SizeSoFar++; + } + ZeroFieldSize = Info.Size == 0; + } + return true; +} +bool ConstStructBuilder::DoZeroInitPadding(const ASTRecordLayout &Layout, + bool AllowOverwrite, + CharUnits SizeSoFar) { + CharUnits TotalSize = Layout.getSize(); + if (SizeSoFar < TotalSize) + if (!AppendBytes(SizeSoFar, getPadding(CGM, TotalSize - SizeSoFar), + AllowOverwrite)) + return false; + SizeSoFar = TotalSize; return true; } @@ -1127,12 +1214,10 @@ public: assert(CurSize <= TotalSize && "Union size mismatch!"); if (unsigned NumPadBytes = TotalSize - CurSize) { - llvm::Type *Ty = CGM.CharTy; - if (NumPadBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumPadBytes); - - Elts.push_back(llvm::UndefValue::get(Ty)); - Types.push_back(Ty); + llvm::Constant *Padding = + getPadding(CGM, CharUnits::fromQuantity(NumPadBytes)); + Elts.push_back(Padding); + Types.push_back(Padding->getType()); } llvm::StructType *STy = llvm::StructType::get(VMContext, Types, false); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index bf3071c0d7e1bfd140071ab24fcfb15d966a4615..40129da1c01155e739ad50531b8fdcb707b2f46b 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1713,25 +1713,15 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition( if (!Ctor && !Dtor) return nullptr; - llvm::Type *CopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy}; - auto *CopyCtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CopyCtorTyArgs, - /*isVarArg=*/false) - ->getPointerTo(); // Copying constructor for the threadprivate variable. // Must be NULL - reserved by runtime, but currently it requires that this // parameter is always NULL. Otherwise it fires assertion. - CopyCtor = llvm::Constant::getNullValue(CopyCtorTy); + CopyCtor = llvm::Constant::getNullValue(CGM.UnqualPtrTy); if (Ctor == nullptr) { - auto *CtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy, - /*isVarArg=*/false) - ->getPointerTo(); - Ctor = llvm::Constant::getNullValue(CtorTy); + Ctor = llvm::Constant::getNullValue(CGM.UnqualPtrTy); } if (Dtor == nullptr) { - auto *DtorTy = llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy, - /*isVarArg=*/false) - ->getPointerTo(); - Dtor = llvm::Constant::getNullValue(DtorTy); + Dtor = llvm::Constant::getNullValue(CGM.UnqualPtrTy); } if (!CGF) { auto *InitFunctionTy = @@ -1817,7 +1807,7 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF, OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), OMPRTL___kmpc_threadprivate_cached), Args), - VarLVType->getPointerTo(/*AddrSpace=*/0)), + CGF.Builder.getPtrTy(0)), VarLVType, CGM.getContext().getTypeAlignInChars(VarType)); } @@ -2131,10 +2121,7 @@ static Address emitAddrOfVarFromArray(CodeGenFunction &CGF, Address Array, llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr); llvm::Type *ElemTy = CGF.ConvertTypeForMem(Var->getType()); - return Address( - CGF.Builder.CreateBitCast( - Ptr, ElemTy->getPointerTo(Ptr->getType()->getPointerAddressSpace())), - ElemTy, CGF.getContext().getDeclAlign(Var)); + return Address(Ptr, ElemTy, CGF.getContext().getDeclAlign(Var)); } static llvm::Value *emitCopyprivateCopyFunction( @@ -2166,11 +2153,11 @@ static llvm::Value *emitCopyprivateCopyFunction( // Src = (void*[n])(RHSArg); Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)), - ArgsElemType->getPointerTo()), + CGF.Builder.getPtrTy(0)), ArgsElemType, CGF.getPointerAlign()); Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)), - ArgsElemType->getPointerTo()), + CGF.Builder.getPtrTy(0)), ArgsElemType, CGF.getPointerAlign()); // *(Type0*)Dst[0] = *(Type0*)Src[0]; // *(Type1*)Dst[1] = *(Type1*)Src[1]; @@ -3681,9 +3668,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, QualType KmpTaskTWithPrivatesQTy = C.getRecordType(KmpTaskTWithPrivatesQTyRD); QualType KmpTaskTWithPrivatesPtrQTy = C.getPointerType(KmpTaskTWithPrivatesQTy); - llvm::Type *KmpTaskTWithPrivatesTy = CGF.ConvertType(KmpTaskTWithPrivatesQTy); - llvm::Type *KmpTaskTWithPrivatesPtrTy = - KmpTaskTWithPrivatesTy->getPointerTo(); + llvm::Type *KmpTaskTWithPrivatesPtrTy = CGF.Builder.getPtrTy(0); llvm::Value *KmpTaskTWithPrivatesTySize = CGF.getTypeSize(KmpTaskTWithPrivatesQTy); QualType SharedsPtrTy = C.getPointerType(SharedsTy); @@ -4402,7 +4387,7 @@ Address CGOpenMPRuntime::emitDepobjDependClause( Args, ".dep.arr.addr"); llvm::Type *KmpDependInfoLlvmTy = CGF.ConvertTypeForMem(KmpDependInfoTy); Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - Addr, KmpDependInfoLlvmTy->getPointerTo()); + Addr, CGF.Builder.getPtrTy(0)); DependenciesArray = Address(Addr, KmpDependInfoLlvmTy, Align); // Write number of elements in the first element of array for depobj. LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy); @@ -4844,11 +4829,11 @@ llvm::Function *CGOpenMPRuntime::emitReductionFunction( // Src = (void*[n])(RHSArg); Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)), - ArgsElemType->getPointerTo()), + CGF.Builder.getPtrTy(0)), ArgsElemType, CGF.getPointerAlign()); Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)), - ArgsElemType->getPointerTo()), + CGF.Builder.getPtrTy(0)), ArgsElemType, CGF.getPointerAlign()); // ... @@ -5280,8 +5265,7 @@ static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM, CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc); QualType PrivateType = RCG.getPrivateType(N); Address PrivateAddr = CGF.EmitLoadOfPointer( - CGF.GetAddrOfLocalVar(&Param).withElementType( - CGF.ConvertTypeForMem(PrivateType)->getPointerTo()), + CGF.GetAddrOfLocalVar(&Param).withElementType(CGF.Builder.getPtrTy(0)), C.getPointerType(PrivateType)->castAs()); llvm::Value *Size = nullptr; // If the size of the reduction item is non-constant, load it from global @@ -5369,15 +5353,14 @@ static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM, // Pull out the pointer to the variable. CGF.EmitLoadOfPointer( CGF.GetAddrOfLocalVar(&ParamInOut) - .withElementType( - CGF.ConvertTypeForMem(LHSVD->getType())->getPointerTo()), + .withElementType(CGF.Builder.getPtrTy(0)), C.getPointerType(LHSVD->getType())->castAs())); PrivateScope.addPrivate( RHSVD, // Pull out the pointer to the variable. CGF.EmitLoadOfPointer( CGF.GetAddrOfLocalVar(&ParamIn).withElementType( - CGF.ConvertTypeForMem(RHSVD->getType())->getPointerTo()), + CGF.Builder.getPtrTy(0)), C.getPointerType(RHSVD->getType())->castAs())); PrivateScope.Privatize(); // Emit the combiner body: diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index c920d93957b16ee41b55007ec13ca43dd7a0c085..35ff75416cb7761fb241119dd3fe00426ee1de79 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -2274,6 +2274,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(const OMPRequiresDecl *D) { case OffloadArch::SM_89: case OffloadArch::SM_90: case OffloadArch::SM_90a: + case OffloadArch::SM_100: case OffloadArch::GFX600: case OffloadArch::GFX601: case OffloadArch::GFX602: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index e1fd9b72b8d7b2d02d86023bd2b1b0c2df3faafe..f3023c7a20c4050f2a66740b5d747f23a705b48a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -463,7 +463,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EscapeArgs.resize(EscapedLocals.size()); for (auto &Pair : EscapedLocals) EscapeArgs[Pair.second] = Pair.first; - llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameEscapeFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localescape); CGBuilderTy(*this, AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); } @@ -3130,7 +3130,7 @@ void CodeGenFunction::emitAlignmentAssumptionCheck( llvm::Instruction *Assumption) { assert(isa_and_nonnull(Assumption) && cast(Assumption)->getCalledOperand() == - llvm::Intrinsic::getDeclaration( + llvm::Intrinsic::getOrInsertDeclaration( Builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::assume) && "Assumption should be a call to llvm.assume()."); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5ba098144a74e79f086ebc99fd9e65864a7dae79..b05ab3606a698ba37fdf26a91eabbd3ab388c8f1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -44,6 +44,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/CodeGen/BackendUtil.h" @@ -175,10 +176,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { else if (ABIStr == "aapcs16") Kind = ARMABIKind::AAPCS16_VFP; else if (CodeGenOpts.FloatABI == "hard" || - (CodeGenOpts.FloatABI != "soft" && - (Triple.getEnvironment() == llvm::Triple::GNUEABIHF || - Triple.getEnvironment() == llvm::Triple::MuslEABIHF || - Triple.getEnvironment() == llvm::Triple::EABIHF))) + (CodeGenOpts.FloatABI != "soft" && Triple.isHardFloatABI())) Kind = ARMABIKind::AAPCS_VFP; return createARMTargetCodeGenInfo(CGM, Kind); @@ -1596,6 +1594,19 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) { getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } +void CodeGenModule::warnStackExhausted(SourceLocation Loc) { + // Only warn about this once. + if (!WarnedStackExhausted) { + getDiags().Report(Loc, diag::warn_stack_exhausted); + WarnedStackExhausted = true; + } +} + +void CodeGenModule::runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref Fn) { + clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn); +} + llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { return llvm::ConstantInt::get(SizeTy, size.getQuantity()); } @@ -6218,8 +6229,8 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) { llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef Tys) { - return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, - Tys); + return llvm::Intrinsic::getOrInsertDeclaration(&getModule(), + (llvm::Intrinsic::ID)IID, Tys); } static llvm::StringMapEntry & diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index c58bb88035ca8ab3ef781e9350424aa8bf89fca1..fa82a81b05dd539c433c66bf369066152db7697f 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -336,6 +336,7 @@ private: std::unique_ptr PGOReader; InstrProfStats PGOStats; std::unique_ptr SanStats; + bool WarnedStackExhausted = false; // A set of references that have only been seen via a weakref so far. This is // used to remove the weak of the reference if we ever see a direct reference @@ -1297,6 +1298,16 @@ public: /// Print out an error that codegen doesn't support the specified decl yet. void ErrorUnsupported(const Decl *D, const char *Type); + /// Warn that the stack is nearly exhausted. + void warnStackExhausted(SourceLocation Loc); + + /// Run some code with "sufficient" stack space. (Currently, at least 256K is + /// guaranteed). Produces a warning if we're low on stack space and allocates + /// more in that case. Use this in code that may recurse deeply to avoid stack + /// overflow. + void runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref Fn); + /// Set the attributes on the LLVM function for the given decl and function /// info. This applies attributes necessary for handling the ABI as well as /// user specified attributes like section. @@ -1676,6 +1687,57 @@ public: MustTailCallUndefinedGlobals.insert(Global); } + bool shouldZeroInitPadding() const { + // In C23 (N3096) $6.7.10: + // """ + // If any object is initialized with an empty iniitializer, then it is + // subject to default initialization: + // - if it is an aggregate, every member is initialized (recursively) + // according to these rules, and any padding is initialized to zero bits; + // - if it is a union, the first named member is initialized (recursively) + // according to these rules, and any padding is initialized to zero bits. + // + // If the aggregate or union contains elements or members that are + // aggregates or unions, these rules apply recursively to the subaggregates + // or contained unions. + // + // If there are fewer initializers in a brace-enclosed list than there are + // elements or members of an aggregate, or fewer characters in a string + // literal used to initialize an array of known size than there are elements + // in the array, the remainder of the aggregate is subject to default + // initialization. + // """ + // + // From my understanding, the standard is ambiguous in the following two + // areas: + // 1. For a union type with empty initializer, if the first named member is + // not the largest member, then the bytes comes after the first named member + // but before padding are left unspecified. An example is: + // union U { int a; long long b;}; + // union U u = {}; // The first 4 bytes are 0, but 4-8 bytes are left + // unspecified. + // + // 2. It only mentions padding for empty initializer, but doesn't mention + // padding for a non empty initialization list. And if the aggregation or + // union contains elements or members that are aggregates or unions, and + // some are non empty initializers, while others are empty initiailizers, + // the padding initialization is unclear. An example is: + // struct S1 { int a; long long b; }; + // struct S2 { char c; struct S1 s1; }; + // // The values for paddings between s2.c and s2.s1.a, between s2.s1.a + // and s2.s1.b are unclear. + // struct S2 s2 = { 'c' }; + // + // Here we choose to zero initiailize left bytes of a union type. Because + // projects like the Linux kernel are relying on this behavior. If we don't + // explicitly zero initialize them, the undef values can be optimized to + // return gabage data. We also choose to zero initialize paddings for + // aggregates and unions, no matter they are initialized by empty + // initializers or non empty initializers. This can provide a consistent + // behavior. So projects like the Linux kernel can rely on it. + return !getLangOpts().CPlusPlus; + } + private: bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index c38198f7db6eb3ad26c1f6c39ea9f75a56338e49..82eb7234c98c7af0db3a1eca66960bb5d0a5c7af 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -60,7 +60,8 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, // example, we should probably enable PrintCanonicalTypes and // FullyQualifiedNames. PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy(); - Policy.SuppressInlineNamespace = false; + Policy.SuppressInlineNamespace = + PrintingPolicy::SuppressInlineNamespaceMode::None; // Name the codegen type after the typedef name // if there is no tag type name available diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index f7d7471d386b2116bd97bfc1f5a95dfc42e9dc35..49ac1a76e767aa0602e1b8eb61a6c94451223a41 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -35,7 +35,9 @@ public: case llvm::Triple::EABI: case llvm::Triple::EABIHF: case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIT64: case llvm::Triple::GNUEABIHF: + case llvm::Triple::GNUEABIHFT64: case llvm::Triple::MuslEABI: case llvm::Triple::MuslEABIHF: return true; @@ -48,6 +50,7 @@ public: switch (getTarget().getTriple().getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: + case llvm::Triple::GNUEABIHFT64: case llvm::Triple::MuslEABIHF: return true; default: diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp index 56129622f48dbde7e92a541bca3ae6135464b2e6..23c96fa5cf98cb3926f80c0de80f5aca4c04c7d9 100644 --- a/clang/lib/CodeGen/Targets/SystemZ.cpp +++ b/clang/lib/CodeGen/Targets/SystemZ.cpp @@ -110,8 +110,8 @@ public: if (Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isFP128Ty()) { llvm::Module &M = CGM.getModule(); auto &Ctx = M.getContext(); - llvm::Function *TDCFunc = - llvm::Intrinsic::getDeclaration(&M, llvm::Intrinsic::s390_tdc, Ty); + llvm::Function *TDCFunc = llvm::Intrinsic::getOrInsertDeclaration( + &M, llvm::Intrinsic::s390_tdc, Ty); unsigned TDCBits = 0; switch (BuiltinID) { case Builtin::BI__builtin_isnan: diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index a53f09e3033954c211c96cc7099820096ed1f5b2..883edf841128cf5bfdf4ed2fe49ac6eddb22c405 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -610,7 +610,8 @@ static llvm::Triple computeTargetTriple(const Driver &D, if (A->getOption().matches(options::OPT_m64) || A->getOption().matches(options::OPT_maix64)) { AT = Target.get64BitArchVariant().getArch(); - if (Target.getEnvironment() == llvm::Triple::GNUX32) + if (Target.getEnvironment() == llvm::Triple::GNUX32 || + Target.getEnvironment() == llvm::Triple::GNUT64) Target.setEnvironment(llvm::Triple::GNU); else if (Target.getEnvironment() == llvm::Triple::MuslX32) Target.setEnvironment(llvm::Triple::Musl); @@ -673,6 +674,7 @@ static llvm::Triple computeTargetTriple(const Driver &D, } else if (ABIName == "n32") { Target = Target.get64BitArchVariant(); if (Target.getEnvironment() == llvm::Triple::GNU || + Target.getEnvironment() == llvm::Triple::GNUT64 || Target.getEnvironment() == llvm::Triple::GNUABI64) Target.setEnvironment(llvm::Triple::GNUABIN32); else if (Target.getEnvironment() == llvm::Triple::Musl || @@ -681,6 +683,7 @@ static llvm::Triple computeTargetTriple(const Driver &D, } else if (ABIName == "64") { Target = Target.get64BitArchVariant(); if (Target.getEnvironment() == llvm::Triple::GNU || + Target.getEnvironment() == llvm::Triple::GNUT64 || Target.getEnvironment() == llvm::Triple::GNUABIN32) Target.setEnvironment(llvm::Triple::GNUABI64); else if (Target.getEnvironment() == llvm::Triple::Musl || diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index bb5c0e6db9978eb4aa05f4676efefd11641c9507..08e906ac9e80676c451019f6ae17b901144a8756 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -400,6 +400,14 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void AVRToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { + // Reject C/C++ compilation for avr1 devices since they have no SRAM. + const Driver &D = getDriver(); + std::string CPU = getCPUName(D, DriverArgs, getTriple()); + std::optional FamilyName = GetMCUFamilyName(CPU); + if (CPU == "avr1" || (FamilyName && *FamilyName == "avr1")) + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-mmcu=" + CPU << "c/c++"; + // By default, use `.ctors` (not `.init_array`), as required by libgcc, which // runs constructors/destructors on AVR. if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index a6041b809b80b6fc80e7c286b60dbb08cf3da11a..0489911ecd9deea5061701fff2ac7f2c2aa8fa25 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -327,6 +327,11 @@ void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHF : llvm::Triple::GNUEABI); break; + case llvm::Triple::GNUEABIT64: + case llvm::Triple::GNUEABIHFT64: + Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHFT64 + : llvm::Triple::GNUEABIT64); + break; case llvm::Triple::EABI: case llvm::Triple::EABIHF: Triple.setEnvironment(isHardFloat ? llvm::Triple::EABIHF @@ -414,10 +419,12 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { return FloatABI::Soft; switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: + case llvm::Triple::GNUEABIHFT64: case llvm::Triple::MuslEABIHF: case llvm::Triple::EABIHF: return FloatABI::Hard; case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIT64: case llvm::Triple::MuslEABI: case llvm::Triple::EABI: // EABI is always AAPCS, and if it was not marked 'hard', it's softfp diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 34d24b02e1423fa3339fc9b7509803489b802ec6..02b3453a4f6c7361d933814d645b54c99071a4cb 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -94,24 +94,6 @@ 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 @@ -7761,31 +7743,10 @@ 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 = - 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); + auto GRecordSwitches = false; + auto FRecordSwitches = false; + if (shouldRecordCommandLine(TC, Args, FRecordSwitches, GRecordSwitches)) { + auto FlagsArgString = renderEscapedCommandLine(TC, Args); if (TC.UseDwarfDebugFlags() || GRecordSwitches) { CmdArgs.push_back("-dwarf-debug-flags"); CmdArgs.push_back(FlagsArgString); @@ -8785,10 +8746,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 cb5577e06e3e01fea6d64d8343ffeac02301fd69..7841f8b7125236e13437aa3d334652b496de0c51 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -2994,3 +2994,62 @@ void tools::handleColorDiagnosticsArgs(const Driver &D, const ArgList &Args, if (D.getDiags().getDiagnosticOptions().ShowColors) CmdArgs.push_back("-fcolor-diagnostics"); } + +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 eff21b210b4244306a6236391383767001bec612..9cafac2538862ae82609b8b54027cc85e92ac951 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -237,6 +237,31 @@ void addMCModel(const Driver &D, const llvm::opt::ArgList &Args, void handleColorDiagnosticsArgs(const Driver &D, const llvm::opt::ArgList &Args, 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/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 7a70cf1c5694fd6eb5493540d4f12e45f98ee4fc..b368c473756731beb5e79df43cf8528c22faf7d6 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -87,6 +87,8 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_124; if (raw_version < 12060) return CudaVersion::CUDA_125; + if (raw_version < 12070) + return CudaVersion::CUDA_126; return CudaVersion::NEW; } @@ -669,6 +671,7 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(126, 85); CASE_CUDA_VERSION(125, 85); CASE_CUDA_VERSION(124, 84); CASE_CUDA_VERSION(123, 83); @@ -691,6 +694,10 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, CASE_CUDA_VERSION(91, 61); CASE_CUDA_VERSION(90, 60); #undef CASE_CUDA_VERSION + // TODO: Use specific CUDA version once it's public. + case clang::CudaVersion::NEW: + PtxFeature = "+ptx86"; + break; default: PtxFeature = "+ptx42"; } diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 19b43594b00815919c64d98296b7a67c500c39e3..e2f8f6e0cca1c6d4cdf5c4a85f11cabe14d7eb91 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -882,6 +882,20 @@ 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()); const char *Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index eea61cc42634ae7523f7e42e293fce7451e8f2b3..2410fb86b39a72c145e6c3e4799334ca3be3f0ae 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -671,7 +671,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddAllArgs(CmdArgs, options::OPT_T); + Args.addAllArgs(CmdArgs, {options::OPT_T, options::OPT_t}); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique(JA, *this, @@ -2703,6 +2703,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHFT64 || TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); @@ -2714,6 +2715,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHFT64 || TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index b3adfe65402ff350796d2c9a04bf369444061a6a..9fe4f1e0e20965df027c3bc430734dff4da872c4 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -340,21 +340,21 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, void HIP::constructGenerateObjFileFromHIPFatBinary( Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const JobAction &JA, const Tool &T) { - const ToolChain &TC = T.getToolChain(); + const Driver &D = C.getDriver(); std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); // Create Temp Object File Generator, // Offload Bundled file and Bundled Object file. // Keep them if save-temps is enabled. - const char *McinFile; + const char *ObjinFile; const char *BundleFile; - if (C.getDriver().isSaveTempsEnabled()) { - McinFile = C.getArgs().MakeArgString(Name + ".mcin"); + if (D.isSaveTempsEnabled()) { + ObjinFile = C.getArgs().MakeArgString(Name + ".mcin"); BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); } else { - auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); - McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); - auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); + auto TmpNameMcin = D.GetTemporaryPath(Name, "mcin"); + ObjinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); + auto TmpNameFb = D.GetTemporaryPath(Name, "hipfb"); BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); } HIP::constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, T); @@ -454,19 +454,20 @@ void HIP::constructGenerateObjFileFromHIPFatBinary( // Open script file and write the contents. std::error_code EC; - llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); + llvm::raw_fd_ostream Objf(ObjinFile, EC, llvm::sys::fs::OF_None); if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + D.Diag(clang::diag::err_unable_to_make_temp) << EC.message(); return; } Objf << ObjBuffer; - ArgStringList McArgs{"-triple", Args.MakeArgString(HostTriple.normalize()), + ArgStringList McArgs{"-target", Args.MakeArgString(HostTriple.normalize()), "-o", Output.getFilename(), - McinFile, "--filetype=obj"}; - const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); - C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), Mc, - McArgs, Inputs, Output)); + "-x", "assembler", + ObjinFile, "-c"}; + C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), + D.getClangProgramPath(), McArgs, + Inputs, Output, D.getPrependArg())); } diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index a1646fbb0c358b90b989f3b1313f800af47283f8..fa03236c0ce9253e8ba1e6bdd3c26bbde7715976 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -525,6 +525,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { case llvm::Triple::thumbeb: { const bool HF = Triple.getEnvironment() == llvm::Triple::GNUEABIHF || + Triple.getEnvironment() == llvm::Triple::GNUEABIHFT64 || tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard; LibDir = "lib"; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 9aec11e69fde1dbabd0592331a7077dd3036c92d..44a6894d30fb29be96f58db391e38689cf39fb4e 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -163,6 +163,8 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } + ToolChain.addProfileRTLibs(Args, CmdArgs); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 75304908dc65066b2017327f71544f99350819bf..bde77578769906a86ff341a13b17eb256111d481 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -420,7 +420,7 @@ BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. - if (CommentPragmasRegex.match(Content[LineIndex])) + if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); return getCommentSplit(Content[LineIndex].substr(TailOffset), ContentStartColumn, ColumnLimit, Style.TabWidth, @@ -608,7 +608,7 @@ BreakableToken::Split BreakableBlockComment::getSplit( unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. - if (CommentPragmasRegex.match(Content[LineIndex])) + if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); return getCommentSplit(Content[LineIndex].substr(TailOffset), ContentStartColumn, ColumnLimit, Style.TabWidth, @@ -855,7 +855,8 @@ bool BreakableBlockComment::mayReflow( StringRef IndentContent = Content[LineIndex]; if (Lines[LineIndex].ltrim(Blanks).starts_with("*")) IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1); - return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) && + return LineIndex > 0 && AlwaysReflow && + !CommentPragmasRegex.match(IndentContent) && mayReflowContent(Content[LineIndex]) && !Tok.Finalized && !switchesFormatting(tokenAt(LineIndex)); } @@ -1160,7 +1161,8 @@ bool BreakableLineCommentSection::mayReflow( // // text that protrudes // // into text with different indent // We do reflow in that case in block comments. - return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) && + return LineIndex > 0 && AlwaysReflow && + !CommentPragmasRegex.match(IndentContent) && mayReflowContent(Content[LineIndex]) && !Tok.Finalized && !switchesFormatting(tokenAt(LineIndex)) && OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1]; diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h index 8b9360a3335ef41965d5448793a358417d85f4df..45c00b35fd01ede5161e8d04d4ea291bf744e27d 100644 --- a/clang/lib/Format/BreakableToken.h +++ b/clang/lib/Format/BreakableToken.h @@ -384,6 +384,8 @@ protected: // The intended start column of the first line of text from this section. unsigned StartColumn; + const bool AlwaysReflow = Style.ReflowComments == FormatStyle::RCS_Always; + // The prefix to use in front a line that has been reflown up. // For example, when reflowing the second line after the first here: // // comment 1 diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 4df8dc89be459fc7c913c3638791da609489829e..fd53969e4b3b330fd5ad4f5bc471840cbfc2596c 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -2471,7 +2471,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, State.Line->InPPDirective, Encoding, Style); } } else if (Current.is(TT_BlockComment)) { - if (!Style.ReflowComments || + if (Style.ReflowComments == FormatStyle::RCS_Never || // If a comment token switches formatting, like // /* clang-format on */, we don't want to break it further, // but we may still want to adjust its indentation. @@ -2492,7 +2492,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, } return true; }(); - if (!Style.ReflowComments || + if (Style.ReflowComments == FormatStyle::RCS_Never || CommentPragmasRegex.match(Current.TokenText.substr(2)) || switchesFormatting(Current) || !RegularComments) { return nullptr; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f97127f09d2096ba53c82c422fc1a8ef7587df63..148270795c562f81e4f869f9ddfa512dc5b69a6f 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -527,6 +527,17 @@ template <> struct MappingTraits { } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::ReflowCommentsStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::RCS_Never); + IO.enumCase(Value, "IndentOnly", FormatStyle::RCS_IndentOnly); + IO.enumCase(Value, "Always", FormatStyle::RCS_Always); + // For backward compatibility: + IO.enumCase(Value, "false", FormatStyle::RCS_Never); + IO.enumCase(Value, "true", FormatStyle::RCS_Always); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) { @@ -1569,7 +1580,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PPIndentWidth = -1; LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; - LLVMStyle.ReflowComments = true; + LLVMStyle.ReflowComments = FormatStyle::RCS_Always; LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave; LLVMStyle.RemoveSemicolon = false; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 364d7e9855e8cf5c8b86ea3ab545ad8508fceaab..fcefaa7bb298eabd7358749d63a7c1ce772d5e13 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1175,26 +1175,19 @@ private: ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); Contexts.back().ColonIsDictLiteral = true; - - const auto *Prev = OpeningBrace.getPreviousNonComment(); - - if (OpeningBrace.is(BK_BracedInit)) { + if (OpeningBrace.is(BK_BracedInit)) Contexts.back().IsExpression = true; - if (Prev) { - for (auto *Tok = Prev->Previous; Tok && Tok->isPointerOrReference(); - Tok = Tok->Previous) { - Tok->setFinalizedType(TT_PointerOrReference); - } - } - } - - if (Style.isJavaScript() && Prev && Prev->is(TT_JsTypeColon)) + if (Style.isJavaScript() && OpeningBrace.Previous && + OpeningBrace.Previous->is(TT_JsTypeColon)) { Contexts.back().IsExpression = false; - + } + if (Style.isVerilog() && + (!OpeningBrace.getPreviousNonComment() || + OpeningBrace.getPreviousNonComment()->isNot(Keywords.kw_apostrophe))) { + Contexts.back().VerilogMayBeConcatenation = true; + } if (Style.isTableGen()) Contexts.back().ColonIsDictLiteral = false; - else if (Style.isVerilog() && !(Prev && Prev->is(Keywords.kw_apostrophe))) - Contexts.back().VerilogMayBeConcatenation = true; unsigned CommaCount = 0; while (CurrentToken) { @@ -1551,7 +1544,8 @@ private: // Case D. if (Keywords.isVerilogIdentifier(*Prev) && PrevPrev->is(tok::comma)) { const FormatToken *PrevParen = PrevPrev->getPreviousNonComment(); - if (PrevParen->is(tok::r_paren) && PrevParen->MatchingParen && + if (PrevParen && PrevParen->is(tok::r_paren) && + PrevParen->MatchingParen && PrevParen->MatchingParen->is(TT_VerilogInstancePortLParen)) { return true; } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 9c4a065fd93b96300ce7fedb529113b8211771ae..c9625c39e527b4ac9670169a9c94164359b77ffc 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -4623,9 +4623,9 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) { // section on \p Line. static bool continuesLineCommentSection(const FormatToken &FormatTok, - const UnwrappedLine &Line, + const UnwrappedLine &Line, const FormatStyle &Style, const llvm::Regex &CommentPragmasRegex) { - if (Line.Tokens.empty()) + if (Line.Tokens.empty() || Style.ReflowComments != FormatStyle::RCS_Always) return false; StringRef IndentContent = FormatTok.TokenText; @@ -4738,7 +4738,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) { // FIXME: Consider putting separate line comment sections as children to the // unwrapped line instead. Tok->ContinuesLineCommentSection = - continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex); + continuesLineCommentSection(*Tok, *Line, Style, CommentPragmasRegex); if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection) addUnwrappedLine(); pushToken(Tok); @@ -4811,8 +4811,8 @@ void UnwrappedLineParser::distributeComments( if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) { FormatTok->ContinuesLineCommentSection = false; } else { - FormatTok->ContinuesLineCommentSection = - continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex); + FormatTok->ContinuesLineCommentSection = continuesLineCommentSection( + *FormatTok, *Line, Style, CommentPragmasRegex); } if (!FormatTok->ContinuesLineCommentSection && (isOnNewLine(*FormatTok) || FormatTok->IsFirst)) { diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index e4b462b9b0fd81b0c04b35406935b5aaa134eaec..64f90c493c1055ddef06d4924c2d02cabee2ad3d 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -457,8 +457,6 @@ private: return "BuildingDeductionGuides"; case CodeSynthesisContext::TypeAliasTemplateInstantiation: return "TypeAliasTemplateInstantiation"; - case CodeSynthesisContext::PartialOrderingTTP: - return "PartialOrderingTTP"; } return ""; } diff --git a/clang/lib/Headers/intrin0.h b/clang/lib/Headers/intrin0.h index 866c8896617d22aea66ef301f68a623318bddc6e..6b01f3808652aa8077c4f0448d41681f250686c3 100644 --- a/clang/lib/Headers/intrin0.h +++ b/clang/lib/Headers/intrin0.h @@ -44,7 +44,7 @@ unsigned char _InterlockedCompareExchange128_rel(__int64 volatile *_Destination, __int64 *_ComparandResult); #endif -#ifdef __x86_64__ && !defined(__arm64ec__) +#if defined(__x86_64__) && !defined(__arm64ec__) unsigned __int64 _umul128(unsigned __int64, unsigned __int64, unsigned __int64 *); unsigned __int64 __shiftleft128(unsigned __int64 _LowPart, diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index f0b4593e0cc22e1d167257154497876c35498a9c..ecc5166d7b814c9b0be0b681d8c2dba0c6dd7188 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -902,6 +902,10 @@ void Preprocessor::Lex(Token &Result) { case tok::r_brace: StdCXXImportSeqState.handleCloseBrace(); break; +#define PRAGMA_ANNOTATION(X) case tok::annot_##X: +// For `#pragma ...` mimic ';'. +#include "clang/Basic/TokenKinds.def" +#undef PRAGMA_ANNOTATION // This token is injected to represent the translation of '#include "a.h"' // into "import a.h;". Mimic the notional ';'. case tok::annot_module_include: diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index b27e50b147f4a8e2343a3dbdbc7c33dec5385349..51d4dc38c17f670727bf01ae02da2d65416075c7 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -797,23 +797,26 @@ bool Parser::ParseOpenACCSizeExprList( /// [num:]int-expr /// dim:int-expr /// static:size-expr -bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) { +Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) { if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) && NextToken().is(tok::colon)) { // 'static' just takes a size-expr, which is an int-expr or an asterisk. ConsumeToken(); ConsumeToken(); - return ParseOpenACCSizeExpr(OpenACCClauseKind::Gang).isInvalid(); + ExprResult Res = ParseOpenACCSizeExpr(OpenACCClauseKind::Gang); + return {OpenACCGangKind::Static, Res}; } if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) && NextToken().is(tok::colon)) { ConsumeToken(); ConsumeToken(); - return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid, - OpenACCClauseKind::Gang, GangLoc) - .first.isInvalid(); + // Parse this as a const-expression, and we'll check its integer-ness/value + // in CheckGangExpr. + ExprResult Res = + getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); + return {OpenACCGangKind::Dim, Res}; } if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) && @@ -822,27 +825,40 @@ bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) { ConsumeToken(); // Fallthrough to the 'int-expr' handling for when 'num' is omitted. } + // This is just the 'num' case where 'num' is optional. - return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid, - OpenACCClauseKind::Gang, GangLoc) - .first.isInvalid(); + ExprResult Res = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid, + OpenACCClauseKind::Gang, GangLoc) + .first; + return {OpenACCGangKind::Num, Res}; } -bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) { - if (ParseOpenACCGangArg(GangLoc)) { +bool Parser::ParseOpenACCGangArgList( + SourceLocation GangLoc, llvm::SmallVectorImpl &GKs, + llvm::SmallVectorImpl &IntExprs) { + + Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc); + if (!Res.second.isUsable()) { SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, Parser::StopBeforeMatch); - return false; + return true; } + GKs.push_back(Res.first); + IntExprs.push_back(Res.second.get()); + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { ExpectAndConsume(tok::comma); - if (ParseOpenACCGangArg(GangLoc)) { + Res = ParseOpenACCGangArg(GangLoc); + if (!Res.second.isUsable()) { SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, Parser::StopBeforeMatch); - return false; + return true; } + + GKs.push_back(Res.first); + IntExprs.push_back(Res.second.get()); } return false; } @@ -1114,6 +1130,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( Parens.skipToEnd(); return OpenACCCanContinue(); } + ParsedClause.setIntExprDetails(IntExpr.get()); break; } case OpenACCClauseKind::Async: { @@ -1129,12 +1146,16 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( } break; } - case OpenACCClauseKind::Gang: - if (ParseOpenACCGangArgList(ClauseLoc)) { + case OpenACCClauseKind::Gang: { + llvm::SmallVector GKs; + llvm::SmallVector IntExprs; + if (ParseOpenACCGangArgList(ClauseLoc, GKs, IntExprs)) { Parens.skipToEnd(); return OpenACCCanContinue(); } + ParsedClause.setGangDetails(std::move(GKs), std::move(IntExprs)); break; + } case OpenACCClauseKind::Wait: { OpenACCWaitParseInfo Info = ParseOpenACCWaitArgument(ClauseLoc, diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 009b8d000e6b0e3e5489d71ab399231e3061d994..9b3894767d86291a4fd38dbf9df42267bc3ba344 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -404,7 +404,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) { if (LHSRecordDecl->hasAttr()) return true; - if (Ctor->getConstructor()->getNumParams() != 1 || + if (Ctor->getConstructor()->param_empty() || !isContainerOfPointer(LHSRecordDecl)) return false; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9f91ee9a39f2f99e76d38fd6a442e46d77903f31..f0d1634af529f0b86055926cc41fa9357a9e31c5 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2385,10 +2385,11 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const { return nullptr; } -LambdaScopeInfo *Sema::getEnclosingLambda() const { +CapturingScopeInfo *Sema::getEnclosingLambdaOrBlock() const { for (auto *Scope : llvm::reverse(FunctionScopes)) { - if (auto *LSI = dyn_cast(Scope)) { - if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && + if (auto *CSI = dyn_cast(Scope)) { + auto *LSI = dyn_cast(CSI); + if (LSI && LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && LSI->AfterParameterList) { // We have switched contexts due to template instantiation. // FIXME: We should swap out the FunctionScopes during code synthesis @@ -2396,7 +2397,7 @@ LambdaScopeInfo *Sema::getEnclosingLambda() const { assert(!CodeSynthesisContexts.empty()); return nullptr; } - return LSI; + return CSI; } } return nullptr; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index cf2a5a622a3a4d38d9653f91b607fa4b694d5759..68a8dfaf1f6183cb819dab36ff3a5a208262bb25 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -750,12 +750,10 @@ bool Sema::UnifySection(StringRef SectionName, int SectionFlags, if (auto A = Decl->getAttr()) if (A->isImplicit()) PragmaLocation = A->getLocation(); - auto SectionIt = Context.SectionInfos.find(SectionName); - if (SectionIt == Context.SectionInfos.end()) { - Context.SectionInfos[SectionName] = - ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags); + auto [SectionIt, Inserted] = Context.SectionInfos.try_emplace( + SectionName, Decl, PragmaLocation, SectionFlags); + if (Inserted) return false; - } // A pre-declared section takes precedence w/o diagnostic. const auto &Section = SectionIt->second; if (Section.SectionFlags == SectionFlags || diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 998a148a7d24a14d9c1b93e9fc863ed6be41116e..e36ee06221371668e66946d6d0e4db1fa25f389b 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); @@ -834,7 +834,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; @@ -910,15 +909,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(); } @@ -957,8 +954,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; @@ -1068,16 +1064,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)) @@ -1524,7 +1520,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, @@ -1805,8 +1800,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 b4494de060538b352cc6506e6c9dd9bca0c9cbbb..5642c821f4ad7cb986f45eae8ee0d47501bdbe17 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -357,10 +357,13 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, return nullptr; } - // FIXME: LookupNestedNameSpecifierName isn't the right kind of - // lookup for class-names. - LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName : - LookupOrdinaryName; + // In the case where we know that the identifier is a class name, we know that + // it is a type declaration (struct, class, union or enum) so we can use tag + // name lookup. + // + // C++ [class.derived]p2 (wrt lookup in a base-specifier): The lookup for + // the component name of the type-name or simple-template-id is type-only. + LookupNameKind Kind = isClassName ? LookupTagName : LookupOrdinaryName; LookupResult Result(*this, &II, NameLoc, Kind); if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we @@ -4510,10 +4513,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: @@ -7663,7 +7666,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()); @@ -7682,6 +7685,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 @@ -8059,12 +8066,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(); } } @@ -9885,6 +9886,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) { @@ -12042,10 +12045,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()) { @@ -15179,8 +15179,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // we know that references to that pack must also be expanded within the // lambda scope. if (New->isParameterPack()) - if (auto *LSI = getEnclosingLambda()) - LSI->LocalPacks.push_back(New); + if (auto *CSI = getEnclosingLambdaOrBlock()) + CSI->LocalPacks.push_back(New); if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() || New->getType().hasNonTrivialToPrimitiveCopyCUnion()) @@ -17107,8 +17107,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 811b3ed2859a2689c4ad4e55f4e6f0c79ecf7f23..c7f2fe08bc1d3e9fdac56101ff4136db6a8341b2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17426,8 +17426,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/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a9e370a9ffbdf9e915af242329ecea7a27196ad5..06a03ee11cc29022117b518254bb751f4010c1b5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4096,7 +4096,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); - Diag(Tok.getLocation(), diag::ext_imaginary_constant); + // In C++, this is a GNU extension. In C, it's a C2y extension. + unsigned DiagId; + if (getLangOpts().CPlusPlus) + DiagId = diag::ext_gnu_imaginary_constant; + else if (getLangOpts().C2y) + DiagId = diag::warn_c23_compat_imaginary_constant; + else + DiagId = diag::ext_c2y_imaginary_constant; + Diag(Tok.getLocation(), DiagId); } return Res; } @@ -16138,17 +16146,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo); QualType T = Sig->getType(); - - // FIXME: We should allow unexpanded parameter packs here, but that would, - // in turn, make the block expression contain unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) { - // Drop the parameters. - FunctionProtoType::ExtProtoInfo EPI; - EPI.HasTrailingReturn = false; - EPI.TypeQuals.addConst(); - T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI); - Sig = Context.getTrivialTypeSourceInfo(T); - } + DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block); // GetTypeForDeclarator always produces a function type for a block // literal signature. Furthermore, it is always a FunctionProtoType @@ -16420,7 +16418,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy); - BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); + BlockExpr *Result = new (Context) + BlockExpr(BD, BlockTy, BSI->ContainsUnexpandedParameterPack); // If the block isn't obviously global, i.e. it captures anything at // all, then we need to do a few things in the surrounding context: @@ -16443,6 +16442,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (getCurFunction()) getCurFunction()->addBlock(BD); + // This can happen if the block's return type is deduced, but + // the return expression is invalid. if (BD->isInvalidDecl()) return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(), {Result}, Result->getType()); @@ -18915,7 +18916,17 @@ bool Sema::tryCaptureVariable( // We need to sync up the Declaration Context with the // FunctionScopeIndexToStopAt if (FunctionScopeIndexToStopAt) { + assert(!FunctionScopes.empty() && "No function scopes to stop at?"); unsigned FSIndex = FunctionScopes.size() - 1; + // When we're parsing the lambda parameter list, the current DeclContext is + // NOT the lambda but its parent. So move away the current LSI before + // aligning DC and FunctionScopeIndexToStopAt. + if (auto *LSI = dyn_cast(FunctionScopes[FSIndex]); + FSIndex && LSI && !LSI->AfterParameterList) + --FSIndex; + assert(MaxFunctionScopesIndex <= FSIndex && + "FunctionScopeIndexToStopAt should be no greater than FSIndex into " + "FunctionScopes."); while (FSIndex != MaxFunctionScopesIndex) { DC = getLambdaAwareParentOfDeclContext(DC); --FSIndex; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8e9bcb10a80b46fe086bbd7a234dbf781a5738ac..40f24ea0ab2eaada8b0d0512f9cc47242b187df8 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -503,17 +503,23 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, const IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); - if (!PP.getSourceManager().isInSystemHeader(Loc)) { - if (auto Hint = FixItHint::CreateReplacement( - Name.getSourceRange(), - (StringRef("operator\"\"") + II->getName()).str()); - isReservedInAllContexts(Status)) { - Diag(Loc, diag::warn_reserved_extern_symbol) - << II << static_cast(Status) << Hint; - } else { - Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint; - } - } + + auto Hint = FixItHint::CreateReplacement( + Name.getSourceRange(), + (StringRef("operator\"\"") + II->getName()).str()); + + // Only emit this diagnostic if we start with an underscore, else the + // diagnostic for C++11 requiring a space between the quotes and the + // identifier conflicts with this and gets confusing. The diagnostic stating + // this is a reserved name should force the underscore, which gets this + // back. + if (II->isReservedLiteralSuffixId() != + ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore) + Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint; + + if (isReservedInAllContexts(Status)) + Diag(Loc, diag::warn_reserved_extern_symbol) + << II << static_cast(Status) << Hint; } if (!SS.isValid()) @@ -2151,7 +2157,8 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. - if (!ArraySize) { + // Dependent case will be handled separately. + if (!ArraySize && !AllocType->isDependentType()) { if (const ConstantArrayType *Array = Context.getAsConstantArrayType(AllocType)) { ArraySize = IntegerLiteral::Create(Context, Array->getSize(), @@ -8680,7 +8687,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( while (isa_and_nonnull(DC)) DC = DC->getParent(); assert( - CurrentLSI->CallOperator == DC && + (CurrentLSI->CallOperator == DC || !CurrentLSI->AfterParameterList) && "The current call operator must be synchronized with Sema's CurContext"); #endif // NDEBUG diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp index 0ac5de29f66aa75e9d2ebadd9cc13dc7510bbb13..70e5d78661a835639aba5d527a3474ed3275d39c 100644 --- a/clang/lib/Sema/SemaFunctionEffects.cpp +++ b/clang/lib/Sema/SemaFunctionEffects.cpp @@ -1133,6 +1133,13 @@ private: return true; } + bool VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Finally) { + diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, + ViolationID::ThrowsOrCatchesExceptions, + Finally->getAtFinallyLoc()); + return true; + } + bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, ViolationID::AccessesObjCMethodOrProperty, @@ -1140,6 +1147,26 @@ private: return true; } + bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *ARP) { + // Under the hood, @autorelease (potentially?) allocates memory and + // invokes ObjC methods. We don't currently have memory allocation as + // a "language construct" but we do have ObjC messaging, so diagnose that. + diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, + ViolationID::AccessesObjCMethodOrProperty, + ARP->getBeginLoc()); + return true; + } + + bool VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Sync) { + // Under the hood, this calls objc_sync_enter and objc_sync_exit, wrapped + // in a @try/@finally block. Diagnose this generically as "ObjC + // messaging". + diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, + ViolationID::AccessesObjCMethodOrProperty, + Sync->getBeginLoc()); + return true; + } + bool VisitSEHExceptStmt(SEHExceptStmt *Exc) { diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, ViolationID::ThrowsOrCatchesExceptions, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5d6a586fe5a2cfd1f7e7c53ae84058fa0d253172..f560865681fa5a6850f1943688b169465b6f919c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9953,7 +9953,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) { auto *Pattern = Template; while (Pattern->getInstantiatedFromMemberTemplate()) { - if (Pattern->isMemberSpecialization()) + if (Pattern->hasMemberSpecialization()) break; Pattern = Pattern->getInstantiatedFromMemberTemplate(); } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index aeb20299b714a3c4e7cfb01ded73b8fe3c5094b5..7b9d5f4ff7eb341545fead5136f9714cf04fd828 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -2353,7 +2353,10 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, Block->setBody(new (Context) CompoundStmt(ConvLocation)); // Create the block literal expression. - Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType()); + // TODO: Do we ever get here if we have unexpanded packs in the lambda??? + Expr *BuildBlock = + new (Context) BlockExpr(Block, Conv->getConversionType(), + /*ContainsUnexpandedParameterPack=*/false); ExprCleanupObjects.push_back(Block); Cleanup.setExprNeedsCleanups(true); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 60fa195221c9384a89e4211774b76bce79e5fce5..f3f62474d06441585d8928d67142a427239b759f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3666,9 +3666,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); if (CheckTemplateArgument( Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), - 0, SugaredChecked, CanonicalChecked, CTAK_Specified, - /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr) || + 0, SugaredChecked, CanonicalChecked, CTAK_Specified) || Trap.hasErrorOccurred()) IsTemplate = false; } diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 66f8029a2754b9339556be449c1de0ac1374c0f6..1b24331cbd87ca11d79873d95994b1dfad73387a 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -366,6 +366,31 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, } } + case OpenACCClauseKind::Gang: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::Routine: + return true; + default: + return false; + } + case OpenACCClauseKind::Worker: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::Routine: + return true; + default: + return false; + } + } + } + default: // Do nothing so we can go to the 'unimplemented' diagnostic instead. return true; @@ -459,6 +484,23 @@ class SemaOpenACCClauseVisitor { return nullptr; } + // OpenACC 3.3 2.9: + // A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause + // appears. + bool DiagIfSeqClause(SemaOpenACC::OpenACCParsedClause &Clause) { + const auto *Itr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + + if (Itr != ExistingClauses.end()) { + SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) + << Clause.getClauseKind() << (*Itr)->getClauseKind(); + SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + + return true; + } + return false; + } + public: SemaOpenACCClauseVisitor(SemaOpenACC &S, ArrayRef ExistingClauses) @@ -470,26 +512,13 @@ public: OpenACCClause *Visit(SemaOpenACC::OpenACCParsedClause &Clause) { switch (Clause.getClauseKind()) { - case OpenACCClauseKind::Gang: - case OpenACCClauseKind::Worker: - case OpenACCClauseKind::Vector: { - // TODO OpenACC: These are only implemented enough for the 'seq' diagnostic, - // otherwise treats itself as unimplemented. When we implement these, we - // can remove them from here. - - // 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()) { - SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine) - << Clause.getClauseKind() << (*Itr)->getClauseKind(); - SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + case OpenACCClauseKind::Vector: { + // TODO OpenACC: These are only implemented enough for the 'seq' + // diagnostic, otherwise treats itself as unimplemented. When we + // implement these, we can remove them from here. + DiagIfSeqClause(Clause); + return isNotImplemented(); } - return isNotImplemented(); - } #define VISIT_CLAUSE(CLAUSE_NAME) \ case OpenACCClauseKind::CLAUSE_NAME: \ @@ -1006,6 +1035,169 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIndependentClause( Clause.getEndLoc()); } +OpenACCClause *SemaOpenACCClauseVisitor::VisitWorkerClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + if (DiagIfSeqClause(Clause)) + return nullptr; + + // Restrictions only properly implemented on 'loop' constructs, and it is + // the only construct that can do anything with this, so skip/treat as + // unimplemented for the combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + return isNotImplemented(); + + Expr *IntExpr = + Clause.getNumIntExprs() != 0 ? Clause.getIntExprs()[0] : nullptr; + + if (IntExpr) { + switch (SemaRef.getActiveComputeConstructInfo().Kind) { + case OpenACCDirectiveKind::Invalid: + SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Worker << "num" << /*orphan=*/0; + IntExpr = nullptr; + break; + case OpenACCDirectiveKind::Parallel: + SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Worker << "num" << /*parallel=*/1; + IntExpr = nullptr; + break; + case OpenACCDirectiveKind::Serial: + SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Worker << "num" << /*serial=*/3; + IntExpr = nullptr; + break; + case OpenACCDirectiveKind::Kernels: { + const auto *Itr = + llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, + llvm::IsaPred); + if (Itr != SemaRef.getActiveComputeConstructInfo().Clauses.end()) { + SemaRef.Diag(IntExpr->getBeginLoc(), diag::err_acc_num_arg_conflict) + << OpenACCClauseKind::Worker << /*num_workers=*/1; + SemaRef.Diag((*Itr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + + IntExpr = nullptr; + } + break; + } + default: + llvm_unreachable("Non compute construct in active compute construct"); + } + } + + // OpenACC 3.3 2.9.3: The region of a loop with a 'worker' clause may not + // contain a loop with a gang or worker clause unless within a nested compute + // region. + if (SemaRef.LoopWorkerClauseLoc.isValid()) { + // This handles the 'inner loop' diagnostic, but we cannot set that we're on + // one of these until we get to the end of the construct. + SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) + << OpenACCClauseKind::Worker << OpenACCClauseKind::Worker + << /*skip kernels construct info*/ 0; + SemaRef.Diag(SemaRef.LoopWorkerClauseLoc, + diag::note_acc_previous_clause_here); + return nullptr; + } + + return OpenACCWorkerClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), IntExpr, + Clause.getEndLoc()); +} + +OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + if (DiagIfSeqClause(Clause)) + return nullptr; + + // Restrictions only properly implemented on 'loop' constructs, and it is + // the only construct that can do anything with this, so skip/treat as + // unimplemented for the combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + return isNotImplemented(); + + llvm::SmallVector GangKinds; + llvm::SmallVector IntExprs; + + // Store the existing locations, so we can do duplicate checking. Index is + // the int-value of the OpenACCGangKind enum. + SourceLocation ExistingElemLoc[3]; + + for (unsigned I = 0; I < Clause.getIntExprs().size(); ++I) { + OpenACCGangKind GK = Clause.getGangKinds()[I]; + ExprResult ER = SemaRef.CheckGangExpr(GK, Clause.getIntExprs()[I]); + + if (!ER.isUsable()) + continue; + + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... An argument with no + // keyword or with num keyword is only allowed when num_gangs does not + // appear on the kernels construct. + if (SemaRef.getActiveComputeConstructInfo().Kind == + OpenACCDirectiveKind::Kernels && + GK == OpenACCGangKind::Num) { + const auto *Itr = + llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, + llvm::IsaPred); + + if (Itr != SemaRef.getActiveComputeConstructInfo().Clauses.end()) { + SemaRef.Diag(ER.get()->getBeginLoc(), diag::err_acc_num_arg_conflict) + << OpenACCClauseKind::Gang << /*num_gangs=*/0; + SemaRef.Diag((*Itr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + continue; + } + } + + // OpenACC 3.3 2.9: 'gang-arg-list' may have at most one num, one dim, and + // one static argument. + if (ExistingElemLoc[static_cast(GK)].isValid()) { + SemaRef.Diag(ER.get()->getBeginLoc(), diag::err_acc_gang_multiple_elt) + << static_cast(GK); + SemaRef.Diag(ExistingElemLoc[static_cast(GK)], + diag::note_acc_previous_expr_here); + continue; + } + + ExistingElemLoc[static_cast(GK)] = ER.get()->getBeginLoc(); + GangKinds.push_back(GK); + IntExprs.push_back(ER.get()); + } + + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... The region of a loop + // with a gang clause may not contain another loop with a gang clause unless + // within a nested compute region. + if (SemaRef.LoopGangClauseOnKernelLoc.isValid()) { + // This handles the 'inner loop' diagnostic, but we cannot set that we're on + // one of these until we get to the end of the construct. + SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) + << OpenACCClauseKind::Gang << OpenACCClauseKind::Gang + << /*kernels construct info*/ 1; + SemaRef.Diag(SemaRef.LoopGangClauseOnKernelLoc, + diag::note_acc_previous_clause_here); + return nullptr; + } + + // OpenACC 3.3 2.9.3: The region of a loop with a 'worker' clause may not + // contain a loop with a gang or worker clause unless within a nested compute + // region. + if (SemaRef.LoopWorkerClauseLoc.isValid()) { + // This handles the 'inner loop' diagnostic, but we cannot set that we're on + // one of these until we get to the end of the construct. + SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_in_clause_region) + << OpenACCClauseKind::Gang << OpenACCClauseKind::Worker + << /*kernels construct info*/ 1; + SemaRef.Diag(SemaRef.LoopWorkerClauseLoc, + diag::note_acc_previous_clause_here); + return nullptr; + } + + return OpenACCGangClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), GangKinds, IntExprs, + Clause.getEndLoc()); +} + OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( SemaOpenACC::OpenACCParsedClause &Clause) { // Restrictions only properly implemented on 'loop' constructs, and it is @@ -1118,17 +1310,52 @@ SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII( SemaOpenACC &S, OpenACCDirectiveKind DK, ArrayRef UnInstClauses, ArrayRef Clauses) - : SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct), - DirKind(DK), LoopRAII(SemaRef, /*PreserveDepth=*/false) { + : SemaRef(S), OldActiveComputeConstructInfo(S.ActiveComputeConstructInfo), + DirKind(DK), OldLoopGangClauseOnKernelLoc(S.LoopGangClauseOnKernelLoc), + OldLoopWorkerClauseLoc(S.LoopWorkerClauseLoc), + LoopRAII(SemaRef, /*PreserveDepth=*/false) { // Compute constructs end up taking their 'loop'. if (DirKind == OpenACCDirectiveKind::Parallel || DirKind == OpenACCDirectiveKind::Serial || DirKind == OpenACCDirectiveKind::Kernels) { - SemaRef.InsideComputeConstruct = true; + SemaRef.ActiveComputeConstructInfo.Kind = DirKind; + SemaRef.ActiveComputeConstructInfo.Clauses = Clauses; SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs); + + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... The region of a loop + // with a gang clause may not contain another loop with a gang clause unless + // within a nested compute region. + // + // Implement the 'unless within a nested compute region' part. + SemaRef.LoopGangClauseOnKernelLoc = {}; + SemaRef.LoopWorkerClauseLoc = {}; } else if (DirKind == OpenACCDirectiveKind::Loop) { SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses); SetTileInfoBeforeAssociatedStmt(UnInstClauses, Clauses); + + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... The region of a loop + // with a gang clause may not contain another loop with a gang clause unless + // within a nested compute region. + // + // We don't bother doing this when this is a template instantiation, as + // there is no reason to do these checks: the existance of a + // gang/kernels/etc cannot be dependent. + if (SemaRef.getActiveComputeConstructInfo().Kind == + OpenACCDirectiveKind::Kernels && + UnInstClauses.empty()) { + // This handles the 'outer loop' part of this. + auto *Itr = llvm::find_if(Clauses, llvm::IsaPred); + if (Itr != Clauses.end()) + SemaRef.LoopGangClauseOnKernelLoc = (*Itr)->getBeginLoc(); + } + + if (UnInstClauses.empty()) { + auto *Itr = llvm::find_if(Clauses, llvm::IsaPred); + if (Itr != Clauses.end()) + SemaRef.LoopWorkerClauseLoc = (*Itr)->getBeginLoc(); + } } } @@ -1199,7 +1426,10 @@ void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt( } SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() { - SemaRef.InsideComputeConstruct = WasInsideComputeConstruct; + SemaRef.ActiveComputeConstructInfo = OldActiveComputeConstructInfo; + SemaRef.LoopGangClauseOnKernelLoc = OldLoopGangClauseOnKernelLoc; + SemaRef.LoopWorkerClauseLoc = OldLoopWorkerClauseLoc; + if (DirKind == OpenACCDirectiveKind::Parallel || DirKind == OpenACCDirectiveKind::Serial || DirKind == OpenACCDirectiveKind::Kernels) { @@ -1761,6 +1991,109 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) { ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})}; } +namespace { +ExprResult CheckGangStaticExpr(SemaOpenACC &S, Expr *E) { + if (isa(E)) + return E; + return S.ActOnIntExpr(OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Gang, + E->getBeginLoc(), E); +} +} // namespace + +ExprResult SemaOpenACC::CheckGangExpr(OpenACCGangKind GK, Expr *E) { + // Gang Expr legality depends on the associated compute construct. + switch (ActiveComputeConstructInfo.Kind) { + case OpenACCDirectiveKind::Invalid: + case OpenACCDirectiveKind::Parallel: { + switch (GK) { + // OpenACC 3.3 2.9.2: When the parent compute construct is a parallel + // construct, or an orphaned loop construct, the gang clause behaves as + // follows. ... The dim argument must be a constant positive integer value + // 1, 2, or 3. + case OpenACCGangKind::Dim: { + if (!E) + return ExprError(); + ExprResult Res = + ActOnIntExpr(OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Gang, + E->getBeginLoc(), E); + + if (!Res.isUsable()) + return Res; + + if (Res.get()->isInstantiationDependent()) + return Res; + + std::optional ICE = + Res.get()->getIntegerConstantExpr(getASTContext()); + + if (!ICE || *ICE <= 0 || ICE > 3) { + Diag(Res.get()->getBeginLoc(), diag::err_acc_gang_dim_value) + << ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue(); + return ExprError(); + } + + return ExprResult{ + ConstantExpr::Create(getASTContext(), Res.get(), APValue{*ICE})}; + } + // OpenACC 3.3 2.9.2: When the parent compute construct is a parallel + // construct, or an orphaned loop construct, the gang clause behaves as + // follows. ... The num argument is not allowed. + case OpenACCGangKind::Num: + Diag(E->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Gang << GK + << (/*orphan/parallel=*/ActiveComputeConstructInfo.Kind == + OpenACCDirectiveKind::Parallel + ? 1 + : 0); + return ExprError(); + case OpenACCGangKind::Static: + return CheckGangStaticExpr(*this, E); + } + } break; + case OpenACCDirectiveKind::Kernels: { + switch (GK) { + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... The dim argument is + // not allowed. + case OpenACCGangKind::Dim: + Diag(E->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Gang << GK << /*kernels=*/2; + return ExprError(); + // OpenACC 3.3 2.9.2: When the parent compute construct is a kernels + // construct, the gang clause behaves as follows. ... An argument with no + // keyword or with num keyword is only allowed when num_gangs does not + // appear on the kernels construct. ... The region of a loop with the gang + // clause may not contain another loop with a gang clause unless within a + // nested compute region. + case OpenACCGangKind::Num: + // This isn't allowed if there is a 'num_gangs' on the kernel construct, + // and makes loop-with-gang-clause ill-formed inside of this 'loop', but + // nothing can be enforced here. + return ExprResult{E}; + case OpenACCGangKind::Static: + return CheckGangStaticExpr(*this, E); + } + } break; + case OpenACCDirectiveKind::Serial: { + switch (GK) { + // 'dim' and 'num' don't really make sense on serial, and GCC rejects them + // too, so we disallow them too. + case OpenACCGangKind::Dim: + case OpenACCGangKind::Num: + Diag(E->getBeginLoc(), diag::err_acc_int_arg_invalid) + << OpenACCClauseKind::Gang << GK << /*Kernels=*/3; + return ExprError(); + case OpenACCGangKind::Static: + return CheckGangStaticExpr(*this, E); + } + } + default: + llvm_unreachable("Non compute construct in active compute construct?"); + } + + llvm_unreachable("Compute construct directive not handled?"); +} + ExprResult SemaOpenACC::CheckTileSizeExpr(Expr *SizeExpr) { if (!SizeExpr) return ExprError(); @@ -2031,7 +2364,7 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, // If we are in the scope of a compute construct, add this to the list of // loop constructs that need assigning to the next closing compute // construct. - if (InsideComputeConstruct) + if (isInComputeConstruct()) ParentlessLoopConstructs.push_back(LoopConstruct); return LoopConstruct; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f545e9341e1ae6c5c45f235ef7178bfe59b0afdf..1205e85b4e6f531a01af00a3ea4ba89f263f6e9b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1422,8 +1422,12 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, // the implicit object parameter are of the same type. auto NormalizeQualifiers = [&](const CXXMethodDecl *M, Qualifiers Q) { - if (M->isExplicitObjectMemberFunction()) + if (M->isExplicitObjectMemberFunction()) { + auto ThisType = M->getFunctionObjectParameterReferenceType(); + if (ThisType.isConstQualified()) + Q.removeConst(); return Q; + } // We do not allow overloading based off of '__restrict'. Q.removeRestrict(); @@ -1439,14 +1443,23 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, return Q; }; - auto CompareType = [&](QualType Base, QualType D) { - auto BS = Base.getNonReferenceType().getCanonicalType().split(); + auto AreQualifiersEqual = [&](SplitQualType BS, SplitQualType DS) { BS.Quals = NormalizeQualifiers(OldMethod, BS.Quals); + DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals); + + if (OldMethod->isExplicitObjectMemberFunction()) { + BS.Quals.removeVolatile(); + DS.Quals.removeVolatile(); + } + + return BS.Quals == DS.Quals; + }; + auto CompareType = [&](QualType Base, QualType D) { + auto BS = Base.getNonReferenceType().getCanonicalType().split(); auto DS = D.getNonReferenceType().getCanonicalType().split(); - DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals); - if (BS.Quals != DS.Quals) + if (!AreQualifiersEqual(BS, DS)) return false; if (OldMethod->isImplicitObjectMemberFunction() && @@ -6864,8 +6877,7 @@ void Sema::AddOverloadCandidate( OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction, - bool HasMatchedPackOnParmToNonPackOnArg) { + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { const FunctionProtoType *Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6884,8 +6896,7 @@ void Sema::AddOverloadCandidate( AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, - PartialOverloading, EarlyConversions, PO, - HasMatchedPackOnParmToNonPackOnArg); + PartialOverloading, EarlyConversions, PO); return; } // We treat a constructor like a non-member function, since its object @@ -6928,8 +6939,6 @@ void Sema::AddOverloadCandidate( CandidateSet.getRewriteInfo().getRewriteKind(Function, PO); Candidate.IsADLCandidate = IsADLCandidate; Candidate.ExplicitCallArguments = Args.size(); - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -7457,13 +7466,16 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, } } -void Sema::AddMethodCandidate( - CXXMethodDecl *Method, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) { +void +Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef Args, + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions, + bool PartialOverloading, + ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO) { const FunctionProtoType *Proto = dyn_cast(Method->getType()->getAs()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -7494,8 +7506,6 @@ void Sema::AddMethodCandidate( Candidate.TookAddressOfOverload = CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet; Candidate.ExplicitCallArguments = Args.size(); - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; bool IgnoreExplicitObject = (Method->isExplicitObjectMemberFunction() && @@ -7666,8 +7676,8 @@ void Sema::AddMethodTemplateCandidate( ConversionSequenceList Conversions; if (TemplateDeductionResult Result = DeduceTemplateArguments( MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, - PartialOverloading, /*AggregateDeductionCandidate=*/false, - /*PartialOrdering=*/false, ObjectType, ObjectClassification, + PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType, + ObjectClassification, [&](ArrayRef ParamTypes) { return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, @@ -7705,8 +7715,7 @@ void Sema::AddMethodTemplateCandidate( AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO, - Info.hasMatchedPackOnParmToNonPackOnArg()); + Conversions, PO); } /// Determine whether a given function template has a simple explicit specifier @@ -7752,7 +7761,6 @@ void Sema::AddTemplateOverloadCandidate( if (TemplateDeductionResult Result = DeduceTemplateArguments( FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, AggregateCandidateDeduction, - /*PartialOrdering=*/false, /*ObjectType=*/QualType(), /*ObjectClassification=*/Expr::Classification(), [&](ArrayRef ParamTypes) { @@ -7793,8 +7801,7 @@ void Sema::AddTemplateOverloadCandidate( Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, AllowExplicit, /*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO, - Info.AggregateDeductionCandidateHasMismatchedArity, - Info.hasMatchedPackOnParmToNonPackOnArg()); + Info.AggregateDeductionCandidateHasMismatchedArity); } bool Sema::CheckNonDependentConversions( @@ -7916,8 +7923,7 @@ void Sema::AddConversionCandidate( CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, - bool AllowExplicit, bool AllowResultConversion, - bool HasMatchedPackOnParmToNonPackOnArg) { + bool AllowExplicit, bool AllowResultConversion) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); QualType ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -7962,8 +7968,6 @@ void Sema::AddConversionCandidate( Candidate.FinalConversion.setAllToTypes(ToType); Candidate.Viable = true; Candidate.ExplicitCallArguments = 1; - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -8165,8 +8169,7 @@ void Sema::AddTemplateConversionCandidate( assert(Specialization && "Missing function template specialization?"); AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, CandidateSet, AllowObjCConversionOnExplicit, - AllowExplicit, AllowResultConversion, - Info.hasMatchedPackOnParmToNonPackOnArg()); + AllowExplicit, AllowResultConversion); } void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, @@ -10519,10 +10522,6 @@ bool clang::isBetterOverloadCandidate( isa(Cand2.Function)) return isa(Cand1.Function); - if (Cand1.HasMatchedPackOnParmToNonPackOnArg != - Cand2.HasMatchedPackOnParmToNonPackOnArg) - return Cand2.HasMatchedPackOnParmToNonPackOnArg; - // -- F1 is a non-template function and F2 is a function template // specialization, or, if not that, bool Cand1IsSpecialization = Cand1.Function && diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index d81c6de3428dc7b684ed07fd632644d9568ef238..f801455596fe6f408feb7e33932545cdf61c4a0d 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -682,6 +682,10 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, case ParsedAttr::AT_Annotate: return S.CreateAnnotationAttr(A); default: + if (Attr *AT = nullptr; A.getInfo().handleStmtAttribute(S, St, A, AT) != + ParsedAttrInfo::NotHandled) { + return AT; + } // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is // needed for attributes in Attr.td that do not list any subjects. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 62d0d0914fa3062a6ae07b8230365987347516ac..294eb8e3353cde75d39b0a9c3e32a1c9357b9d0a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1010,8 +1010,8 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, Param->setAccess(AS_public); if (Param->isParameterPack()) - if (auto *LSI = getEnclosingLambda()) - LSI->LocalPacks.push_back(Param); + if (auto *CSI = getEnclosingLambdaOrBlock()) + CSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); @@ -1542,8 +1542,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Param->setInvalidDecl(); if (Param->isParameterPack()) - if (auto *LSI = getEnclosingLambda()) - LSI->LocalPacks.push_back(Param); + if (auto *CSI = getEnclosingLambdaOrBlock()) + CSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(), @@ -1593,7 +1593,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter( Param->setAccess(AS_public); if (Param->isParameterPack()) - if (auto *LSI = getEnclosingLambda()) + if (auto *LSI = getEnclosingLambdaOrBlock()) LSI->LocalPacks.push_back(Param); // If the template template parameter has a name, then link the identifier @@ -1795,8 +1795,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 && @@ -1984,19 +1985,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, @@ -2011,30 +1999,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 @@ -2046,23 +2010,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. @@ -2089,10 +2036,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. @@ -2105,7 +2050,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); @@ -2120,12 +2068,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()) @@ -2135,8 +2077,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); @@ -4133,7 +4129,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."); @@ -4251,17 +4248,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 @@ -5179,8 +5175,7 @@ bool Sema::CheckTemplateArgument( unsigned ArgumentPackIndex, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, - CheckTemplateArgumentKind CTAK, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg) { + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted, @@ -5395,8 +5390,8 @@ bool Sema::CheckTemplateArgument( case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering, - MatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateTemplateArgument(TempParm, Params, Arg, + /*IsDeduced=*/CTAK != CTAK_Specified)) return true; SugaredConverted.push_back(Arg.getArgument()); @@ -5470,7 +5465,7 @@ bool Sema::CheckTemplateArgumentList( SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, - bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) { + bool PartialOrderingTTP) { if (ConstraintsNotSatisfied) *ConstraintsNotSatisfied = false; @@ -5503,7 +5498,8 @@ bool Sema::CheckTemplateArgumentList( DefaultArgs && ParamIdx >= DefaultArgs.StartPos) { // All written arguments should have been consumed by this point. assert(ArgIdx == NumArgs && "bad default argument deduction"); - if (ParamIdx == DefaultArgs.StartPos) { + // FIXME: Don't ignore parameter packs. + if (ParamIdx == DefaultArgs.StartPos && !(*Param)->isParameterPack()) { assert(Param + DefaultArgs.Args.size() <= ParamEnd); // Default arguments from a DeducedTemplateName are already converted. for (const TemplateArgument &DefArg : DefaultArgs.Args) { @@ -5549,8 +5545,7 @@ bool Sema::CheckTemplateArgumentList( if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc, SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - MatchedPackOnParmToNonPackOnArg)) + CTAK_Specified)) return true; CanonicalConverted.back().setIsDefaulted( @@ -5708,8 +5703,7 @@ bool Sema::CheckTemplateArgumentList( // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) + CTAK_Specified)) return true; SugaredConverted.back().setIsDefaulted(true); @@ -5730,9 +5724,8 @@ bool Sema::CheckTemplateArgumentList( // pack expansions; they might be empty. This can happen even if // PartialTemplateArgs is false (the list of arguments is complete but // still dependent). - if (PartialOrderingTTP || - (CurrentInstantiationScope && - CurrentInstantiationScope->getPartiallySubstitutedPack())) { + if (ArgIdx < NumArgs && CurrentInstantiationScope && + CurrentInstantiationScope->getPartiallySubstitutedPack()) { while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) { const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument(); @@ -5779,9 +5772,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()))) { @@ -7292,10 +7283,10 @@ static void DiagnoseTemplateParameterListArityMismatch( Sema &S, TemplateParameterList *New, TemplateParameterList *Old, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); -bool Sema::CheckTemplateTemplateArgument( - TemplateTemplateParmDecl *Param, TemplateParameterList *Params, - TemplateArgumentLoc &Arg, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg) { +bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, + TemplateArgumentLoc &Arg, + bool IsDeduced) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); if (!Template) { @@ -7330,47 +7321,64 @@ bool Sema::CheckTemplateTemplateArgument( << Template; } - if (!getLangOpts().RelaxedTemplateTemplateArgs) - return !TemplateParameterListsAreEqual( - Template->getTemplateParameters(), Params, /*Complain=*/true, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); - // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. - if (!isTemplateTemplateParameterAtLeastAsSpecializedAs( - Params, Param, Template, DefaultArgs, Arg.getLocation(), - PartialOrdering, MatchedPackOnParmToNonPackOnArg)) - return true; - // P2113 - // C++20[temp.func.order]p2 - // [...] If both deductions succeed, the partial ordering selects the - // more constrained template (if one exists) as determined below. - SmallVector ParamsAC, TemplateAC; - Params->getAssociatedConstraints(ParamsAC); - // C++20[temp.arg.template]p3 - // [...] In this comparison, if P is unconstrained, the constraints on A - // are not considered. - if (ParamsAC.empty()) - return false; + if (getLangOpts().RelaxedTemplateTemplateArgs) { + // Quick check for the common case: + // If P contains a parameter pack, then A [...] matches P if each of A's + // template parameters matches the corresponding template parameter in + // the template-parameter-list of P. + if (TemplateParameterListsAreEqual( + Template->getTemplateParameters(), Params, false, + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) + return false; - Template->getAssociatedConstraints(TemplateAC); + if (isTemplateTemplateParameterAtLeastAsSpecializedAs( + Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) { + // P2113 + // C++20[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template (if one exists) as determined below. + SmallVector ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; - bool IsParamAtLeastAsConstrained; - if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, - IsParamAtLeastAsConstrained)) - return true; - if (!IsParamAtLeastAsConstrained) { - Diag(Arg.getLocation(), - diag::err_template_template_parameter_not_at_least_as_constrained) - << Template << Param << Arg.getSourceRange(); - Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; - Diag(Template->getLocation(), diag::note_entity_declared_at) << Template; - MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, - TemplateAC); - return true; + Template->getAssociatedConstraints(TemplateAC); + + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) + << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; + } + return false; + } + // FIXME: Produce better diagnostics for deduction failures. } - return false; + + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), + Params, + true, + TPL_TemplateTemplateArgumentMatch, + Arg.getLocation()); } static Sema::SemaDiagnosticBuilder noteLocation(Sema &S, const NamedDecl &Decl, @@ -8453,15 +8461,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. @@ -8471,6 +8476,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()) { @@ -8482,11 +8492,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 @@ -9086,8 +9091,8 @@ bool Sema::CheckFunctionTemplateSpecialization( TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( - cast(FunTmpl->getFirstDecl()), - ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info); + FunTmpl, ExplicitTemplateArgs ? &Args : nullptr, FT, + Specialization, Info); TDK != TemplateDeductionResult::Success) { // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. @@ -9758,14 +9763,11 @@ DeclResult Sema::ActOnExplicitInstantiation( // Check that the template argument list is well-formed for this // template. - bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false; SmallVector SugaredConverted, CanonicalConverted; - if (CheckTemplateArgumentList( - ClassTemplate, TemplateNameLoc, TemplateArgs, - /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true, - /*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false, - &PrimaryHasMatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return true; // Find the class template specialization declaration that @@ -9886,9 +9888,7 @@ DeclResult Sema::ActOnExplicitInstantiation( = cast_or_null( Specialization->getDefinition()); if (!Def) - InstantiateClassTemplateSpecialization( - TemplateNameLoc, Specialization, TSK, - /*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg); + InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); else if (TSK == TSK_ExplicitInstantiationDefinition) { MarkVTableUsed(TemplateNameLoc, Specialization, true); Specialization->setPointOfInstantiation(Def->getPointOfInstantiation()); @@ -11290,8 +11290,8 @@ private: 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 e49d315f7186bca02d88bae209d86015407d88dc..7cfb8d687c796a92fe117352d597c0c53515b774 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -145,9 +145,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( PartialOrderingKind POK, bool DeducedFromArrayBound, bool *HasDeducedAnyParam); -/// What directions packs are allowed to match non-packs. -enum class PackFold { ParameterToArgument, ArgumentToParameter, Both }; - +enum class PackFold { ParameterToArgument, ArgumentToParameter }; static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef Ps, @@ -1713,21 +1711,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); if (Result.isNull()) { - // We can also get inconsistencies when matching NTTP type. - switch (NamedDecl *Param = TemplateParams->getParam(Index); - Param->getKind()) { - case Decl::TemplateTypeParm: - Info.Param = cast(Param); - break; - case Decl::NonTypeTemplateParm: - Info.Param = cast(Param); - break; - case Decl::TemplateTemplateParm: - Info.Param = cast(Param); - break; - default: - llvm_unreachable("unexpected kind"); - } + Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; Info.SecondArg = NewDeduced; return TemplateDeductionResult::Inconsistent; @@ -2565,31 +2549,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, P.getAsExpr())) { switch (A.getKind()) { - case TemplateArgument::Expression: { - const Expr *E = A.getAsExpr(); - // When checking NTTP, if either the parameter or the argument is - // dependent, as there would be otherwise nothing to deduce, we force - // the argument to the parameter type using this dependent implicit - // cast, in order to maintain invariants. Now we can deduce the - // resulting type from the original type, and deduce the original type - // against the parameter we are checking. - if (const auto *ICE = dyn_cast(E); - ICE && ICE->getCastKind() == clang::CK_Dependent) { - E = ICE->getSubExpr(); - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, ICE->getType(), E->getType(), Info, - Deduced, TDF_SkipNonDependent, - PartialOrdering ? PartialOrderingKind::NonCall - : PartialOrderingKind::None, - /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; - } - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, DeducedTemplateArgument(A), E->getType(), - Info, PartialOrdering, Deduced, HasDeducedAnyParam); - } case TemplateArgument::Integral: + case TemplateArgument::Expression: case TemplateArgument::StructuralValue: return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(A), @@ -2678,75 +2639,50 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch, bool PartialOrdering, PackFold PackFold, bool *HasDeducedAnyParam) { - bool FoldPackParameter = PackFold == PackFold::ParameterToArgument || - PackFold == PackFold::Both, - FoldPackArgument = PackFold == PackFold::ArgumentToParameter || - PackFold == PackFold::Both; - + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Ps, As); // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - if (FoldPackParameter && hasPackExpansionBeforeEnd(Ps)) - return TemplateDeductionResult::Success; - - if (FoldPackArgument && hasPackExpansionBeforeEnd(As)) + if (hasPackExpansionBeforeEnd(Ps)) return TemplateDeductionResult::Success; // C++0x [temp.deduct.type]p9: // If P has a form that contains or , then each argument Pi of the // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. - for (unsigned ArgIdx = 0, ParamIdx = 0; /**/; /**/) { - if (!hasTemplateArgumentForDeduction(Ps, ParamIdx)) - return !FoldPackParameter && hasTemplateArgumentForDeduction(As, ArgIdx) - ? TemplateDeductionResult::MiscellaneousDeductionFailure - : TemplateDeductionResult::Success; - - if (!Ps[ParamIdx].isPackExpansion()) { + unsigned ArgIdx = 0, ParamIdx = 0; + for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) { + const TemplateArgument &P = Ps[ParamIdx]; + if (!P.isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. if (!hasTemplateArgumentForDeduction(As, ArgIdx)) - return !FoldPackArgument && NumberOfArgumentsMustMatch + return NumberOfArgumentsMustMatch ? TemplateDeductionResult::MiscellaneousDeductionFailure : TemplateDeductionResult::Success; - if (As[ArgIdx].isPackExpansion()) { - // C++1z [temp.deduct.type]p9: - // During partial ordering, if Ai was originally a pack expansion - // [and] Pi is not a pack expansion, template argument deduction - // fails. - if (!FoldPackArgument) - return TemplateDeductionResult::MiscellaneousDeductionFailure; - - TemplateArgument Pattern = As[ArgIdx].getPackExpansionPattern(); - for (;;) { - // Deduce template parameters from the pattern. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Ps[ParamIdx], Pattern, Info, - PartialOrdering, Deduced, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; + // C++1z [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion [and] + // Pi is not a pack expansion, template argument deduction fails. + if (As[ArgIdx].isPackExpansion()) + return TemplateDeductionResult::MiscellaneousDeductionFailure; - ++ParamIdx; - if (!hasTemplateArgumentForDeduction(Ps, ParamIdx)) - return TemplateDeductionResult::Success; - if (Ps[ParamIdx].isPackExpansion()) - break; - } - } else { - // Perform deduction for this Pi/Ai pair. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Ps[ParamIdx], As[ArgIdx], Info, - PartialOrdering, Deduced, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; + // Perform deduction for this Pi/Ai pair. + TemplateArgument Pi = P, Ai = As[ArgIdx]; + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Pi, Ai); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, + PartialOrdering, Deduced, + HasDeducedAnyParam); + Result != TemplateDeductionResult::Success) + return Result; - ++ArgIdx; - ++ParamIdx; - continue; - } + // Move to the next argument. + ++ArgIdx; + continue; } // The parameter is a pack expansion. @@ -2756,7 +2692,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // each remaining argument in the template argument list of A. Each // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by Pi. - TemplateArgument Pattern = Ps[ParamIdx].getPackExpansionPattern(); + TemplateArgument Pattern = P.getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); @@ -2767,16 +2703,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, for (; hasTemplateArgumentForDeduction(As, ArgIdx) && PackScope.hasNextElement(); ++ArgIdx) { - if (!As[ArgIdx].isPackExpansion()) { - if (!FoldPackParameter) - return TemplateDeductionResult::MiscellaneousDeductionFailure; - if (FoldPackArgument) - Info.setMatchedPackOnParmToNonPackOnArg(); - } + TemplateArgument Pi = Pattern, Ai = As[ArgIdx]; + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Pi, Ai); // Deduce template arguments from the pattern. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering, - Deduced, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2785,8 +2718,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Build argument packs for each of the parameter packs expanded by this // pack expansion. - return PackScope.finish(); + if (auto Result = PackScope.finish(); + Result != TemplateDeductionResult::Success) + return Result; } + + return TemplateDeductionResult::Success; } TemplateDeductionResult Sema::DeduceTemplateArguments( @@ -2955,7 +2892,7 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, /// fully-converted template arguments. static bool ConvertDeducedTemplateArgument( Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, - TemplateDeductionInfo &Info, bool IsDeduced, bool PartialOrdering, + TemplateDeductionInfo &Info, bool IsDeduced, SmallVectorImpl &SugaredOutput, SmallVectorImpl &CanonicalOutput) { auto ConvertArg = [&](DeducedTemplateArgument Arg, @@ -2966,20 +2903,15 @@ static bool ConvertDeducedTemplateArgument( TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc( Arg, QualType(), Info.getLocation(), Param); - bool MatchedPackOnParmToNonPackOnArg = false; // Check the template argument, converting it as necessary. - auto Res = S.CheckTemplateArgument( + return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput, CanonicalOutput, IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) - : Sema::CTAK_Specified, - PartialOrdering, &MatchedPackOnParmToNonPackOnArg); - if (MatchedPackOnParmToNonPackOnArg) - Info.setMatchedPackOnParmToNonPackOnArg(); - return Res; + : Sema::CTAK_Specified); }; if (Arg.getKind() == TemplateArgument::Pack) { @@ -3062,9 +2994,9 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( SmallVectorImpl &Deduced, TemplateDeductionInfo &Info, SmallVectorImpl &SugaredBuilder, - SmallVectorImpl &CanonicalBuilder, bool PartialOrdering, - LocalInstantiationScope *CurrentInstantiationScope, - unsigned NumAlreadyConverted, bool *IsIncomplete) { + SmallVectorImpl &CanonicalBuilder, + LocalInstantiationScope *CurrentInstantiationScope = nullptr, + unsigned NumAlreadyConverted = 0, bool *IsIncomplete = nullptr) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -3107,8 +3039,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( // We may have deduced this argument, so it still needs to be // checked and converted. if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, - IsDeduced, PartialOrdering, - SugaredBuilder, CanonicalBuilder)) { + IsDeduced, SugaredBuilder, + CanonicalBuilder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! Info.reset( @@ -3174,9 +3106,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( // Check whether we can actually use the default argument. if (S.CheckTemplateArgument( Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), - /*ArgumentPackIndex=*/0, SugaredBuilder, CanonicalBuilder, - Sema::CTAK_Specified, /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) { + 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! @@ -3208,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 @@ -3232,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(), @@ -3284,9 +3187,7 @@ FinishTemplateArgumentDeduction( SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, - CanonicalBuilder, IsPartialOrdering, - /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, - /*IsIncomplete=*/nullptr); + CanonicalBuilder); Result != TemplateDeductionResult::Success) return Result; @@ -3327,20 +3228,16 @@ FinishTemplateArgumentDeduction( return TemplateDeductionResult::SubstitutionFailure; } - bool MatchedPackOnParmToNonPackOnArg = false; bool ConstraintsNotSatisfied; SmallVector SugaredConvertedInstArgs, CanonicalConvertedInstArgs; if (S.CheckTemplateArgumentList( Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false, SugaredConvertedInstArgs, CanonicalConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied, - /*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg)) + /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) return ConstraintsNotSatisfied ? TemplateDeductionResult::ConstraintsNotSatisfied : TemplateDeductionResult::SubstitutionFailure; - if (MatchedPackOnParmToNonPackOnArg) - Info.setMatchedPackOnParmToNonPackOnArg(); TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -3378,6 +3275,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S); Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template)); @@ -3386,45 +3284,29 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // explicitly specified, template argument deduction fails. SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced=*/PartialOrdering, Deduced, Info, - SugaredBuilder, CanonicalBuilder, PartialOrdering, + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, + SugaredBuilder, CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr, - /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr); + /*NumAlreadyConverted=*/0U); Result != TemplateDeductionResult::Success) return Result; // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); - auto isSame = [&](unsigned I, const TemplateArgument &P, - const TemplateArgument &A) { - if (isSameTemplateArg(S.Context, P, A, PartialOrdering, - /*PackExpansionMatchesPack=*/true)) - return true; - Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); - Info.FirstArg = P; - Info.SecondArg = A; - return false; - }; for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - const TemplateArgument &P = TemplateArgs[I]; - if (P.isPackExpansion()) { - assert(I == TemplateArgs.size() - 1); - for (/**/; I != E; ++I) { - const TemplateArgument &A = CanonicalBuilder[I]; - if (A.getKind() == TemplateArgument::Pack) { - for (const TemplateArgument &Ai : A.getPackAsArray()) - if (!isSame(I, P, Ai)) - return TemplateDeductionResult::NonDeducedMismatch; - } else if (!isSame(I, P, A)) { - return TemplateDeductionResult::NonDeducedMismatch; - } - } - break; - } - if (!isSame(I, P, CanonicalBuilder[I])) + TemplateArgument InstArg = CanonicalBuilder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering, + /*PackExpansionMatchesPack=*/true)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; return TemplateDeductionResult::NonDeducedMismatch; + } } + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + if (!PartialOrdering) { if (auto Result = CheckDeducedArgumentConstraints( S, Template, SugaredBuilder, CanonicalBuilder, Info); @@ -3445,6 +3327,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S); Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD)); @@ -3453,15 +3336,20 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // explicitly specified, template argument deduction fails. SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, TD, /*IsDeduced=*/false, Deduced, Info, SugaredBuilder, - CanonicalBuilder, /*PartialOrdering=*/false, - /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, - /*IsIncomplete=*/nullptr); + S, TD, /*IsPartialOrdering=*/false, Deduced, Info, SugaredBuilder, + CanonicalBuilder); + Result != TemplateDeductionResult::Success) + return Result; + + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + + if (auto Result = CheckDeducedArgumentConstraints(S, TD, SugaredBuilder, + CanonicalBuilder, Info); Result != TemplateDeductionResult::Success) return Result; - return ::CheckDeducedArgumentConstraints(S, TD, SugaredBuilder, - CanonicalBuilder, Info); + return TemplateDeductionResult::Success; } /// Perform template argument deduction to determine whether the given template @@ -3508,20 +3396,16 @@ DeduceTemplateArguments(Sema &S, T *Partial, if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + TemplateDeductionResult Result; S.runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(S, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info); }); - - if (Result != TemplateDeductionResult::Success) - return Result; - - if (Trap.hasErrorOccurred()) - return TemplateDeductionResult::SubstitutionFailure; - - return TemplateDeductionResult::Success; + return Result; } TemplateDeductionResult @@ -3577,18 +3461,14 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(*this, TD, Deduced, Info); }); - - if (Result != TemplateDeductionResult::Success) - return Result; - - if (Trap.hasErrorOccurred()) - return TemplateDeductionResult::SubstitutionFailure; - - return TemplateDeductionResult::Success; + return Result; } /// Determine whether the given type T is a simple-template-id type. @@ -3994,8 +3874,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs, - bool PartialOverloading, bool PartialOrdering, - llvm::function_ref CheckNonDependent) { + bool PartialOverloading, llvm::function_ref CheckNonDependent) { // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); @@ -4018,10 +3897,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( bool IsIncomplete = false; SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - *this, FunctionTemplate, /*IsDeduced=*/true, Deduced, Info, - SugaredBuilder, CanonicalBuilder, PartialOrdering, - CurrentInstantiationScope, NumExplicitlySpecified, - PartialOverloading ? &IsIncomplete : nullptr); + *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, + SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, + NumExplicitlySpecified, PartialOverloading ? &IsIncomplete : nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4179,11 +4057,10 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // keep track of these diagnostics. They'll be emitted if this specialization // is actually used. if (Info.diag_begin() != Info.diag_end()) { - SuppressedDiagnosticsMap::iterator - Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl()); - if (Pos == SuppressedDiagnostics.end()) - SuppressedDiagnostics[Specialization->getCanonicalDecl()] - .append(Info.diag_begin(), Info.diag_end()); + auto [Pos, Inserted] = + SuppressedDiagnostics.try_emplace(Specialization->getCanonicalDecl()); + if (Inserted) + Pos->second.append(Info.diag_begin(), Info.diag_end()); } return TemplateDeductionResult::Success; @@ -4553,8 +4430,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, bool PartialOverloading, bool AggregateDeductionCandidate, - bool PartialOrdering, QualType ObjectType, - Expr::Classification ObjectClassification, + QualType ObjectType, Expr::Classification ObjectClassification, llvm::function_ref)> CheckNonDependent) { if (FunctionTemplate->isInvalidDecl()) return TemplateDeductionResult::Invalid; @@ -4769,8 +4645,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( runWithSufficientStackSpace(Info.getLocation(), [&] { Result = FinishTemplateArgumentDeduction( FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - &OriginalCallArgs, PartialOverloading, PartialOrdering, - [&, CallingCtx]() { + &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() { ContextRAII SavedContext(*this, CallingCtx); return CheckNonDependent(ParamTypesForArgChecking); }); @@ -4882,10 +4757,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = FinishTemplateArgumentDeduction( - FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false, - /*PartialOrdering=*/true); + Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, + Specialization, Info); }); if (Result != TemplateDeductionResult::Success) return Result; @@ -5065,10 +4939,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionDecl *ConversionSpecialized = nullptr; TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = FinishTemplateArgumentDeduction( - ConversionTemplate, Deduced, 0, ConversionSpecialized, Info, - &OriginalCallArgs, /*PartialOverloading=*/false, - /*PartialOrdering=*/false); + Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + ConversionSpecialized, Info, + &OriginalCallArgs); }); Specialization = cast_or_null(ConversionSpecialized); return Result; @@ -5645,8 +5518,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( S, FTD, /*IsDeduced=*/true, Deduced, Info, SugaredBuilder, - CanonicalBuilder, /*PartialOrdering=*/true, - /*CurrentInstantiationScope=*/nullptr, + CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, &IsIncomplete); Result != TemplateDeductionResult::Success) return Result; @@ -6236,23 +6108,14 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, return false; const auto *TST1 = cast(T1); - - Sema::SFINAETrap Trap(S); - - TemplateDeductionResult Result; + bool AtLeastAsSpecialized; S.runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = ::FinishTemplateArgumentDeduction( - S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced, - Info); + AtLeastAsSpecialized = + FinishTemplateArgumentDeduction( + S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), + Deduced, Info) == TemplateDeductionResult::Success; }); - - if (Result != TemplateDeductionResult::Success) - return false; - - if (Trap.hasErrorOccurred()) - return false; - - return true; + return AtLeastAsSpecialized; } namespace { @@ -6490,9 +6353,8 @@ bool Sema::isMoreSpecializedThanPrimary( } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg, - const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, - bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg) { + TemplateParameterList *P, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced) { // C++1z [temp.arg.template]p4: (DR 150) // A template template-parameter P is at least as specialized as a // template template-argument A if, given the following rewrite to two @@ -6504,12 +6366,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // TemplateParameterList *A = AArg->getTemplateParameters(); - Sema::InstantiatingTemplate Inst( - *this, ArgLoc, Sema::InstantiatingTemplate::PartialOrderingTTP(), PArg, - SourceRange(P->getTemplateLoc(), P->getRAngleLoc())); - if (Inst.isInvalid()) - return false; - // Given an invented class template X with the template parameter list of // A (including default arguments): // - Each function template has a single function parameter whose type is @@ -6524,6 +6380,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // templates. SmallVector PArgs; { + SFINAETrap Trap(*this); + Context.getInjectedTemplateArgs(P, PArgs); TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); @@ -6543,17 +6401,18 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // C++1z [temp.arg.template]p3: // If the rewrite produces an invalid type, then P is not at least as // specialized as A. - SmallVector CanonicalPArgs; - if (CheckTemplateArgumentList( - AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs, - /*UpdateArgsWithConversions=*/true, - /*ConstraintsNotSatisfied=*/nullptr, - /*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg)) + SmallVector SugaredPArgs; + if (CheckTemplateArgumentList(AArg, Loc, PArgList, DefaultArgs, false, + SugaredPArgs, PArgs, + /*UpdateArgsWithConversions=*/true, + /*ConstraintsNotSatisfied=*/nullptr, + /*PartialOrderTTP=*/true) || + Trap.hasErrorOccurred()) return false; } // Determine whether P1 is at least as specialized as P2. - TemplateDeductionInfo Info(ArgLoc, A->getDepth()); + TemplateDeductionInfo Info(Loc, A->getDepth()); SmallVector Deduced; Deduced.resize(A->size()); @@ -6568,92 +6427,29 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // be inverted between Ps and As. On non-deduced context, matching needs to // happen both ways, according to [temp.arg.template]p3, but this is // currently implemented as a special case elsewhere. - switch (::DeduceTemplateArguments( - *this, A, AArgs, PArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true, - PartialOrdering ? PackFold::ArgumentToParameter : PackFold::Both, - /*HasDeducedAnyParam=*/nullptr)) { - case clang::TemplateDeductionResult::Success: - if (MatchedPackOnParmToNonPackOnArg && - Info.hasMatchedPackOnParmToNonPackOnArg()) - *MatchedPackOnParmToNonPackOnArg = true; - break; - - case TemplateDeductionResult::MiscellaneousDeductionFailure: - Diag(AArg->getLocation(), diag::err_template_param_list_different_arity) - << (A->size() > P->size()) << /*isTemplateTemplateParameter=*/true - << SourceRange(A->getTemplateLoc(), P->getRAngleLoc()); - return false; - case TemplateDeductionResult::NonDeducedMismatch: - Diag(AArg->getLocation(), diag::err_non_deduced_mismatch) - << Info.FirstArg << Info.SecondArg; - return false; - case TemplateDeductionResult::Inconsistent: - Diag(getAsNamedDecl(Info.Param)->getLocation(), - diag::err_inconsistent_deduction) - << Info.FirstArg << Info.SecondArg; - return false; - case TemplateDeductionResult::AlreadyDiagnosed: + if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false, + /*PartialOrdering=*/true, + IsDeduced ? PackFold::ArgumentToParameter + : PackFold::ParameterToArgument, + /*HasDeducedAnyParam=*/nullptr) != + TemplateDeductionResult::Success) return false; - // None of these should happen for a plain deduction. - case TemplateDeductionResult::Invalid: - case TemplateDeductionResult::InstantiationDepth: - case TemplateDeductionResult::Incomplete: - case TemplateDeductionResult::IncompletePack: - case TemplateDeductionResult::Underqualified: - case TemplateDeductionResult::SubstitutionFailure: - case TemplateDeductionResult::DeducedMismatch: - case TemplateDeductionResult::DeducedMismatchNested: - case TemplateDeductionResult::TooManyArguments: - case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: - case TemplateDeductionResult::NonDependentConversionFailure: - case TemplateDeductionResult::ConstraintsNotSatisfied: - case TemplateDeductionResult::CUDATargetMismatch: - llvm_unreachable("Unexpected Result"); - } - SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); + Sema::InstantiatingTemplate Inst(*this, Info.getLocation(), AArg, DeducedArgs, + Info); + if (Inst.isInvalid()) + return false; - TemplateDeductionResult TDK; + bool AtLeastAsSpecialized; runWithSufficientStackSpace(Info.getLocation(), [&] { - TDK = ::FinishTemplateArgumentDeduction( - *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info); + AtLeastAsSpecialized = + ::FinishTemplateArgumentDeduction( + *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info) == + TemplateDeductionResult::Success; }); - switch (TDK) { - case TemplateDeductionResult::Success: - return true; - - // It doesn't seem possible to get a non-deduced mismatch when partial - // ordering TTPs. - case TemplateDeductionResult::NonDeducedMismatch: - llvm_unreachable("Unexpected NonDeducedMismatch"); - - // Substitution failures should have already been diagnosed. - case TemplateDeductionResult::AlreadyDiagnosed: - case TemplateDeductionResult::SubstitutionFailure: - case TemplateDeductionResult::InstantiationDepth: - return false; - - // None of these should happen when just converting deduced arguments. - case TemplateDeductionResult::Invalid: - case TemplateDeductionResult::Incomplete: - case TemplateDeductionResult::IncompletePack: - case TemplateDeductionResult::Inconsistent: - case TemplateDeductionResult::Underqualified: - case TemplateDeductionResult::DeducedMismatch: - case TemplateDeductionResult::DeducedMismatchNested: - case TemplateDeductionResult::TooManyArguments: - case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: - case TemplateDeductionResult::NonDependentConversionFailure: - case TemplateDeductionResult::ConstraintsNotSatisfied: - case TemplateDeductionResult::MiscellaneousDeductionFailure: - case TemplateDeductionResult::CUDATargetMismatch: - llvm_unreachable("Unexpected Result"); - } - llvm_unreachable("Unexpected TDK"); + return AtLeastAsSpecialized; } namespace { diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 2d3e58548fb7ac2c7e27d5bc66977fb429d04aef..3a87128a7db0fa23995ace8967083c8a3a81496f 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 2f60c0beb22e73e68d0599f7a46728b4ef62fa3c..8c7f694c09042e6b1f515638d1fa1a3e2500b0e2 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,396 @@ 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( - TSTy->getTemplateName().getAsTemplateDecl(), 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?"); + + 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 (Innermost) + AddInnermostTemplateArguments(TATD); + else if (ForConstraintInstantiation) + AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(), + /*Final=*/false); + + return UseNextDecl(TATD); + } -Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, - MultiLevelTemplateArgumentList &Result, - ASTContext &Context, - bool ForConstraintInstantiation) { - if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { + Decl *VisitConceptDecl(ConceptDecl *CD) { 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(CD); + + return UseNextDecl(CD); } - 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 *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()->hasMemberSpecialization()) + 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); } - // 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 *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->hasMemberSpecialization()) + return Done(); + } else { + auto *CTD = Specialized.get(); + if (CTD->hasMemberSpecialization()) + 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->hasMemberSpecialization()) + return Done(); + } else { + auto *VTD = Specialized.get(); + if (VTD->hasMemberSpecialization()) + 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