let Read = [{ node->isDependentType() }];
}
def : Property<"declaration", DeclRef> {
- // Serializing a reference to the canonical declaration is apparently
- // necessary to make module-merging work.
+ // We don't know which declaration was originally referenced here, and we
+ // cannot reference a declaration that follows the use (because that can
+ // introduce deserialization cycles), so conservatively generate a
+ // reference to the first declaration.
+ // FIXME: If this is a reference to a class template specialization, that
+ // can still introduce a deserialization cycle.
let Read = [{ node->getDecl()->getCanonicalDecl() }];
}
}
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);
+ if (const auto *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+ for (const auto *PNA : Spec->getSpecializedTemplate()
+ ->getTemplatedDecl()
+ ->getMostRecentDecl()
+ ->specific_attrs<PreferredNameAttr>()) {
+ if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), Spec))
+ return printTypeSpec(
+ PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
+ }
}
printTag(T->getDecl(), OS);
/// If not, we can skip instantiating it. The attribute may or may not have
/// been instantiated yet.
static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
- // 'preferred_name' is only relevant to the matching specialization of the
+ // Never instantiate preferred_name attributes; they're relevant only on the
// template.
- if (const auto *PNA = dyn_cast<PreferredNameAttr>(A)) {
- QualType T = PNA->getTypedefType();
- const auto *RD = cast<CXXRecordDecl>(D);
- if (!T->isDependentType() && !RD->isDependentContext() &&
- !declaresSameEntity(T->getAsCXXRecordDecl(), RD))
- return false;
- for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
- if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
- PNA->getTypedefType()))
- return false;
- return true;
- }
+ if (const auto *PNA = dyn_cast<PreferredNameAttr>(A))
+ return false;
return true;
}
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 -emit-pch -o %t.a %s
+// RUN: %clang_cc1 -std=c++20 -include-pch %t.a %s -verify
+
+#ifndef HEADER
+#define HEADER
+
+namespace preferred_name {
+ template<typename T> struct X;
+ using Y = X<int>;
+ using Z = X<float>;
+ template<typename T> struct [[using clang: preferred_name(Y), preferred_name(Z)]] X {};
+ Y y;
+}
+
+#else
+
+namespace preferred_name {
+ Z z;
+
+ template<typename T> T forget(T t) { return t; }
+ void f() {
+ forget(y).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Y'}}
+ forget(z).foo(); // expected-error {{no member named 'foo' in 'preferred_name::Z'}}
+ }
+}
+
+#endif
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
// CHECK: TemplateArgument type 'int'
// CHECK-NOT: PreferredNameAttr
- // CHECK: PreferredNameAttr {{.*}} preferred_name::X
- // CHECK-NOT: PreferredNameAttr
// CHECK: CXXRecordDecl
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
// CHECK: TemplateArgument type 'float'
// CHECK-NOT: PreferredNameAttr
- // CHECK: PreferredNameAttr {{.*}} preferred_name::Y
- // CHECK-NOT: PreferredNameAttr
// CHECK: CXXRecordDecl
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
// CHECK: TemplateArgument type 'double'
clang::preferred_name(const_iterator)]] Iter {};
};
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>::Iter<const int>' to 'int'}}
}
for (auto const &ai : Args)
ai->writeTemplateInstantiation(OS);
- OS << " return new (C) " << R.getName() << "Attr(C, *A";
+ OS << " return new (C) " << R.getName() << "Attr(C, *A";
for (auto const &ai : Args) {
OS << ", ";
ai->writeTemplateInstantiationArgs(OS);
}
- OS << ");\n }\n";
+ OS << ");\n"
+ << " }\n";
}
OS << " } // end switch\n"
<< " llvm_unreachable(\"Unknown attribute!\");\n"