Skip to content

Commit 89a5bbc

Browse files
committed
[clang] Distinguish unresolved templates in UnresolvedLookupExpr
This patch revolves around the misuse of UnresolvedLookupExpr in BuildTemplateIdExpr. Basically, we build up an UnresolvedLookupExpr not only for function overloads but for "unresolved" templates wherever we need an expression for template decls. For example, a dependent VarTemplateDecl can be wrapped with such an expression before template instantiation. (See 6170072) Also, one important thing is that UnresolvedLookupExpr uses a "canonical" QualType to describe the containing unresolved decls: a DependentTy is for dependent expressions and an OverloadTy otherwise. Therefore, this modeling for non-dependent templates leaves a problem in that the expression is marked and perceived as if describing overload functions. The consumer then expects functions for every such expression, although the fact is the reverse. Hence, we run into crashes. As to the patch, I added a new canonical type "UnresolvedTemplateTy" to model these cases. Given that we have been using this model (intentionally or accidentally) and it is pretty baked in throughout the code, I think extending the role of UnresolvedLookupExpr is reasonable. Further, I added some diagnostics for the direct occurrence of these expressions, which are supposed to be ill-formed. As a bonus, this patch also fixes some typos in the diagnostics and creates RecoveryExprs rather than nothing in the hope of a better error-recovery for clangd. Fixes #88832 Fixes #63243 Fixes #48673
1 parent f71e25b commit 89a5bbc

File tree

14 files changed

+125
-6
lines changed

14 files changed

+125
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ Bug Fixes to C++ Support
535535
- Fix a crash when deducing ``auto`` from an invalid dereference (#GH88329).
536536
- Fix a crash in requires expression with templated base class member function. Fixes (#GH84020).
537537
- Placement new initializes typedef array with correct size (#GH41441)
538+
- Fixed a misuse of ``UnresolvedLookupExpr`` for ill-formed templated expressions. Fixes (#GH48673), (#GH63243) and (#GH88832).
538539

539540
Bug Fixes to AST Handling
540541
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
11161116
CanQualType BFloat16Ty;
11171117
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
11181118
CanQualType VoidPtrTy, NullPtrTy;
1119-
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
1119+
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
1120+
UnknownAnyTy;
11201121
CanQualType BuiltinFnTy;
11211122
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
11221123
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;

clang/include/clang/AST/BuiltinTypes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
285285
// x->foo # if only contains non-static members
286286
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
287287

288+
// The type of an unresolved template. Used in UnresolvedLookupExpr.
289+
PLACEHOLDER_TYPE(UnresolvedTemplate, UnresolvedTemplateTy)
290+
288291
// The type of an expression which refers to a pseudo-object,
289292
// such as those introduced by Objective C's @property or
290293
// VS.NET's __property declarations. A placeholder type. The

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,9 @@ enum PredefinedTypeIDs {
10991099
// \brief WebAssembly reference types with auto numeration
11001100
#define WASM_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID,
11011101
#include "clang/Basic/WebAssemblyReferenceTypes.def"
1102+
1103+
/// The placeholder type for unresolved templates.
1104+
PREDEF_TYPE_UNRESOLVED_TEMPLATE,
11021105
// Sentinel value. Considered a predefined type but not useable as one.
11031106
PREDEF_TYPE_LAST_ID
11041107
};
@@ -1108,7 +1111,7 @@ enum PredefinedTypeIDs {
11081111
///
11091112
/// Type IDs for non-predefined types will start at
11101113
/// NUM_PREDEF_TYPE_IDs.
1111-
const unsigned NUM_PREDEF_TYPE_IDS = 502;
1114+
const unsigned NUM_PREDEF_TYPE_IDS = 503;
11121115

11131116
// Ensure we do not overrun the predefined types we reserved
11141117
// in the enum PredefinedTypeIDs above.

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
13061306
// Placeholder type for bound members.
13071307
InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
13081308

1309+
// Placeholder type for unresolved templates.
1310+
InitBuiltinType(UnresolvedTemplateTy, BuiltinType::UnresolvedTemplate);
1311+
13091312
// Placeholder type for pseudo-objects.
13101313
InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject);
13111314

clang/lib/AST/NSAPI.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
454454
#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
455455
#include "clang/Basic/WebAssemblyReferenceTypes.def"
456456
case BuiltinType::BoundMember:
457+
case BuiltinType::UnresolvedTemplate:
457458
case BuiltinType::Dependent:
458459
case BuiltinType::Overload:
459460
case BuiltinType::UnknownAny:

clang/lib/AST/Type.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,6 +3381,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
33813381
return "<overloaded function type>";
33823382
case BoundMember:
33833383
return "<bound member function type>";
3384+
case UnresolvedTemplate:
3385+
return "<unresolved template type>";
33843386
case PseudoObject:
33853387
return "<pseudo-object type>";
33863388
case Dependent:
@@ -4673,6 +4675,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
46734675
#include "clang/AST/BuiltinTypes.def"
46744676
return false;
46754677

4678+
case BuiltinType::UnresolvedTemplate:
46764679
// Dependent types that could instantiate to a pointer type.
46774680
case BuiltinType::Dependent:
46784681
case BuiltinType::Overload:

clang/lib/AST/TypeLoc.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
399399
case BuiltinType::NullPtr:
400400
case BuiltinType::Overload:
401401
case BuiltinType::Dependent:
402+
case BuiltinType::UnresolvedTemplate:
402403
case BuiltinType::BoundMember:
403404
case BuiltinType::UnknownAny:
404405
case BuiltinType::ARCUnbridgedCast:

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6349,6 +6349,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
63496349
#include "clang/AST/BuiltinTypes.def"
63506350
return false;
63516351

6352+
case BuiltinType::UnresolvedTemplate:
63526353
// We cannot lower out overload sets; they might validly be resolved
63536354
// by the call machinery.
63546355
case BuiltinType::Overload:
@@ -21234,6 +21235,24 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
2123421235
if (!placeholderType) return E;
2123521236

2123621237
switch (placeholderType->getKind()) {
21238+
case BuiltinType::UnresolvedTemplate: {
21239+
auto *ULE = cast<UnresolvedLookupExpr>(E);
21240+
const DeclarationNameInfo &NameInfo = ULE->getNameInfo();
21241+
NestedNameSpecifierLoc Loc = ULE->getQualifierLoc();
21242+
NamedDecl *Temp = *ULE->decls_begin();
21243+
bool IsTypeAliasTemplateDecl = isa<TypeAliasTemplateDecl>(Temp);
21244+
if (NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier())
21245+
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
21246+
<< NNS << NameInfo.getName().getAsString() << Loc.getSourceRange()
21247+
<< IsTypeAliasTemplateDecl;
21248+
else
21249+
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
21250+
<< "" << NameInfo.getName().getAsString() << Loc.getSourceRange()
21251+
<< IsTypeAliasTemplateDecl;
21252+
Diag(Temp->getLocation(), diag::note_referenced_type_template)
21253+
<< IsTypeAliasTemplateDecl;
21254+
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
21255+
}
2123721256

2123821257
// Overloaded expressions.
2123921258
case BuiltinType::Overload: {

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5553,7 +5553,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
55535553
R.getRepresentativeDecl(), TemplateKWLoc, TemplateArgs);
55545554
if (Res.isInvalid() || Res.isUsable())
55555555
return Res;
5556-
// Result is dependent. Carry on to build an UnresolvedLookupEpxr.
5556+
// Result is dependent. Carry on to build an UnresolvedLookupExpr.
55575557
KnownDependent = true;
55585558
}
55595559

@@ -5571,6 +5571,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
55715571
TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs,
55725572
R.begin(), R.end(), KnownDependent);
55735573

5574+
// Model the templates with UnresolvedTemplateTy. The expression should then
5575+
// either be transformed in an instantiation or diagnosed.
5576+
if (ULE->getType() == Context.OverloadTy && R.isSingleResult() &&
5577+
!R.getFoundDecl()->getAsFunction())
5578+
ULE->setType(Context.UnresolvedTemplateTy);
5579+
55745580
return ULE;
55755581
}
55765582

@@ -5609,8 +5615,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
56095615
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
56105616
<< SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange()
56115617
<< isTypeAliasTemplateDecl;
5612-
Diag(Temp->getLocation(), diag::note_referenced_type_template) << 0;
5613-
return ExprError();
5618+
Diag(Temp->getLocation(), diag::note_referenced_type_template)
5619+
<< isTypeAliasTemplateDecl;
5620+
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
56145621
};
56155622

56165623
if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>())

clang/lib/Serialization/ASTCommon.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
186186
case BuiltinType::Overload:
187187
ID = PREDEF_TYPE_OVERLOAD_ID;
188188
break;
189+
case BuiltinType::UnresolvedTemplate:
190+
ID = PREDEF_TYPE_UNRESOLVED_TEMPLATE;
191+
break;
189192
case BuiltinType::BoundMember:
190193
ID = PREDEF_TYPE_BOUND_MEMBER;
191194
break;

clang/lib/Serialization/ASTReader.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7311,6 +7311,9 @@ QualType ASTReader::GetType(TypeID ID) {
73117311
case PREDEF_TYPE_OVERLOAD_ID:
73127312
T = Context.OverloadTy;
73137313
break;
7314+
case PREDEF_TYPE_UNRESOLVED_TEMPLATE:
7315+
T = Context.UnresolvedTemplateTy;
7316+
break;
73147317
case PREDEF_TYPE_BOUND_MEMBER:
73157318
T = Context.BoundMemberTy;
73167319
break;

clang/test/SemaCXX/PR62533.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
template<typename T>
44
struct test {
5-
template<typename> using fun_diff = char; // expected-note 2{{class template declared here}}
5+
template<typename> using fun_diff = char; // expected-note 2{{type alias template declared here}}
66
};
77

88
template<typename T, typename V>

clang/test/SemaTemplate/template-id-expr.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,74 @@ class E {
186186
#endif
187187
template<typename T> using D = int; // expected-note {{declared here}}
188188
E<D> ed; // expected-note {{instantiation of}}
189+
190+
namespace non_functions {
191+
192+
#if __cplusplus >= 201103L
193+
namespace PR88832 {
194+
template <typename T> struct O {
195+
static const T v = 0;
196+
};
197+
198+
struct P {
199+
template <typename T> using I = typename O<T>::v; // #TypeAlias
200+
};
201+
202+
struct Q {
203+
template <typename T> int foo() {
204+
return T::template I<int>; // expected-error {{'P::I' is expected to be a non-type template, but instantiated to a type alias template}}
205+
// expected-note@#TypeAlias {{type alias template declared here}}
206+
}
207+
};
208+
209+
int bar() {
210+
return Q().foo<P>(); // expected-note-re {{function template specialization {{.*}} requested here}}
211+
}
212+
213+
} // namespace PR88832
214+
#endif
215+
216+
namespace PR63243 {
217+
218+
namespace std {
219+
template <class T> struct add_pointer { // #add_pointer
220+
};
221+
} // namespace std
222+
223+
class A {};
224+
225+
int main() {
226+
std::__add_pointer<A>::type ptr; // #ill-formed-decl
227+
// expected-error@#ill-formed-decl {{no template named '__add_pointer'}}
228+
// expected-note@#add_pointer {{'add_pointer' declared here}}
229+
// expected-error@#ill-formed-decl {{expected ';' after expression}}
230+
// expected-error@#ill-formed-decl {{no type named 'type' in the global namespace}}
231+
// expected-error@#ill-formed-decl {{'std::add_pointer' is expected to be a non-type template, but instantiated to a class template}}
232+
// expected-note@#add_pointer {{class template declared here}}
233+
234+
// expected-warning@#ill-formed-decl {{keyword '__add_pointer' will be made available as an identifier here}}
235+
}
236+
237+
} // namespace PR63243
238+
239+
namespace PR48673 {
240+
241+
template <typename T> struct C {
242+
template <int TT> class Type {}; // #ClassTemplate
243+
};
244+
245+
template <typename T1> struct A {
246+
void foo() {
247+
C<T1>::template Type<2>; // #templated-decl-as-expression
248+
// expected-error@#templated-decl-as-expression {{'C<float>::Type' is expected to be a non-type template, but instantiated to a class template}}}
249+
// expected-note@#ClassTemplate {{class template declared here}}
250+
}
251+
};
252+
253+
void test() {
254+
A<float>().foo(); // expected-note-re {{instantiation of member function {{.*}} requested here}}
255+
}
256+
257+
} // namespace PR48673
258+
259+
}

0 commit comments

Comments
 (0)