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.
This commit is contained in:
Richard Smith 2021-01-05 15:32:44 -08:00
parent 8b124c19f5
commit b12e473531
4 changed files with 51 additions and 13 deletions

View File

@ -2093,6 +2093,7 @@ public:
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();

View File

@ -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,18 +1426,30 @@ void TypePrinter::printSubstTemplateTypeParmPackAfter(
printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
}
void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
raw_ostream &OS, bool FullyQualify) {
IncludeStrongLifetimeRAII Strong(Policy);
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) {
IncludeStrongLifetimeRAII Strong(Policy);
T->getTemplateName().print(OS, Policy);
const TemplateParameterList *TPL = nullptr;
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl())
TPL = TD->getTemplateParameters();
printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL);
spaceBeforePlaceHolder(OS);
printTemplateId(T, OS, false);
}
void TypePrinter::printTemplateSpecializationAfter(

View File

@ -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>(

View File

@ -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>'}}