[llvm-branch-commits] [clang] b12e473 - Allow dependent alias template specializations in the preferred_name
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jan 5 15:38:29 PST 2021
Author: Richard Smith
Date: 2021-01-05T15:33:51-08:00
New Revision: b12e4735317ec96e1b35deee68b90d62a23a9353
URL: https://github.com/llvm/llvm-project/commit/b12e4735317ec96e1b35deee68b90d62a23a9353
DIFF: https://github.com/llvm/llvm-project/commit/b12e4735317ec96e1b35deee68b90d62a23a9353.diff
LOG: Allow dependent alias template specializations in the preferred_name
attribute.
This was intended to work, but didn't match the checks because these
types are modeled as TemplateSpecializationTypes not TypedefTypes.
Added:
Modified:
clang/include/clang/AST/Type.h
clang/lib/AST/TypePrinter.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/SemaTemplate/attributes.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 684005c4876d..143a05cba6ad 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<TypedefType>())
+ return true;
+ if (auto *TST = getAs<TemplateSpecializationType>())
+ 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 54c451291a07..d1882ac1a3b3 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<PreferredNameAttr>()) {
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
- T->getDecl()))
- return printTypeSpec(
- PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
+ T->getDecl())) {
+ // Find the outermost typedef or alias template.
+ QualType T = PNA->getTypedefType();
+ while (true) {
+ if (auto *TT = dyn_cast<TypedefType>(T))
+ return printTypeSpec(TT->getDecl(), OS);
+ if (auto *TST = dyn_cast<TemplateSpecializationType>(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 c836031afcfb..0872cc640b39 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<TypedefType>()) {
+ 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<ClassTemplateSpecializationDecl>(
diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index 3f52412a23ac..b0bcca566dd9 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -126,4 +126,10 @@ namespace preferred_name {
};
auto it = MemberTemplate<int>::Iter<const int>();
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
+
+ template<int A, int B, typename ...T> struct Foo;
+ template<typename ...T> using Bar = Foo<1, 2, T...>;
+ template<int A, int B, typename ...T> struct [[clang::preferred_name(::preferred_name::Bar<T...>)]] Foo {};
+ Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar<int, float>'}}
}
+::preferred_name::Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar<int, float>'}}
More information about the llvm-branch-commits
mailing list