Skip to content

Commit ffc5ee0

Browse files
committed
Merge commit 8ac140f39084 from llvm git (by Younan Zhang):
[Clang][NFCI] Cleanup the fix for default function argument substitution (#104911) (This is one step towards tweaking `getTemplateInstantiationArgs()` as discussed in llvm/llvm-project#102922) We don't always substitute into default arguments while transforming a function parameter. In that case, we would preserve the uninstantiated expression until after, e.g. building up a CXXDefaultArgExpr and instantiate the expression there. For member function instantiation, this algorithm used to cause a problem in that the default argument of an out-of-line member function specialization couldn't get properly instantiated. This is because, in `getTemplateInstantiationArgs()`, we would give up visiting a function's declaration context if the function is a specialization of a member template. For example, ```cpp template <class T> struct S { template <class U> void f(T = sizeof(T)); }; template <> template <class U> void S<int>::f(int) {} ``` The default argument `sizeof(U)` that lexically appears inside the declaration would be copied to the function declaration in the class template specialization `S<int>`, as well as to the function's out-of-line definition. We use template arguments collected from the out-of-line function definition when substituting into the default arguments. We would therefore give up the traversal after the function, resulting in a single-level template argument of the `f` itself. However the default argument here could still reference the template parameters of the primary template, hence the error. In fact, this is similar to constraint checking in some respects: we actually want the "whole" template arguments relative to the primary template, not those relative to the function definition. So this patch adds another flag to indicate `getTemplateInstantiationArgs()` for that. This patch also consolidates the tests for default arguments and removes some unnecessary tests. This fixes a crash or assertion failure while building tests for the devel/hpx port. PR: 288352 MFC after: 3 days
1 parent 3717484 commit ffc5ee0

File tree

3 files changed

+22
-20
lines changed

3 files changed

+22
-20
lines changed

contrib/llvm-project/clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13052,12 +13052,19 @@ class Sema final : public SemaBase {
1305213052
/// ForConstraintInstantiation indicates we should continue looking when
1305313053
/// encountering a lambda generic call operator, and continue looking for
1305413054
/// arguments on an enclosing class template.
13055+
///
13056+
/// \param SkipForSpecialization when specified, any template specializations
13057+
/// in a traversal would be ignored.
13058+
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
13059+
/// when encountering a specialized member function template, rather than
13060+
/// returning immediately.
1305513061
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
1305613062
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
1305713063
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
1305813064
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
1305913065
bool ForConstraintInstantiation = false,
13060-
bool SkipForSpecialization = false);
13066+
bool SkipForSpecialization = false,
13067+
bool ForDefaultArgumentSubstitution = false);
1306113068

1306213069
/// RAII object to handle the state changes required to synthesize
1306313070
/// a function body.

contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
269269
Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
270270
MultiLevelTemplateArgumentList &Result,
271271
const FunctionDecl *Pattern, bool RelativeToPrimary,
272-
bool ForConstraintInstantiation) {
272+
bool ForConstraintInstantiation,
273+
bool ForDefaultArgumentSubstitution) {
273274
// Add template arguments from a function template specialization.
274275
if (!RelativeToPrimary &&
275276
Function->getTemplateSpecializationKindForInstantiation() ==
@@ -299,7 +300,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
299300
// If this function was instantiated from a specialized member that is
300301
// a function template, we're done.
301302
assert(Function->getPrimaryTemplate() && "No function template?");
302-
if (Function->getPrimaryTemplate()->isMemberSpecialization())
303+
if (!ForDefaultArgumentSubstitution &&
304+
Function->getPrimaryTemplate()->isMemberSpecialization())
303305
return Response::Done();
304306

305307
// If this function is a generic lambda specialization, we are done.
@@ -465,7 +467,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
465467
const NamedDecl *ND, const DeclContext *DC, bool Final,
466468
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
467469
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
468-
bool SkipForSpecialization) {
470+
bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
469471
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
470472
// Accumulate the set of template argument lists in this structure.
471473
MultiLevelTemplateArgumentList Result;
@@ -507,7 +509,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
507509
SkipForSpecialization);
508510
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
509511
R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
510-
ForConstraintInstantiation);
512+
ForConstraintInstantiation,
513+
ForDefaultArgumentSubstitution);
511514
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
512515
R = HandleRecordDecl(*this, Rec, Result, Context,
513516
ForConstraintInstantiation);
@@ -3231,7 +3234,6 @@ bool Sema::SubstDefaultArgument(
32313234
// default argument expression appears.
32323235
ContextRAII SavedContext(*this, FD);
32333236
std::unique_ptr<LocalInstantiationScope> LIS;
3234-
MultiLevelTemplateArgumentList NewTemplateArgs = TemplateArgs;
32353237

32363238
if (ForCallExpr) {
32373239
// When instantiating a default argument due to use in a call expression,
@@ -3244,19 +3246,10 @@ bool Sema::SubstDefaultArgument(
32443246
/*ForDefinition*/ false);
32453247
if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
32463248
return true;
3247-
const FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
3248-
if (PrimaryTemplate && PrimaryTemplate->isOutOfLine()) {
3249-
TemplateArgumentList *CurrentTemplateArgumentList =
3250-
TemplateArgumentList::CreateCopy(getASTContext(),
3251-
TemplateArgs.getInnermost());
3252-
NewTemplateArgs = getTemplateInstantiationArgs(
3253-
FD, FD->getDeclContext(), /*Final=*/false,
3254-
CurrentTemplateArgumentList->asArray(), /*RelativeToPrimary=*/true);
3255-
}
32563249
}
32573250

32583251
runWithSufficientStackSpace(Loc, [&] {
3259-
Result = SubstInitializer(PatternExpr, NewTemplateArgs,
3252+
Result = SubstInitializer(PatternExpr, TemplateArgs,
32603253
/*DirectInit*/ false);
32613254
});
32623255
}

contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4659,10 +4659,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
46594659
//
46604660
// template<typename T>
46614661
// A<T> Foo(int a = A<T>::FooImpl());
4662-
MultiLevelTemplateArgumentList TemplateArgs =
4663-
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
4664-
/*Final=*/false, /*Innermost=*/std::nullopt,
4665-
/*RelativeToPrimary=*/true);
4662+
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
4663+
FD, FD->getLexicalDeclContext(),
4664+
/*Final=*/false, /*Innermost=*/std::nullopt,
4665+
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
4666+
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
4667+
/*ForDefaultArgumentSubstitution=*/true);
46664668

46674669
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
46684670
return true;

0 commit comments

Comments
 (0)