diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-01-28 17:15:10 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-01-28 17:15:10 +0000 |
commit | fb034663885239079329e40d57eb59e32e08fa1a (patch) | |
tree | acfc9de664a1a6ec9925303094fcd1230fab42b0 | |
parent | aec0f37d11069598111997455602144b293f417d (diff) | |
download | bcm5719-llvm-fb034663885239079329e40d57eb59e32e08fa1a.tar.gz bcm5719-llvm-fb034663885239079329e40d57eb59e32e08fa1a.zip |
Complete semantic checking for typedef redeclarations in C++. The
rules are slightly different than in C, and now we handle both
dialects properly.
llvm-svn: 63211
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.def | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 57 | ||||
-rw-r--r-- | clang/test/SemaCXX/class.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaCXX/typedef-redecl.cpp | 25 | ||||
-rw-r--r-- | clang/www/cxx_status.html | 11 |
5 files changed, 80 insertions, 17 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.def b/clang/include/clang/Basic/DiagnosticSemaKinds.def index f73f6ee23fb..6cc23dd427a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.def +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.def @@ -468,6 +468,8 @@ DIAG(err_redefinition_different_kind, ERROR, "redefinition of %0 as different kind of symbol") DIAG(err_redefinition_different_typedef, ERROR, "typedef redefinition with different types (%0 vs %1)") +DIAG(err_tag_definition_of_typedef, ERROR, + "definition of type %0 conflicts with typedef of the same name") DIAG(err_conflicting_types, ERROR, "conflicting types for %0") DIAG(err_nested_redefinition, ERROR, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e0cb526c601..22650f525db 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -384,23 +384,31 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { } // Fall through - the typedef name was not a builtin type. } - // Verify the old decl was also a typedef. - TypedefDecl *Old = dyn_cast<TypedefDecl>(OldD); + // Verify the old decl was also a type. + TypeDecl *Old = dyn_cast<TypeDecl>(OldD); if (!Old) { - Diag(New->getLocation(), diag::err_redefinition_different_kind) + Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); if (!objc_types) Diag(OldD->getLocation(), diag::note_previous_definition); return New; } - + + // Determine the "old" type we'll use for checking and diagnostics. + QualType OldType; + if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old)) + OldType = OldTypedef->getUnderlyingType(); + else + OldType = Context.getTypeDeclType(Old); + // If the typedef types are not identical, reject them in all languages and // with any extensions enabled. - if (Old->getUnderlyingType() != New->getUnderlyingType() && - Context.getCanonicalType(Old->getUnderlyingType()) != + + if (OldType != New->getUnderlyingType() && + Context.getCanonicalType(OldType) != Context.getCanonicalType(New->getUnderlyingType())) { Diag(New->getLocation(), diag::err_redefinition_different_typedef) - << New->getUnderlyingType() << Old->getUnderlyingType(); + << New->getUnderlyingType() << OldType; if (!objc_types) Diag(Old->getLocation(), diag::note_previous_definition); return New; @@ -1276,8 +1284,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the - // tag type. - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) PrevDecl = 0; QualType R = GetTypeForDeclarator(D, S); @@ -2887,8 +2897,6 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } if (PrevDecl) { - assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) && - "unexpected Decl type"); if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -2955,7 +2963,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. } else { - // PrevDecl is a namespace. + // PrevDecl is a namespace, template, or anything else + // that lives in the IDNS_Tag identifier namespace. if (isDeclInScope(PrevDecl, SearchDC, S)) { // The tag name clashes with a namespace name, issue an error and // recover by making this tag be anonymous. @@ -3054,6 +3063,30 @@ CreateNewDecl: New->addAttr(new PackedAttr(Alignment * 8)); } + if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) { + // C++ [dcl.typedef]p3: + // [...] Similarly, in a given scope, a class or enumeration + // shall not be declared with the same name as a typedef-name + // that is declared in that scope and refers to a type other + // than the class or enumeration itself. + LookupResult Lookup = LookupName(S, Name, + LookupCriteria(LookupCriteria::Ordinary, + true, true)); + TypedefDecl *PrevTypedef = 0; + if (Lookup.getKind() == LookupResult::Found) + PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl()); + + if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) && + Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != + Context.getCanonicalType(Context.getTypeDeclType(New))) { + Diag(Loc, diag::err_tag_definition_of_typedef) + << Context.getTypeDeclType(New) + << PrevTypedef->getUnderlyingType(); + Diag(PrevTypedef->getLocation(), diag::note_previous_definition); + Invalid = true; + } + } + if (Invalid) New->setInvalidDecl(); diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index d739af87dd7..02608faa0f6 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -30,7 +30,7 @@ public: func btm : 1; // expected-error {{error: bit-field 'btm' with non-integral type}} NestedC bc : 1; // expected-error {{error: bit-field 'bc' with non-integral type}} - enum E { en1, en2 }; + enum E1 { en1, en2 }; int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}} static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}} diff --git a/clang/test/SemaCXX/typedef-redecl.cpp b/clang/test/SemaCXX/typedef-redecl.cpp index eabcef8b319..016882feb2b 100644 --- a/clang/test/SemaCXX/typedef-redecl.cpp +++ b/clang/test/SemaCXX/typedef-redecl.cpp @@ -1,12 +1,33 @@ // RUN: clang -fsyntax-only -verify %s - typedef int INT; typedef INT REALLY_INT; // expected-note {{previous definition is here}} typedef REALLY_INT REALLY_REALLY_INT; typedef REALLY_INT BOB; typedef float REALLY_INT; // expected-error{{typedef redefinition with different types ('float' vs 'INT')}} -class X { +struct X { typedef int result_type; // expected-note {{previous definition is here}} typedef INT result_type; // expected-error {{redefinition of 'result_type'}} }; + +struct Y; // expected-note{{previous definition is here}} +typedef int Y; // expected-error{{typedef redefinition with different types ('int' vs 'struct Y')}} + +typedef int Y2; // expected-note{{previous definition is here}} +struct Y2; // expected-error{{definition of type 'struct Y2' conflicts with typedef of the same name}} + +void f(); // expected-note{{previous definition is here}} +typedef int f; // expected-error{{redefinition of 'f' as different kind of symbol}} + +typedef int f2; // expected-note{{previous definition is here}} +void f2(); // expected-error{{redefinition of 'f2' as different kind of symbol}} + +typedef struct s s; +typedef int I; +typedef int I; +typedef I I; + +struct s { }; + +typedef class st { /* ... */ } st; // expected-note{{previous use is here}} +struct st; // expected-error{{use of 'st' with tag type that does not match previous declaration}} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index a83157b193e..22a419af5ee 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -944,13 +944,20 @@ welcome!</p> <td class="complete" align="center">✓</td>
<td class="complete" align="center">✓</td>
<td></td>
- <td>I think we handle everything.</td>
+ <td></td>
</tr>
<tr><td>7 [dcl.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 7.1 [dcl.spec]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 7.1.1 [dcl.stc]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 7.1.2 [dcl.fct.spec]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td> 7.1.3 [dcl.typedef]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td> 7.1.3 [dcl.typedef]</td>
+ <td class="complete" align="center">✓</td>
+ <td class="complete" align="center">✓</td>
+ <td class="complete" align="center">✓</td>
+ <td class="advanced"></td>
+ <td>Typedefs of anonymous tag types do not use the name of the typedef for linkage purposes.</td>
+</tr>
<tr><td> 7.1.4 [dcl.friend]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 7.1.5 [dcl.type]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 7.1.5.1 [dcl.type.cv]</td><td></td><td></td><td></td><td></td><td></td></tr>
|