diff options
| author | John McCall <rjmccall@apple.com> | 2011-02-01 08:20:08 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2011-02-01 08:20:08 +0000 |
| commit | 04fcd0d58f3cf32ec3456dd08d789ff919087b20 (patch) | |
| tree | cfd6c89d431570009cda279993ad97556105ec7b | |
| parent | ecd90b5946c9dbfb156557872dd5dcdcb5358606 (diff) | |
| download | bcm5719-llvm-04fcd0d58f3cf32ec3456dd08d789ff919087b20.tar.gz bcm5719-llvm-04fcd0d58f3cf32ec3456dd08d789ff919087b20.zip | |
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.
llvm-svn: 124653
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 45 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 16 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/mangle-unnamed.cpp | 11 |
3 files changed, 57 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b2cb96134c0..6341de996ad 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5697,17 +5697,46 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, D.getIdentifier(), TInfo); - if (const TagType *TT = T->getAs<TagType>()) { - TagDecl *TD = TT->getDecl(); + // Bail out immediately if we have an invalid declaration. + if (D.isInvalidType()) { + NewTD->setInvalidDecl(); + return 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; - // If the TagDecl that the TypedefDecl points to is an anonymous decl - // keep track of the TypedefDecl. - if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) - TD->setTypedefForAnonDecl(NewTD); + // Otherwise, set this is the anon-decl typedef for the tag. + tagFromDeclSpec->setTypedefForAnonDecl(NewTD); + break; + } + + default: + break; } - if (D.isInvalidType()) - NewTD->setInvalidDecl(); return NewTD; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 759e2c16f1d..73b01271b21 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -143,13 +143,15 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { if (Invalid) Typedef->setInvalidDecl(); - if (const TagType *TT = DI->getType()->getAs<TagType>()) { - TagDecl *TD = TT->getDecl(); - - // If the TagDecl that the TypedefDecl points to is an anonymous decl - // keep track of the TypedefDecl. - if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) - TD->setTypedefForAnonDecl(Typedef); + // If the old typedef was the name for linkage purposes of an anonymous + // tag decl, re-establish that relationship for the new typedef. + if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) { + TagDecl *oldTag = oldTagType->getDecl(); + if (oldTag->getTypedefForAnonDecl() == D) { + TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl(); + assert(!newTag->getIdentifier() && !newTag->getTypedefForAnonDecl()); + newTag->setTypedefForAnonDecl(Typedef); + } } if (TypedefDecl *Prev = D->getPreviousDeclaration()) { diff --git a/clang/test/CodeGenCXX/mangle-unnamed.cpp b/clang/test/CodeGenCXX/mangle-unnamed.cpp index 83b46d69454..e9f60d04507 100644 --- a/clang/test/CodeGenCXX/mangle-unnamed.cpp +++ b/clang/test/CodeGenCXX/mangle-unnamed.cpp @@ -69,3 +69,14 @@ int f7() { // CHECK: _ZZ2f7vE1a 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); } |

