Skip to content

Commit 4b8b70a

Browse files
authored
[Clang] Fix dependence handling of nttp for variable templates (#69075)
The dependence of a template argument is not only determined by the argument itself, but also by the type of the template parameter: > Furthermore, a non-type [template-argument](https://eel.is/c++draft/temp.names#nt:template-argument) is dependent if the corresponding non-type [template-parameter](https://eel.is/c++draft/temp.param#nt:template-parameter) is of reference or pointer type and the [template-argument](https://eel.is/c++draft/temp.names#nt:template-argument) designates or points to a member of the current instantiation or a member of a dependent type[.](https://eel.is/c++draft/temp.dep#temp-3.sentence-1) For example: ```cpp struct A{}; template <const A& T> const A JoinStringViews = T; template <int V> class Builder { public: static constexpr A Equal{}; static constexpr auto Val = JoinStringViews<Equal>; }; ``` The constant expression `Equal` is not dependent, but because the type of the template parameter is a reference type and `Equal` is a member of the current instantiation, the template argument of `JoinStringViews<Equal>` is actually dependent, which makes `JoinStringViews<Equal>` dependent. When a template-id of a variable template is dependent, `CheckVarTemplateId` will return an `UnresolvedLookupExpr`, but `UnresolvedLookupExpr` calculates dependence by template arguments only (the `ConstantExpr` `Equal` here), which is not dependent. This causes type deduction to think that `JoinStringViews<Equal>` is `OverloadTy` and treat it as a function template, which is clearly wrong. This PR adds a `KnownDependent` parameter to the constructor of `UnresolvedLookupExpr`. After canonicalization, if `CanonicalConverted` contains any dependent argument, `KnownDependent` is set to `true`. This fixes the dependence calculation of `UnresolvedLookupExpr` for dependent variable templates. Fixes #65153 .
1 parent 12a731b commit 4b8b70a

File tree

7 files changed

+46
-21
lines changed

7 files changed

+46
-21
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ Bug Fixes to C++ Support
516516
rather than prefer the non-templated constructor as specified in
517517
[standard.group]p3.
518518

519+
- Fixed a crash caused by incorrect handling of dependence on variable templates
520+
with non-type template parameters of reference type. Fixes:
521+
(`#65153 <https://github.com/llvm/llvm-project/issues/65153>`_)
522+
519523
Bug Fixes to AST Handling
520524
^^^^^^^^^^^^^^^^^^^^^^^^^
521525
- Fixed an import failure of recursive friend class template.

clang/include/clang/AST/ExprCXX.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,7 +3191,8 @@ class UnresolvedLookupExpr final
31913191
const DeclarationNameInfo &NameInfo, bool RequiresADL,
31923192
bool Overloaded,
31933193
const TemplateArgumentListInfo *TemplateArgs,
3194-
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
3194+
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
3195+
bool KnownDependent);
31953196

31963197
UnresolvedLookupExpr(EmptyShell Empty, unsigned NumResults,
31973198
bool HasTemplateKWAndArgsInfo);
@@ -3211,12 +3212,15 @@ class UnresolvedLookupExpr final
32113212
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
32123213
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
32133214

3215+
// After canonicalization, there may be dependent template arguments in
3216+
// CanonicalConverted But none of Args is dependent. When any of
3217+
// CanonicalConverted dependent, KnownDependent is true.
32143218
static UnresolvedLookupExpr *
32153219
Create(const ASTContext &Context, CXXRecordDecl *NamingClass,
32163220
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
32173221
const DeclarationNameInfo &NameInfo, bool RequiresADL,
32183222
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
3219-
UnresolvedSetIterator End);
3223+
UnresolvedSetIterator End, bool KnownDependent);
32203224

32213225
static UnresolvedLookupExpr *CreateEmpty(const ASTContext &Context,
32223226
unsigned NumResults,

clang/lib/AST/ASTImporter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8395,10 +8395,13 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
83958395
if (!ToTemplateKeywordLocOrErr)
83968396
return ToTemplateKeywordLocOrErr.takeError();
83978397

8398+
const bool KnownDependent =
8399+
(E->getDependence() & ExprDependence::TypeValue) ==
8400+
ExprDependence::TypeValue;
83988401
return UnresolvedLookupExpr::Create(
83998402
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
84008403
*ToTemplateKeywordLocOrErr, ToNameInfo, E->requiresADL(), &ToTAInfo,
8401-
ToDecls.begin(), ToDecls.end());
8404+
ToDecls.begin(), ToDecls.end(), KnownDependent);
84028405
}
84038406

84048407
return UnresolvedLookupExpr::Create(

clang/lib/AST/ExprCXX.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,10 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(
354354
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
355355
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
356356
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
357-
UnresolvedSetIterator End)
357+
UnresolvedSetIterator End, bool KnownDependent)
358358
: OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
359-
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End, false,
360-
false, false),
359+
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
360+
KnownDependent, false, false),
361361
NamingClass(NamingClass) {
362362
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
363363
UnresolvedLookupExprBits.Overloaded = Overloaded;
@@ -380,25 +380,25 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
380380
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
381381
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
382382
SourceLocation(), NameInfo, RequiresADL,
383-
Overloaded, nullptr, Begin, End);
383+
Overloaded, nullptr, Begin, End, false);
384384
}
385385

386386
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
387387
const ASTContext &Context, CXXRecordDecl *NamingClass,
388388
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
389389
const DeclarationNameInfo &NameInfo, bool RequiresADL,
390390
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
391-
UnresolvedSetIterator End) {
391+
UnresolvedSetIterator End, bool KnownDependent) {
392392
assert(Args || TemplateKWLoc.isValid());
393393
unsigned NumResults = End - Begin;
394394
unsigned NumTemplateArgs = Args ? Args->size() : 0;
395395
unsigned Size =
396396
totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
397397
TemplateArgumentLoc>(NumResults, 1, NumTemplateArgs);
398398
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
399-
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
400-
TemplateKWLoc, NameInfo, RequiresADL,
401-
/*Overloaded*/ true, Args, Begin, End);
399+
return new (Mem) UnresolvedLookupExpr(
400+
Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL,
401+
/*Overloaded=*/true, Args, Begin, End, KnownDependent);
402402
}
403403

404404
UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty(

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,8 +1299,9 @@ static bool checkTupleLikeDecomposition(Sema &S,
12991299
// in the associated namespaces.
13001300
Expr *Get = UnresolvedLookupExpr::Create(
13011301
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
1302-
DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args,
1303-
UnresolvedSetIterator(), UnresolvedSetIterator());
1302+
DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/ true, &Args,
1303+
UnresolvedSetIterator(), UnresolvedSetIterator(),
1304+
/*KnownDependent=*/false);
13041305

13051306
Expr *Arg = E.get();
13061307
E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4982,7 +4982,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
49824982
return ExprError();
49834983
}
49844984
}
4985-
4985+
bool KnownDependent = false;
49864986
// In C++1y, check variable template ids.
49874987
if (R.getAsSingle<VarTemplateDecl>()) {
49884988
ExprResult Res = CheckVarTemplateId(SS, R.getLookupNameInfo(),
@@ -4991,6 +4991,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
49914991
if (Res.isInvalid() || Res.isUsable())
49924992
return Res;
49934993
// Result is dependent. Carry on to build an UnresolvedLookupEpxr.
4994+
KnownDependent = true;
49944995
}
49954996

49964997
if (R.getAsSingle<ConceptDecl>()) {
@@ -5002,13 +5003,10 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
50025003
// We don't want lookup warnings at this point.
50035004
R.suppressDiagnostics();
50045005

5005-
UnresolvedLookupExpr *ULE
5006-
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
5007-
SS.getWithLocInContext(Context),
5008-
TemplateKWLoc,
5009-
R.getLookupNameInfo(),
5010-
RequiresADL, TemplateArgs,
5011-
R.begin(), R.end());
5006+
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
5007+
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
5008+
TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs,
5009+
R.begin(), R.end(), KnownDependent);
50125010

50135011
return ULE;
50145012
}

clang/test/SemaTemplate/dependent-expr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,18 @@ namespace BindingInStmtExpr {
165165
using U = decltype(num_bindings<T>()); // expected-note {{previous}}
166166
using U = N<3>; // expected-error-re {{type alias redefinition with different types ('N<3>' vs {{.*}}N<2>}}
167167
}
168+
169+
namespace PR65153 {
170+
struct A{};
171+
172+
template <const A& T>
173+
const A JoinStringViews = T;
174+
175+
template <int V>
176+
class Builder {
177+
public:
178+
static constexpr A Equal{};
179+
// no crash here
180+
static constexpr auto Val = JoinStringViews<Equal>;
181+
};
182+
} // namespace PR65153

0 commit comments

Comments
 (0)