forked from OSchip/llvm-project
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
This commit is contained in:
parent
aec0f37d11
commit
fb03466388
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue