зеркало из https://github.com/microsoft/clang-1.git
The code trying to assign a typedef to an anonymous tag declaration was
extremely rambunctious, both on parsing and on template instantiation. Calm it down, fixing an internal consistency assert on anonymous enum instantiation manglings. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124653 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
071d3af0de
Коммит
cde5a400db
|
@ -5697,17 +5697,46 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
|
||||||
D.getIdentifier(),
|
D.getIdentifier(),
|
||||||
TInfo);
|
TInfo);
|
||||||
|
|
||||||
if (const TagType *TT = T->getAs<TagType>()) {
|
// Bail out immediately if we have an invalid declaration.
|
||||||
TagDecl *TD = TT->getDecl();
|
if (D.isInvalidType()) {
|
||||||
|
NewTD->setInvalidDecl();
|
||||||
// If the TagDecl that the TypedefDecl points to is an anonymous decl
|
return NewTD;
|
||||||
// keep track of the TypedefDecl.
|
}
|
||||||
if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
|
|
||||||
TD->setTypedefForAnonDecl(NewTD);
|
// C++ [dcl.typedef]p8:
|
||||||
|
// If the typedef declaration defines an unnamed class (or
|
||||||
|
// enum), the first typedef-name declared by the declaration
|
||||||
|
// to be that class type (or enum type) is used to denote the
|
||||||
|
// class type (or enum type) for linkage purposes only.
|
||||||
|
// We need to check whether the type was declared in the declaration.
|
||||||
|
switch (D.getDeclSpec().getTypeSpecType()) {
|
||||||
|
case TST_enum:
|
||||||
|
case TST_struct:
|
||||||
|
case TST_union:
|
||||||
|
case TST_class: {
|
||||||
|
TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
|
||||||
|
|
||||||
|
// Do nothing if the tag is not anonymous or already has an
|
||||||
|
// associated typedef (from an earlier typedef in this decl group).
|
||||||
|
if (tagFromDeclSpec->getIdentifier()) break;
|
||||||
|
if (tagFromDeclSpec->getTypedefForAnonDecl()) break;
|
||||||
|
|
||||||
|
// A well-formed anonymous tag must always be a TUK_Definition.
|
||||||
|
assert(tagFromDeclSpec->isThisDeclarationADefinition());
|
||||||
|
|
||||||
|
// The type must match the tag exactly; no qualifiers allowed.
|
||||||
|
if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Otherwise, set this is the anon-decl typedef for the tag.
|
||||||
|
tagFromDeclSpec->setTypedefForAnonDecl(NewTD);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (D.isInvalidType())
|
|
||||||
NewTD->setInvalidDecl();
|
|
||||||
return NewTD;
|
return NewTD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,13 +143,15 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
|
||||||
if (Invalid)
|
if (Invalid)
|
||||||
Typedef->setInvalidDecl();
|
Typedef->setInvalidDecl();
|
||||||
|
|
||||||
if (const TagType *TT = DI->getType()->getAs<TagType>()) {
|
// If the old typedef was the name for linkage purposes of an anonymous
|
||||||
TagDecl *TD = TT->getDecl();
|
// tag decl, re-establish that relationship for the new typedef.
|
||||||
|
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
|
||||||
// If the TagDecl that the TypedefDecl points to is an anonymous decl
|
TagDecl *oldTag = oldTagType->getDecl();
|
||||||
// keep track of the TypedefDecl.
|
if (oldTag->getTypedefForAnonDecl() == D) {
|
||||||
if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
|
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
|
||||||
TD->setTypedefForAnonDecl(Typedef);
|
assert(!newTag->getIdentifier() && !newTag->getTypedefForAnonDecl());
|
||||||
|
newTag->setTypedefForAnonDecl(Typedef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
|
if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
|
||||||
|
|
|
@ -69,3 +69,14 @@ int f7() {
|
||||||
// CHECK: _ZZ2f7vE1a
|
// CHECK: _ZZ2f7vE1a
|
||||||
return a.b;
|
return a.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This used to cause an assert because the typedef-for-anonymous-tag
|
||||||
|
// code was trying to claim the enum for the template.
|
||||||
|
enum { T8 };
|
||||||
|
template <class T> struct Test8 {
|
||||||
|
typedef T type;
|
||||||
|
// define internal void @"_ZN5Test8I3$_2EC1ES0_"(
|
||||||
|
Test8(type t) {}
|
||||||
|
};
|
||||||
|
template <class T> void make_test8(T value) { Test8<T> t(value); }
|
||||||
|
void test8() { make_test8(T8); }
|
||||||
|
|
Загрузка…
Ссылка в новой задаче