forked from OSchip/llvm-project
Fix deserialization cycle in preferred_name attribute.
This is really just a workaround for a more fundamental issue in the way we deserialize attributes. See PR48434 for details. Also fix tablegen code generator to produce more correct indentation to resolve buildbot issues with -Werror=misleading-indentation firing inside the generated code.
This commit is contained in:
parent
0b81d9a992
commit
a64c26a47a
|
@ -484,8 +484,12 @@ let Class = TagType in {
|
|||
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() }];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1350,11 +1350,16 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
|
|||
|
||||
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);
|
||||
|
|
|
@ -552,20 +552,10 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
|
|||
/// 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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// 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
|
|
@ -83,14 +83,10 @@ namespace preferred_name {
|
|||
// 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'
|
||||
|
@ -125,5 +121,5 @@ namespace preferred_name {
|
|||
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'}}
|
||||
}
|
||||
|
|
|
@ -3330,12 +3330,13 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
|
|||
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"
|
||||
|
|
Loading…
Reference in New Issue