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;
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();
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);
// 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);
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) {}
};
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>'}}