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 isAtomicType() const; // C11 _Atomic()
|
||||||
bool isUndeducedAutoType() const; // C++11 auto or
|
bool isUndeducedAutoType() const; // C++11 auto or
|
||||||
// C++14 decltype(auto)
|
// C++14 decltype(auto)
|
||||||
|
bool isTypedefNameType() const; // typedef or alias template
|
||||||
|
|
||||||
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
|
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
|
||||||
bool is##Id##Type() const;
|
bool is##Id##Type() const;
|
||||||
|
@ -7066,6 +7067,15 @@ inline bool Type::isOverloadableType() const {
|
||||||
return isDependentType() || isRecordType() || isEnumeralType();
|
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.
|
/// Determines whether this type can decay to a pointer type.
|
||||||
inline bool Type::canDecayToPointerType() const {
|
inline bool Type::canDecayToPointerType() const {
|
||||||
return isFunctionType() || isArrayType();
|
return isFunctionType() || isArrayType();
|
||||||
|
|
|
@ -116,6 +116,8 @@ namespace {
|
||||||
static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
|
static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
|
||||||
void spaceBeforePlaceHolder(raw_ostream &OS);
|
void spaceBeforePlaceHolder(raw_ostream &OS);
|
||||||
void printTypeSpec(NamedDecl *D, 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 printBefore(QualType T, raw_ostream &OS);
|
||||||
void printAfter(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.
|
// Print the preferred name if we have one for this type.
|
||||||
for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
|
for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
|
||||||
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
|
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
|
||||||
T->getDecl()))
|
T->getDecl())) {
|
||||||
return printTypeSpec(
|
// Find the outermost typedef or alias template.
|
||||||
PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
|
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);
|
printTag(T->getDecl(), OS);
|
||||||
|
@ -1416,18 +1426,30 @@ void TypePrinter::printSubstTemplateTypeParmPackAfter(
|
||||||
printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
|
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(
|
void TypePrinter::printTemplateSpecializationBefore(
|
||||||
const TemplateSpecializationType *T,
|
const TemplateSpecializationType *T,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
IncludeStrongLifetimeRAII Strong(Policy);
|
printTemplateId(T, OS, false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypePrinter::printTemplateSpecializationAfter(
|
void TypePrinter::printTemplateSpecializationAfter(
|
||||||
|
|
|
@ -1393,7 +1393,7 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
if (!TSI)
|
if (!TSI)
|
||||||
TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc());
|
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.
|
// Find the template name, if this type names a template specialization.
|
||||||
const TemplateDecl *Template = nullptr;
|
const TemplateDecl *Template = nullptr;
|
||||||
if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
||||||
|
|
|
@ -126,4 +126,10 @@ namespace preferred_name {
|
||||||
};
|
};
|
||||||
auto it = MemberTemplate<int>::Iter<const int>();
|
auto it = MemberTemplate<int>::Iter<const int>();
|
||||||
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to '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