https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/89019
None >From e510a76d231de0e22ba52584a80f18deb6af91c6 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 17 Apr 2024 12:24:56 +0800 Subject: [PATCH] [clang] Distinguish unresolved templates in UnresolvedLookupExpr --- clang/include/clang/AST/ASTContext.h | 3 +- clang/include/clang/AST/BuiltinTypes.def | 2 + .../include/clang/Serialization/ASTBitCodes.h | 4 +- clang/lib/AST/ASTContext.cpp | 3 + clang/lib/AST/NSAPI.cpp | 1 + clang/lib/AST/Type.cpp | 3 + clang/lib/AST/TypeLoc.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 19 +++++ clang/lib/Sema/SemaTemplate.cpp | 11 ++- clang/lib/Serialization/ASTCommon.cpp | 3 + clang/lib/Serialization/ASTReader.cpp | 3 + clang/test/SemaCXX/PR62533.cpp | 2 +- clang/test/SemaTemplate/template-id-expr.cpp | 71 +++++++++++++++++++ 13 files changed, 120 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 28f8d67811f0a2..e9a22f04cfe764 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1116,7 +1116,8 @@ class ASTContext : public RefCountedBase<ASTContext> { CanQualType BFloat16Ty; CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 CanQualType VoidPtrTy, NullPtrTy; - CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; + CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy, + UnknownAnyTy; CanQualType BuiltinFnTy; CanQualType PseudoObjectTy, ARCUnbridgedCastTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index c04f6f6f127191..eb72bf0f866247 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -285,6 +285,8 @@ PLACEHOLDER_TYPE(Overload, OverloadTy) // x->foo # if only contains non-static members PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) +PLACEHOLDER_TYPE(UnresolvedTemplate, UnresolvedTemplateTy) + // The type of an expression which refers to a pseudo-object, // such as those introduced by Objective C's @property or // VS.NET's __property declarations. A placeholder type. The diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 500098dd3dab1d..a0feb3a317611e 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1099,6 +1099,8 @@ enum PredefinedTypeIDs { // \brief WebAssembly reference types with auto numeration #define WASM_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/WebAssemblyReferenceTypes.def" + + PREDEF_TYPE_UNRESOLVED_TEMPLATE, // Sentinel value. Considered a predefined type but not useable as one. PREDEF_TYPE_LAST_ID }; @@ -1108,7 +1110,7 @@ enum PredefinedTypeIDs { /// /// Type IDs for non-predefined types will start at /// NUM_PREDEF_TYPE_IDs. -const unsigned NUM_PREDEF_TYPE_IDS = 502; +const unsigned NUM_PREDEF_TYPE_IDS = 503; // Ensure we do not overrun the predefined types we reserved // in the enum PredefinedTypeIDs above. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6ce233704a5885..e9fba116cff559 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1306,6 +1306,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, // Placeholder type for bound members. InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember); + // Placeholder type for unresolved templates. + InitBuiltinType(UnresolvedTemplateTy, BuiltinType::UnresolvedTemplate); + // Placeholder type for pseudo-objects. InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index ecc56c13fb7573..4e09b27b0f76cd 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -454,6 +454,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" case BuiltinType::BoundMember: + case BuiltinType::UnresolvedTemplate: case BuiltinType::Dependent: case BuiltinType::Overload: case BuiltinType::UnknownAny: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index cb22c91a12aa89..4751d73184262f 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3381,6 +3381,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "<overloaded function type>"; case BoundMember: return "<bound member function type>"; + case UnresolvedTemplate: + return "<unresolved template type>"; case PseudoObject: return "<pseudo-object type>"; case Dependent: @@ -4673,6 +4675,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { #include "clang/AST/BuiltinTypes.def" return false; + case BuiltinType::UnresolvedTemplate: // Dependent types that could instantiate to a pointer type. case BuiltinType::Dependent: case BuiltinType::Overload: diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 21e152f6aea8a0..e8cd7fd7b35b6f 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -399,6 +399,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::NullPtr: case BuiltinType::Overload: case BuiltinType::Dependent: + case BuiltinType::UnresolvedTemplate: case BuiltinType::BoundMember: case BuiltinType::UnknownAny: case BuiltinType::ARCUnbridgedCast: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 7c3faba0f78819..8fe3e2c771f1bf 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6349,6 +6349,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { #include "clang/AST/BuiltinTypes.def" return false; + case BuiltinType::UnresolvedTemplate: // We cannot lower out overload sets; they might validly be resolved // by the call machinery. case BuiltinType::Overload: @@ -21234,6 +21235,24 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { if (!placeholderType) return E; switch (placeholderType->getKind()) { + case BuiltinType::UnresolvedTemplate: { + auto *ULE = cast<UnresolvedLookupExpr>(E); + const DeclarationNameInfo &NameInfo = ULE->getNameInfo(); + NestedNameSpecifierLoc Loc = ULE->getQualifierLoc(); + NamedDecl *Temp = *ULE->decls_begin(); + bool IsTypeAliasTemplateDecl = isa<TypeAliasTemplateDecl>(Temp); + if (NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier()) + Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template) + << NNS << NameInfo.getName().getAsString() << Loc.getSourceRange() + << IsTypeAliasTemplateDecl; + else + Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template) + << "" << NameInfo.getName().getAsString() << Loc.getSourceRange() + << IsTypeAliasTemplateDecl; + Diag(Temp->getLocation(), diag::note_referenced_type_template) + << IsTypeAliasTemplateDecl; + return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}); + } // Overloaded expressions. case BuiltinType::Overload: { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 95171359f0ab17..219ab489f5231c 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5553,7 +5553,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, R.getRepresentativeDecl(), TemplateKWLoc, TemplateArgs); if (Res.isInvalid() || Res.isUsable()) return Res; - // Result is dependent. Carry on to build an UnresolvedLookupEpxr. + // Result is dependent. Carry on to build an UnresolvedLookupExpr. KnownDependent = true; } @@ -5571,6 +5571,10 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs, R.begin(), R.end(), KnownDependent); + if (ULE->getType() == Context.OverloadTy && R.isSingleResult() && + !R.getFoundDecl()->getAsFunction()) + ULE->setType(Context.UnresolvedTemplateTy); + return ULE; } @@ -5609,8 +5613,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template) << SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange() << isTypeAliasTemplateDecl; - Diag(Temp->getLocation(), diag::note_referenced_type_template) << 0; - return ExprError(); + Diag(Temp->getLocation(), diag::note_referenced_type_template) + << isTypeAliasTemplateDecl; + return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}); }; if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index f8d54c0c398906..cd2d40a2c65fcb 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -186,6 +186,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; + case BuiltinType::UnresolvedTemplate: + ID = PREDEF_TYPE_UNRESOLVED_TEMPLATE; + break; case BuiltinType::BoundMember: ID = PREDEF_TYPE_BOUND_MEMBER; break; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index b28df03b4a95e9..445c042330194b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7311,6 +7311,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; + case PREDEF_TYPE_UNRESOLVED_TEMPLATE: + T = Context.UnresolvedTemplateTy; + break; case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; diff --git a/clang/test/SemaCXX/PR62533.cpp b/clang/test/SemaCXX/PR62533.cpp index 920ea54d4b00ed..0753156813f8e7 100644 --- a/clang/test/SemaCXX/PR62533.cpp +++ b/clang/test/SemaCXX/PR62533.cpp @@ -2,7 +2,7 @@ template<typename T> struct test { - template<typename> using fun_diff = char; // expected-note 2{{class template declared here}} + template<typename> using fun_diff = char; // expected-note 2{{type alias template declared here}} }; template<typename T, typename V> diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp index 0555d8b94504fb..741742d9e5d7eb 100644 --- a/clang/test/SemaTemplate/template-id-expr.cpp +++ b/clang/test/SemaTemplate/template-id-expr.cpp @@ -186,3 +186,74 @@ class E { #endif template<typename T> using D = int; // expected-note {{declared here}} E<D> ed; // expected-note {{instantiation of}} + +namespace non_functions { + +#if __cplusplus >= 201103L +namespace PR88832 { +template <typename T> struct O { + static const T v = 0; +}; + +struct P { + template <typename T> using I = typename O<T>::v; // #TypeAlias +}; + +struct Q { + template <typename T> int foo() { + return T::template I<int>; // expected-error {{'P::I' is expected to be a non-type template, but instantiated to a type alias template}} + // expected-note@#TypeAlias {{type alias template declared here}} + } +}; + +int bar() { + return Q().foo<P>(); // expected-note-re {{function template specialization {{.*}} requested here}} +} + +} // namespace PR88832 +#endif + +namespace PR63243 { + +namespace std { +template <class T> struct add_pointer { // #add_pointer +}; +} // namespace std + +class A {}; + +int main() { + std::__add_pointer<A>::type ptr; // #ill-formed-decl + // expected-error@#ill-formed-decl {{no template named '__add_pointer'}} + // expected-note@#add_pointer {{'add_pointer' declared here}} + // expected-error@#ill-formed-decl {{expected ';' after expression}} + // expected-error@#ill-formed-decl {{no type named 'type' in the global namespace}} + // expected-error@#ill-formed-decl {{'std::add_pointer' is expected to be a non-type template, but instantiated to a class template}} + // expected-note@#add_pointer {{class template declared here}} + + // expected-warning@#ill-formed-decl {{keyword '__add_pointer' will be made available as an identifier here}} +} + +} // namespace PR63243 + +namespace PR48673 { + +template <typename T> struct C { + template <int TT> class Type {}; // #ClassTemplate +}; + +template <typename T1> struct A { + void foo() { + C<T1>::template Type<2>; // #templated-decl-as-expression + // expected-error@#templated-decl-as-expression {{'C<float>::Type' is expected to be a non-type template, but instantiated to a class template}}} + // expected-note@#ClassTemplate {{class template declared here}} + } +}; + +void test() { + A<float>().foo(); // expected-note-re {{instantiation of member function {{.*}} requested here}} +} + +} // namespace PR48673 + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits