Skip to content

Commit 7a484d3

Browse files
authored
[clang] Distinguish unresolved templates in UnresolvedLookupExpr (#89019)
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 ffc9a30 commit 7a484d3

File tree

16 files changed

+185
-6
lines changed

16 files changed

+185
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,8 @@ Bug Fixes to C++ Support
681681
whose type is `decltype(auto)`. Fixes (#GH68885).
682682
- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context.
683683
- Fix an assertion failure when parsing an invalid members of an anonymous class. (#GH85447)
684+
- Fixed a misuse of ``UnresolvedLookupExpr`` for ill-formed templated expressions. Fixes (#GH48673), (#GH63243)
685+
and (#GH88832).
684686

685687
Bug Fixes to AST Handling
686688
^^^^^^^^^^^^^^^^^^^^^^^^^

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/AST/ExprCXX.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3163,8 +3163,30 @@ class OverloadExpr : public Expr {
31633163
/// This arises in several ways:
31643164
/// * we might be waiting for argument-dependent lookup;
31653165
/// * the name might resolve to an overloaded function;
3166+
/// * the name might resolve to a non-function template; for example, in the
3167+
/// following snippet, the return expression of the member function
3168+
/// 'foo()' might remain unresolved until instantiation:
3169+
///
3170+
/// \code
3171+
/// struct P {
3172+
/// template <class T> using I = T;
3173+
/// };
3174+
///
3175+
/// struct Q {
3176+
/// template <class T> int foo() {
3177+
/// return T::template I<int>;
3178+
/// }
3179+
/// };
3180+
/// \endcode
3181+
///
3182+
/// ...which is distinct from modeling function overloads, and therefore we use
3183+
/// a different builtin type 'UnresolvedTemplate' to avoid confusion. This is
3184+
/// done in Sema::BuildTemplateIdExpr.
3185+
///
31663186
/// and eventually:
31673187
/// * the lookup might have included a function template.
3188+
/// * the unresolved template gets transformed in an instantiation or gets
3189+
/// diagnosed for its direct use.
31683190
///
31693191
/// These never include UnresolvedUsingValueDecls, which are always class
31703192
/// members and therefore appear only in UnresolvedMemberLookupExprs.

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,9 @@ enum PredefinedTypeIDs {
10911091
// \brief WebAssembly reference types with auto numeration
10921092
#define WASM_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID,
10931093
#include "clang/Basic/WebAssemblyReferenceTypes.def"
1094+
1095+
/// The placeholder type for unresolved templates.
1096+
PREDEF_TYPE_UNRESOLVED_TEMPLATE,
10941097
// Sentinel value. Considered a predefined type but not useable as one.
10951098
PREDEF_TYPE_LAST_ID
10961099
};
@@ -1100,7 +1103,7 @@ enum PredefinedTypeIDs {
11001103
///
11011104
/// Type IDs for non-predefined types will start at
11021105
/// NUM_PREDEF_TYPE_IDs.
1103-
const unsigned NUM_PREDEF_TYPE_IDS = 502;
1106+
const unsigned NUM_PREDEF_TYPE_IDS = 503;
11041107

11051108
// Ensure we do not overrun the predefined types we reserved
11061109
// in the enum PredefinedTypeIDs above.

clang/lib/AST/ASTContext.cpp

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

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

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
@@ -3393,6 +3393,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
33933393
return "<overloaded function type>";
33943394
case BoundMember:
33953395
return "<bound member function type>";
3396+
case UnresolvedTemplate:
3397+
return "<unresolved template type>";
33963398
case PseudoObject:
33973399
return "<pseudo-object type>";
33983400
case Dependent:
@@ -4685,6 +4687,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
46854687
#include "clang/AST/BuiltinTypes.def"
46864688
return false;
46874689

4690+
case BuiltinType::UnresolvedTemplate:
46884691
// Dependent types that could instantiate to a pointer type.
46894692
case BuiltinType::Dependent:
46904693
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/Parse/ParseExprCXX.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
407407
continue;
408408
}
409409

410+
switch (Tok.getKind()) {
411+
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
412+
#include "clang/Basic/TransformTypeTraits.def"
413+
if (!NextToken().is(tok::l_paren)) {
414+
Tok.setKind(tok::identifier);
415+
Diag(Tok, diag::ext_keyword_as_ident)
416+
<< Tok.getIdentifierInfo()->getName() << 0;
417+
continue;
418+
}
419+
[[fallthrough]];
420+
default:
421+
break;
422+
}
423+
410424
// The rest of the nested-name-specifier possibilities start with
411425
// tok::identifier.
412426
if (Tok.isNot(tok::identifier))

0 commit comments

Comments
 (0)