diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 684005c4876d27..143a05cba6ad72 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2093,6 +2093,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { bool isAtomicType() const; // C11 _Atomic() bool isUndeducedAutoType() const; // C++11 auto or // C++14 decltype(auto) + bool isTypedefNameType() const; // typedef or alias template #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ bool is##Id##Type() const; @@ -7066,6 +7067,15 @@ inline bool Type::isOverloadableType() const { return isDependentType() || isRecordType() || isEnumeralType(); } +/// Determines whether this type is written as a typedef-name. +inline bool Type::isTypedefNameType() const { + if (getAs()) + return true; + if (auto *TST = getAs()) + return TST->isTypeAlias(); + return false; +} + /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { return isFunctionType() || isArrayType(); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 54c451291a0777..d1882ac1a3b376 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -116,6 +116,8 @@ namespace { static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier); void spaceBeforePlaceHolder(raw_ostream &OS); void printTypeSpec(NamedDecl *D, raw_ostream &OS); + void printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS, + bool FullyQualify); void printBefore(QualType T, raw_ostream &OS); void printAfter(QualType T, raw_ostream &OS); @@ -1352,9 +1354,17 @@ void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { // Print the preferred name if we have one for this type. for (const auto *PNA : T->getDecl()->specific_attrs()) { if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), - T->getDecl())) - return printTypeSpec( - PNA->getTypedefType()->castAs()->getDecl(), OS); + T->getDecl())) { + // Find the outermost typedef or alias template. + QualType T = PNA->getTypedefType(); + while (true) { + if (auto *TT = dyn_cast(T)) + return printTypeSpec(TT->getDecl(), OS); + if (auto *TST = dyn_cast(T)) + return printTemplateId(TST, OS, /*FullyQualify=*/true); + T = T->getLocallyUnqualifiedSingleStepDesugaredType(); + } + } } printTag(T->getDecl(), OS); @@ -1416,20 +1426,32 @@ void TypePrinter::printSubstTemplateTypeParmPackAfter( printTemplateTypeParmAfter(T->getReplacedParameter(), OS); } -void TypePrinter::printTemplateSpecializationBefore( - const TemplateSpecializationType *T, - raw_ostream &OS) { +void TypePrinter::printTemplateId(const TemplateSpecializationType *T, + raw_ostream &OS, bool FullyQualify) { IncludeStrongLifetimeRAII Strong(Policy); - T->getTemplateName().print(OS, Policy); - const TemplateParameterList *TPL = nullptr; - if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) - TPL = TD->getTemplateParameters(); + TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(); + if (FullyQualify && TD) { + if (!Policy.SuppressScope) + AppendScope(TD->getDeclContext(), OS, TD->getDeclName()); + + IdentifierInfo *II = TD->getIdentifier(); + OS << II->getName(); + } else { + T->getTemplateName().print(OS, Policy); + } + const TemplateParameterList *TPL = TD ? TD->getTemplateParameters() : nullptr; printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL); spaceBeforePlaceHolder(OS); } +void TypePrinter::printTemplateSpecializationBefore( + const TemplateSpecializationType *T, + raw_ostream &OS) { + printTemplateId(T, OS, false); +} + void TypePrinter::printTemplateSpecializationAfter( const TemplateSpecializationType *T, raw_ostream &OS) {} diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c836031afcfba8..0872cc640b39a7 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1393,7 +1393,7 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) { if (!TSI) TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc()); - if (!T.hasQualifiers() && T->getAs()) { + if (!T.hasQualifiers() && T->isTypedefNameType()) { // Find the template name, if this type names a template specialization. const TemplateDecl *Template = nullptr; if (const auto *CTSD = dyn_cast_or_null( diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp index 3f52412a23acb6..b0bcca566dd9bb 100644 --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -126,4 +126,10 @@ namespace preferred_name { }; auto it = MemberTemplate::Iter(); int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate::const_iterator' to 'int'}} + + template struct Foo; + template using Bar = Foo<1, 2, T...>; + template struct [[clang::preferred_name(::preferred_name::Bar)]] Foo {}; + Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar'}} } +::preferred_name::Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar'}}