diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 34 | ||||
-rw-r--r-- | clang/lib/AST/FormatString.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/Interp/Interp.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/Interp/Interp.h | 6 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/RISCV.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/MinGW.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenACC.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 52 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 94 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 25 |
12 files changed, 170 insertions, 128 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9ffae72..5e5570b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2034,23 +2034,25 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { return ToDCOrErr.takeError(); } - DeclContext *ToDC = *ToDCOrErr; - // Remove all declarations, which may be in wrong order in the - // lexical DeclContext and then add them in the proper order. - for (auto *D : FromDC->decls()) { - if (!MightNeedReordering(D)) - continue; + if (const auto *FromRD = dyn_cast<RecordDecl>(FromDC)) { + DeclContext *ToDC = *ToDCOrErr; + // Remove all declarations, which may be in wrong order in the + // lexical DeclContext and then add them in the proper order. + for (auto *D : FromRD->decls()) { + if (!MightNeedReordering(D)) + continue; - assert(D && "DC contains a null decl"); - if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) { - // Remove only the decls which we successfully imported. - assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); - // Remove the decl from its wrong place in the linked list. - ToDC->removeDecl(ToD); - // Add the decl to the end of the linked list. - // This time it will be at the proper place because the enclosing for - // loop iterates in the original (good) order of the decls. - ToDC->addDeclInternal(ToD); + assert(D && "DC contains a null decl"); + if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) { + // Remove only the decls which we successfully imported. + assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); + // Remove the decl from its wrong place in the linked list. + ToDC->removeDecl(ToD); + // Add the decl to the end of the linked list. + // This time it will be at the proper place because the enclosing for + // loop iterates in the original (good) order of the decls. + ToDC->addDeclInternal(ToD); + } } } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index e0c9e18..c5d14b4 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -488,7 +488,6 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return NoMatchPromotionTypeConfusion; break; case BuiltinType::Half: - case BuiltinType::Float16: case BuiltinType::Float: if (T == C.DoubleTy) return MatchPromotion; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index a82d1c3..21ea250 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -290,10 +290,10 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, } bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckDummy(S, OpPC, Ptr)) - return false; if (!CheckLive(S, OpPC, Ptr, AK_Read)) return false; + if (!CheckDummy(S, OpPC, Ptr)) + return false; if (!CheckExtern(S, OpPC, Ptr)) return false; if (!CheckRange(S, OpPC, Ptr, AK_Read)) diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 828d4ea..c05dea0 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1813,9 +1813,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop<T>(); const Pointer &Ptr = S.Stk.peek<Pointer>(); - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) return false; @@ -1843,9 +1840,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop<T>(); const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) return false; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 6bc57a8..59ae12e 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -237,22 +237,15 @@ ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { static std::vector<std::string> collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) { - auto ParseResult = - llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesNeedOverride); - - if (!ParseResult) { - consumeError(ParseResult.takeError()); - return std::vector<std::string>(); - } - - std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector(); - std::vector<std::string> NonISAExtFeatureVec; + auto IsNonISAExtFeature = [](const std::string &Feature) { + assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); + StringRef Ext = StringRef(Feature).drop_front(); // drop the +/- + return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); + }; llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec), - [&](const std::string &Feat) { - return !llvm::is_contained(ImpliedFeatures, Feat); - }); + IsNonISAExtFeature); return NonISAExtFeatureVec; } diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 65512f1..18fc9d4 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -471,12 +471,23 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple, return make_error_code(std::errc::no_such_file_or_directory); } +static bool looksLikeMinGWSysroot(const std::string &Directory) { + StringRef Sep = llvm::sys::path::get_separator(); + if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h")) + return false; + if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a")) + return false; + return true; +} + toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir())); // The sequence for detecting a sysroot here should be kept in sync with // the testTriple function below. llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple()); @@ -487,13 +498,17 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot( getDriver(), LiteralTriple, getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); + // If the install base of Clang seems to have mingw sysroot files directly + // in the toplevel include and lib directories, use this as base instead of + // looking for a triple prefixed GCC in the path. + else if (looksLikeMinGWSysroot(InstallBase)) + Base = InstallBase; else if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else - Base = std::string( - llvm::sys::path::parent_path(getDriver().getInstalledDir())); + Base = InstallBase; Base += llvm::sys::path::get_separator(); findGccLibDir(LiteralTriple); @@ -778,9 +793,15 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple, if (D.SysRoot.size()) return true; llvm::Triple LiteralTriple = getLiteralTriple(D, Triple); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(D.getInstalledDir())); if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName)) return true; + // If the install base itself looks like a mingw sysroot, we'll use that + // - don't use any potentially unrelated gcc to influence what triple to use. + if (looksLikeMinGWSysroot(InstallBase)) + return false; if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple)) return true; // If we neither found a colocated sysroot or a matching gcc executable, diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 3ac3aa3c..8b43438 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5151,6 +5151,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return true; if (Left.IsUnterminatedLiteral) return true; + // FIXME: Breaking after newlines seems useful in general. Turn this into an + // option and recognize more cases like endl etc, and break independent of + // what comes after operator lessless. + if (Right.is(tok::lessless) && Right.Next && + Right.Next->is(tok::string_literal) && Left.is(tok::string_literal) && + Left.TokenText.ends_with("\\n\"")) { + return true; + } if (Right.is(TT_RequiresClause)) { switch (Style.RequiresClausePosition) { case FormatStyle::RCPS_OwnLine: diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index ea5d13d..42d55d0 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -984,7 +984,9 @@ static void inferFrameworkLink(Module *Mod) { assert(!Mod->isSubFramework() && "Can only infer linking for top-level frameworks"); - Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name, + StringRef FrameworkName(Mod->Name); + FrameworkName.consume_back("_Private"); + Mod->LinkLibraries.push_back(Module::LinkLibrary(FrameworkName.str(), /*IsFramework=*/true)); } diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 94c3d0c..84e994e 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -80,6 +80,10 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { if (Tok.is(tok::kw_default)) return OpenACCClauseKind::Default; + // if is also a keyword, make sure we parse it correctly. + if (Tok.is(tok::kw_if)) + return OpenACCClauseKind::If; + if (!Tok.is(tok::identifier)) return OpenACCClauseKind::Invalid; @@ -88,6 +92,7 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { .Case("auto", OpenACCClauseKind::Auto) .Case("default", OpenACCClauseKind::Default) .Case("finalize", OpenACCClauseKind::Finalize) + .Case("if", OpenACCClauseKind::If) .Case("if_present", OpenACCClauseKind::IfPresent) .Case("independent", OpenACCClauseKind::Independent) .Case("nohost", OpenACCClauseKind::NoHost) @@ -324,7 +329,7 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { } bool ClauseHasRequiredParens(OpenACCClauseKind Kind) { - return Kind == OpenACCClauseKind::Default; + return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If; } bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { @@ -356,6 +361,19 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { break; } + case OpenACCClauseKind::If: { + // FIXME: It isn't clear if the spec saying 'condition' means the same as + // it does in an if/while/etc (See ParseCXXCondition), however as it was + // written with Fortran/C in mind, we're going to assume it just means an + // 'expression evaluating to boolean'. + ExprResult CondExpr = + P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); + // An invalid expression can be just about anything, so just give up on + // this clause list. + if (CondExpr.isInvalid()) + return true; + break; + } default: llvm_unreachable("Not a required parens type?"); } @@ -372,8 +390,10 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { // However, they all are named with a single-identifier (or auto/default!) // token, followed in some cases by either braces or parens. bool ParseOpenACCClause(Parser &P) { - if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto, tok::kw_default)) - return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + // A number of clause names are actually keywords, so accept a keyword that + // can be converted to a name. + if (expectIdentifierOrKeyword(P)) + return true; OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e469e42..408ee5f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10377,11 +10377,6 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } -static bool NarrowingErrs(const LangOptions &L) { - return L.CPlusPlus11 && - (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015)); -} - static void DiagnoseNarrowingInInitList(Sema &S, const ImplicitConversionSequence &ICS, QualType PreNarrowingType, @@ -10402,6 +10397,19 @@ static void DiagnoseNarrowingInInitList(Sema &S, return; } + auto MakeDiag = [&](bool IsConstRef, unsigned DefaultDiagID, + unsigned ConstRefDiagID, unsigned WarnDiagID) { + unsigned DiagID; + auto &L = S.getLangOpts(); + if (L.CPlusPlus11 && + (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015))) + DiagID = IsConstRef ? ConstRefDiagID : DefaultDiagID; + else + DiagID = WarnDiagID; + return S.Diag(PostInit->getBeginLoc(), DiagID) + << PostInit->getSourceRange(); + }; + // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. APValue ConstantValue; QualType ConstantType; @@ -10417,13 +10425,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, // narrowing conversion even if the value is a constant and can be // represented exactly as an integer. QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_type_narrowing - : diag::ext_init_list_type_narrowing_const_reference) - : diag::warn_init_list_type_narrowing) - << PostInit->getSourceRange() + MakeDiag(T != EntityType, diag::ext_init_list_type_narrowing, + diag::ext_init_list_type_narrowing_const_reference, + diag::warn_init_list_type_narrowing) << PreNarrowingType.getLocalUnqualifiedType() << T.getLocalUnqualifiedType(); break; @@ -10431,14 +10435,10 @@ static void DiagnoseNarrowingInInitList(Sema &S, case NK_Constant_Narrowing: { // A constant value was narrowed. - QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_constant_narrowing - : diag::ext_init_list_constant_narrowing_const_reference) - : diag::warn_init_list_constant_narrowing) - << PostInit->getSourceRange() + MakeDiag(EntityType.getNonReferenceType() != EntityType, + diag::ext_init_list_constant_narrowing, + diag::ext_init_list_constant_narrowing_const_reference, + diag::warn_init_list_constant_narrowing) << ConstantValue.getAsString(S.getASTContext(), ConstantType) << EntityType.getNonReferenceType().getLocalUnqualifiedType(); break; @@ -10446,14 +10446,10 @@ static void DiagnoseNarrowingInInitList(Sema &S, case NK_Variable_Narrowing: { // A variable's value may have been narrowed. - QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_variable_narrowing - : diag::ext_init_list_variable_narrowing_const_reference) - : diag::warn_init_list_variable_narrowing) - << PostInit->getSourceRange() + MakeDiag(EntityType.getNonReferenceType() != EntityType, + diag::ext_init_list_variable_narrowing, + diag::ext_init_list_variable_narrowing_const_reference, + diag::warn_init_list_variable_narrowing) << PreNarrowingType.getLocalUnqualifiedType() << EntityType.getNonReferenceType().getLocalUnqualifiedType(); break; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9fb7671..e6c267b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1259,6 +1259,43 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, if ((OldTemplate == nullptr) != (NewTemplate == nullptr)) return true; + if (NewTemplate) { + // C++ [temp.over.link]p4: + // The signature of a function template consists of its function + // signature, its return type and its template parameter list. The names + // of the template parameters are significant only for establishing the + // relationship between the template parameters and the rest of the + // signature. + // + // We check the return type and template parameter lists for function + // templates first; the remaining checks follow. + bool SameTemplateParameterList = SemaRef.TemplateParameterListsAreEqual( + NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, + OldTemplate->getTemplateParameters(), false, Sema::TPL_TemplateMatch); + bool SameReturnType = SemaRef.Context.hasSameType( + Old->getDeclaredReturnType(), New->getDeclaredReturnType()); + // FIXME(GH58571): Match template parameter list even for non-constrained + // template heads. This currently ensures that the code prior to C++20 is + // not newly broken. + bool ConstraintsInTemplateHead = + NewTemplate->getTemplateParameters()->hasAssociatedConstraints() || + OldTemplate->getTemplateParameters()->hasAssociatedConstraints(); + // C++ [namespace.udecl]p11: + // The set of declarations named by a using-declarator that inhabits a + // class C does not include member functions and member function + // templates of a base class that "correspond" to (and thus would + // conflict with) a declaration of a function or function template in + // C. + // Comparing return types is not required for the "correspond" check to + // decide whether a member introduced by a shadow declaration is hidden. + if (UseMemberUsingDeclRules && ConstraintsInTemplateHead && + !SameTemplateParameterList) + return true; + if (!UseMemberUsingDeclRules && + (!SameTemplateParameterList || !SameReturnType)) + return true; + } + // Is the function New an overload of the function Old? QualType OldQType = SemaRef.Context.getCanonicalType(Old->getType()); QualType NewQType = SemaRef.Context.getCanonicalType(New->getType()); @@ -1410,43 +1447,6 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, } } - if (NewTemplate) { - // C++ [temp.over.link]p4: - // The signature of a function template consists of its function - // signature, its return type and its template parameter list. The names - // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the - // signature. - // - // We check the return type and template parameter lists for function - // templates first; the remaining checks follow. - bool SameTemplateParameterList = SemaRef.TemplateParameterListsAreEqual( - NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, - OldTemplate->getTemplateParameters(), false, Sema::TPL_TemplateMatch); - bool SameReturnType = SemaRef.Context.hasSameType( - Old->getDeclaredReturnType(), New->getDeclaredReturnType()); - // FIXME(GH58571): Match template parameter list even for non-constrained - // template heads. This currently ensures that the code prior to C++20 is - // not newly broken. - bool ConstraintsInTemplateHead = - NewTemplate->getTemplateParameters()->hasAssociatedConstraints() || - OldTemplate->getTemplateParameters()->hasAssociatedConstraints(); - // C++ [namespace.udecl]p11: - // The set of declarations named by a using-declarator that inhabits a - // class C does not include member functions and member function - // templates of a base class that "correspond" to (and thus would - // conflict with) a declaration of a function or function template in - // C. - // Comparing return types is not required for the "correspond" check to - // decide whether a member introduced by a shadow declaration is hidden. - if (UseMemberUsingDeclRules && ConstraintsInTemplateHead && - !SameTemplateParameterList) - return true; - if (!UseMemberUsingDeclRules && - (!SameTemplateParameterList || !SameReturnType)) - return true; - } - if (!UseOverrideRules) { Expr *NewRC = New->getTrailingRequiresClause(), *OldRC = Old->getTrailingRequiresClause(); @@ -13994,21 +13994,19 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, OverloadCandidateSet::iterator Best; OverloadingResult OverloadResult = CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best); - FunctionDecl *FDecl = Best->Function; // Model the case with a call to a templated function whose definition // encloses the call and whose return type contains a placeholder type as if // the UnresolvedLookupExpr was type-dependent. - if (OverloadResult == OR_Success && FDecl && - FDecl->isTemplateInstantiation() && - FDecl->getReturnType()->isUndeducedType()) { - if (auto TP = FDecl->getTemplateInstantiationPattern(false)) { - if (TP->willHaveBody()) { - CallExpr *CE = - CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_PRValue, - RParenLoc, CurFPFeatureOverrides()); - result = CE; - return result; + if (OverloadResult == OR_Success) { + const FunctionDecl *FDecl = Best->Function; + if (FDecl && FDecl->isTemplateInstantiation() && + FDecl->getReturnType()->isUndeducedType()) { + if (const auto *TP = + FDecl->getTemplateInstantiationPattern(/*ForDefinition=*/false); + TP && TP->willHaveBody()) { + return CallExpr::Create(Context, Fn, Args, Context.DependentTy, + VK_PRValue, RParenLoc, CurFPFeatureOverrides()); } } } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 09dd119..7f20413 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -344,15 +344,26 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; + + if (!CurDecl) + CurDecl = Decl::castFromDeclContext(DC); + if (Innermost) { Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), Innermost->asArray(), Final); - CurDecl = Response::UseNextDecl(ND).NextDecl; + // Populate placeholder template arguments for TemplateTemplateParmDecls. + // This is essential for the case e.g. + // + // template <class> concept Concept = false; + // template <template <Concept C> class T> void foo(T<int>) + // + // where parameter C has a depth of 1 but the substituting argument `int` + // has a depth of 0. + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) + HandleDefaultTempArgIntoTempTempParam(TTP, Result); + CurDecl = Response::UseNextDecl(CurDecl).NextDecl; } - if (!ND) - CurDecl = Decl::castFromDeclContext(DC); - while (!CurDecl->isFileContextDecl()) { Response R; if (const auto *VarTemplSpec = @@ -380,10 +391,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( R = Response::ChangeDecl(CTD->getLexicalDeclContext()); } else if (!isa<DeclContext>(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); - if (CurDecl->getDeclContext()->isTranslationUnit()) { - if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { - R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); - } + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { + R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); } } else { R = HandleGenericDeclContext(CurDecl); |