[cfe-commits] r63211 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp test/SemaCXX/class.cpp test/SemaCXX/typedef-redecl.cpp www/cxx_status.html
Douglas Gregor
dgregor at apple.com
Wed Jan 28 09:15:11 PST 2009
Author: dgregor
Date: Wed Jan 28 11:15:10 2009
New Revision: 63211
URL: http://llvm.org/viewvc/llvm-project?rev=63211&view=rev
Log:
Complete semantic checking for typedef redeclarations in C++. The
rules are slightly different than in C, and now we handle both
dialects properly.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/SemaCXX/class.cpp
cfe/trunk/test/SemaCXX/typedef-redecl.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=63211&r1=63210&r2=63211&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Wed Jan 28 11:15:10 2009
@@ -468,6 +468,8 @@
"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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=63211&r1=63210&r2=63211&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 28 11:15:10 2009
@@ -384,23 +384,31 @@
}
// 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 @@
// 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 @@
}
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 @@
// 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 @@
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();
Modified: cfe/trunk/test/SemaCXX/class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=63211&r1=63210&r2=63211&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/class.cpp (original)
+++ cfe/trunk/test/SemaCXX/class.cpp Wed Jan 28 11:15:10 2009
@@ -30,7 +30,7 @@
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}}
Modified: cfe/trunk/test/SemaCXX/typedef-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typedef-redecl.cpp?rev=63211&r1=63210&r2=63211&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/typedef-redecl.cpp (original)
+++ cfe/trunk/test/SemaCXX/typedef-redecl.cpp Wed Jan 28 11:15:10 2009
@@ -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}}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=63211&r1=63210&r2=63211&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Jan 28 11:15:10 2009
@@ -944,13 +944,20 @@
<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>
More information about the cfe-commits
mailing list