forked from OSchip/llvm-project
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:
parent
8b124c19f5
commit
b12e473531
|
@ -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();
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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>'}}
|
||||
|
|
Loading…
Reference in New Issue