[cfe-commits] r61878 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def lib/AST/Decl.cpp lib/AST/DeclCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/anonymous-union.cpp www/cxx_status.html
Douglas Gregor
dgregor at apple.com
Wed Jan 7 11:46:04 PST 2009
Author: dgregor
Date: Wed Jan 7 13:46:03 2009
New Revision: 61878
URL: http://llvm.org/viewvc/llvm-project?rev=61878&view=rev
Log:
Finished semantic analysis of anonymous unions in C++.
Duplicate-member checking within classes is still a little messy, and
anonymous unions are still completely broken in C. We'll need to unify
the handling of fields in C and C++ to make this code applicable in
both languages.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaCXX/anonymous-union.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Jan 7 13:46:03 2009
@@ -160,6 +160,9 @@
const_cast<const ScopedDecl*>(this)->getDeclContext());
}
+ void setAccess(AccessSpecifier AS) { Access = AS; }
+ AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+
/// getLexicalDeclContext - The declaration context where this ScopedDecl was
/// lexically declared (LexicalDC). May be different from
/// getDeclContext() (SemanticDC).
@@ -360,7 +363,7 @@
StorageClass getStorageClass() const { return (StorageClass)SClass; }
SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
-
+
const Expr *getInit() const { return (const Expr*) Init; }
Expr *getInit() { return (Expr*) Init; }
void setInit(Expr *I) { Init = (Stmt*) I; }
@@ -624,7 +627,6 @@
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
unsigned SClass : 2;
bool IsInline : 1;
- bool IsImplicit : 1;
// Move to DeclGroup when it is implemented.
SourceLocation TypeSpecStartLoc;
@@ -636,7 +638,7 @@
: ValueDecl(DK, DC, L, N, T, PrevDecl),
DeclContext(DK),
ParamInfo(0), Body(0), PreviousDeclaration(0),
- SClass(S), IsInline(isInline), IsImplicit(0), TypeSpecStartLoc(TSSL) {}
+ SClass(S), IsInline(isInline), TypeSpecStartLoc(TSSL) {}
virtual ~FunctionDecl();
virtual void Destroy(ASTContext& C);
@@ -670,9 +672,6 @@
void setBody(Stmt *B) { Body = B; }
- bool isImplicit() { return IsImplicit; }
- void setImplicit() { IsImplicit = true; }
-
/// getPreviousDeclaration - Return the previous declaration of this
/// function.
const FunctionDecl *getPreviousDeclaration() const {
@@ -776,6 +775,12 @@
/// isBitfield - Determines whether this field is a bitfield.
bool isBitField() const { return BitWidth != NULL; }
+ /// isAnonymousStructOrUnion - Determines whether this field is a
+ /// representative for an anonymous struct or union. Such fields are
+ /// unnamed and are implicitly generated by the implementation to
+ /// store the data for the anonymous union or struct.
+ bool isAnonymousStructOrUnion() const;
+
Expr *getBitWidth() const { return BitWidth; }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
@@ -852,10 +857,8 @@
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, ScopedDecl *PrevDecl)
: ScopedDecl(DK, DC, L, Id, PrevDecl), TypeForDecl(0) {}
-public:
- void setAccess(AccessSpecifier AS) { Access = AS; }
- AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= TypeFirst && D->getKind() <= TypeLast;
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Wed Jan 7 13:46:03 2009
@@ -141,6 +141,10 @@
/// HasAttrs - This indicates whether the decl has attributes or not.
unsigned int HasAttrs : 1;
+ /// Implicit - Whether this declaration was implicitly generated by
+ /// the implementation rather than explicitly written by the user.
+ bool Implicit : 1;
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
@@ -178,6 +182,12 @@
/// allows for graceful error recovery.
void setInvalidDecl() { InvalidDecl = 1; }
bool isInvalidDecl() const { return (bool) InvalidDecl; }
+
+ /// isImplicit - Indicates whether the declaration was implicitly
+ /// generated by the implementation. If false, this declaration
+ /// was written explicitly in the source code.
+ bool isImplicit() const { return Implicit; }
+ void setImplicit(bool I = true) { Implicit = I; }
IdentifierNamespace getIdentifierNamespace() const {
switch (DeclKind) {
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Jan 7 13:46:03 2009
@@ -463,9 +463,6 @@
return getLexicalDeclContext() != getDeclContext();
}
- void setAccess(AccessSpecifier AS) { Access = AS; }
- AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
-
/// getParent - Returns the parent of this method declaration, which
/// is the class in which this method is defined.
const CXXRecordDecl *getParent() const {
@@ -617,16 +614,12 @@
/// Explicit - Whether this constructor is explicit.
bool Explicit : 1;
- /// ImplicitlyDeclared - Whether this constructor was implicitly
- /// declared. When false, the constructor was declared by the user.
- bool ImplicitlyDeclared : 1;
-
/// ImplicitlyDefined - Whether this constructor was implicitly
/// defined by the compiler. When false, the constructor was defined
/// by the user. In C++03, this flag will have the same value as
- /// ImplicitlyDeclared. In C++0x, however, a constructor that is
+ /// Implicit. In C++0x, however, a constructor that is
/// explicitly defaulted (i.e., defined with " = default") will have
- /// @c !ImplicitlyDeclared && ImplicitlyDefined.
+ /// @c !Implicit && ImplicitlyDefined.
bool ImplicitlyDefined : 1;
/// FIXME: Add support for base and member initializers.
@@ -636,8 +629,9 @@
bool isExplicit, bool isInline, bool isImplicitlyDeclared)
: CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline,
/*PrevDecl=*/0),
- Explicit(isExplicit), ImplicitlyDeclared(isImplicitlyDeclared),
- ImplicitlyDefined(false) { }
+ Explicit(isExplicit), ImplicitlyDefined(false) {
+ setImplicit(isImplicitlyDeclared);
+ }
public:
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -648,11 +642,6 @@
/// isExplicit - Whether this constructor was marked "explicit" or not.
bool isExplicit() const { return Explicit; }
- /// isImplicitlyDeclared - Whether this constructor was implicitly
- /// declared. If false, then this constructor was explicitly
- /// declared by the user.
- bool isImplicitlyDeclared() const { return ImplicitlyDeclared; }
-
/// isImplicitlyDefined - Whether this constructor was implicitly
/// defined. If false, then this constructor was defined by the
/// user. This operation can only be invoked if the constructor has
@@ -728,16 +717,12 @@
/// };
/// @endcode
class CXXDestructorDecl : public CXXMethodDecl {
- /// ImplicitlyDeclared - Whether this destructor was implicitly
- /// declared. When false, the destructor was declared by the user.
- bool ImplicitlyDeclared : 1;
-
/// ImplicitlyDefined - Whether this destructor was implicitly
/// defined by the compiler. When false, the destructor was defined
/// by the user. In C++03, this flag will have the same value as
- /// ImplicitlyDeclared. In C++0x, however, a destructor that is
+ /// Implicit. In C++0x, however, a destructor that is
/// explicitly defaulted (i.e., defined with " = default") will have
- /// @c !ImplicitlyDeclared && ImplicitlyDefined.
+ /// @c !Implicit && ImplicitlyDefined.
bool ImplicitlyDefined : 1;
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
@@ -745,8 +730,9 @@
bool isInline, bool isImplicitlyDeclared)
: CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline,
/*PrevDecl=*/0),
- ImplicitlyDeclared(isImplicitlyDeclared),
- ImplicitlyDefined(false) { }
+ ImplicitlyDefined(false) {
+ setImplicit(isImplicitlyDeclared);
+ }
public:
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -754,11 +740,6 @@
QualType T, bool isInline,
bool isImplicitlyDeclared);
- /// isImplicitlyDeclared - Whether this destructor was implicitly
- /// declared. If false, then this destructor was explicitly
- /// declared by the user.
- bool isImplicitlyDeclared() const { return ImplicitlyDeclared; }
-
/// isImplicitlyDefined - Whether this destructor was implicitly
/// defined. If false, then this destructor was defined by the
/// user. This operation can only be invoked if the destructor has
@@ -857,9 +838,6 @@
SourceLocation L,IdentifierInfo *Id,
QualType T, ScopedDecl *PrevDecl);
- void setAccess(AccessSpecifier AS) { Access = AS; }
- AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
-
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == CXXClassVar; }
static bool classof(const CXXClassVarDecl *D) { return true; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jan 7 13:46:03 2009
@@ -1476,7 +1476,7 @@
"base class initializer %0 names both a direct base class and an"
" inherited virtual base class")
-// C++ anonymous unions and GNU anonymous structs
+// C++ anonymous unions and GNU anonymous structs/unions
DIAG(ext_anonymous_union, EXTENSION,
"anonymous unions are a GNU extension in C")
DIAG(ext_anonymous_struct, EXTENSION,
@@ -1491,6 +1491,16 @@
"member of anonymous union redeclares %0")
DIAG(err_anonymous_struct_member_redecl, ERROR,
"member of anonymous struct redeclares %0")
+DIAG(err_anonymous_record_with_type, ERROR,
+ "types cannot be declared in an anonymous %select{struct|union}0")
+DIAG(err_anonymous_record_with_function, ERROR,
+ "functions cannot be declared in an anonymous %select{struct|union}0")
+DIAG(err_anonymous_record_with_static, ERROR,
+ "static members cannot be declared in an anonymous %select{struct|union}0")
+DIAG(err_anonymous_record_bad_member, ERROR,
+ "anonymous %select{struct|union}0 can only contain non-static data members")
+DIAG(err_anonymous_record_nonpublic_member, ERROR,
+ "anonymous %select{struct|union}0 cannot contain a %select{private|protected}1 data member")
// Derived classes.
DIAG(err_dup_virtual, ERROR,
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Jan 7 13:46:03 2009
@@ -97,6 +97,15 @@
return new (Mem) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable, PrevDecl);
}
+bool FieldDecl::isAnonymousStructOrUnion() const {
+ if (!isImplicit() || getDeclName())
+ return false;
+
+ if (const RecordType *Record = getType()->getAsRecordType())
+ return Record->getDecl()->isAnonymousStructOrUnion();
+
+ return false;
+}
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
SourceLocation L,
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Jan 7 13:46:03 2009
@@ -153,7 +153,7 @@
void
CXXRecordDecl::addedConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
- if (!ConDecl->isImplicitlyDeclared()) {
+ if (!ConDecl->isImplicit()) {
// Note that we have a user-declared constructor.
UserDeclaredConstructor = true;
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 7 13:46:03 2009
@@ -924,6 +924,48 @@
DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
PrevSpec);
}
+
+ // C++ [class.union]p2:
+ // The member-specification of an anonymous union shall only
+ // define non-static data members. [Note: nested types and
+ // functions cannot be declared within an anonymous union. ]
+ for (DeclContext::decl_iterator Mem = Record->decls_begin(),
+ MemEnd = Record->decls_end();
+ Mem != MemEnd; ++Mem) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) {
+ // C++ [class.union]p3:
+ // An anonymous union shall not have private or protected
+ // members (clause 11).
+ if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
+ Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
+ << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
+ Invalid = true;
+ }
+ } else if ((*Mem)->isImplicit()) {
+ // Any implicit members are fine.
+ } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) {
+ if (!MemRecord->isAnonymousStructOrUnion() &&
+ MemRecord->getDeclName()) {
+ // This is a nested type declaration.
+ Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type)
+ << (int)Record->isUnion();
+ Invalid = true;
+ }
+ } else {
+ // We have something that isn't a non-static data
+ // member. Complain about it.
+ unsigned DK = diag::err_anonymous_record_bad_member;
+ if (isa<TypeDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_type;
+ else if (isa<FunctionDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_function;
+ else if (isa<VarDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_static;
+ Diag((*Mem)->getLocation(), DK)
+ << (int)Record->isUnion();
+ Invalid = true;
+ }
+ }
} else {
// FIXME: Check GNU C semantics
}
@@ -941,6 +983,9 @@
Context.getTypeDeclType(Record),
/*BitWidth=*/0, /*Mutable=*/false,
/*PrevDecl=*/0);
+ Anon->setAccess(AS_public);
+ if (getLangOptions().CPlusPlus)
+ FieldCollector->Add(cast<FieldDecl>(Anon));
} else {
VarDecl::StorageClass SC;
switch (DS.getStorageClassSpec()) {
@@ -966,6 +1011,7 @@
SC, /*FIXME:LastDeclarator=*/0,
DS.getSourceRange().getBegin());
}
+ Anon->setImplicit();
// Add the anonymous struct/union object to the current
// context. We'll be referencing this object when we refer to one of
@@ -3176,18 +3222,52 @@
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
llvm::SmallVector<FieldDecl*, 32> RecFields;
- llvm::SmallSet<const IdentifierInfo*, 32> FieldIDs;
+
+ // FIXME: Eventually, we'd like to eliminate this in favor of
+ // checking for redeclarations on-the-fly.
+ llvm::DenseMap<const IdentifierInfo*, FieldDecl *> FieldIDs;
for (unsigned i = 0; i != NumFields; ++i) {
-
FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
assert(FD && "missing field decl");
- // Remember all fields.
- RecFields.push_back(FD);
-
// Get the type for the field.
Type *FDTy = FD->getType().getTypePtr();
+
+ if (FD->isAnonymousStructOrUnion()) {
+ // We have found a field that represents an anonymous struct
+ // or union. Introduce all of the inner fields (recursively)
+ // into the list of fields we know about, so that we can produce
+ // an appropriate error message in cases like:
+ //
+ // struct X {
+ // union {
+ // int x;
+ // float f;
+ // };
+ // double x;
+ // };
+ llvm::SmallVector<FieldDecl *, 4> AnonStructUnionFields;
+ AnonStructUnionFields.push_back(FD);
+ while (!AnonStructUnionFields.empty()) {
+ FieldDecl *AnonField = AnonStructUnionFields.back();
+ AnonStructUnionFields.pop_back();
+
+ RecordDecl *AnonRecord
+ = AnonField->getType()->getAsRecordType()->getDecl();
+ for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
+ FEnd = AnonRecord->field_end();
+ F != FEnd; ++F) {
+ if ((*F)->isAnonymousStructOrUnion())
+ AnonStructUnionFields.push_back(*F);
+ else if (const IdentifierInfo *II = (*F)->getIdentifier())
+ FieldIDs[II] = *F;
+ }
+ }
+ } else {
+ // Remember all fields written by the user.
+ RecFields.push_back(FD);
+ }
// C99 6.7.2.1p2 - A field may not be a function type.
if (FDTy->isFunctionType()) {
@@ -3262,23 +3342,16 @@
// Keep track of the number of named members.
if (IdentifierInfo *II = FD->getIdentifier()) {
// Detect duplicate member names.
- if (!FieldIDs.insert(II)) {
+ if (FieldIDs[II]) {
Diag(FD->getLocation(), diag::err_duplicate_member) << II;
// Find the previous decl.
- SourceLocation PrevLoc;
- for (unsigned i = 0; ; ++i) {
- assert(i != RecFields.size() && "Didn't find previous def!");
- if (RecFields[i]->getIdentifier() == II) {
- PrevLoc = RecFields[i]->getLocation();
- break;
- }
- }
- Diag(PrevLoc, diag::note_previous_definition);
+ Diag(FieldIDs[II]->getLocation(), diag::note_previous_definition);
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
}
++NumNamedMembers;
+ FieldIDs[II] = FD;
}
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 7 13:46:03 2009
@@ -427,9 +427,12 @@
// class itself; this is known as the injected-class-name. For
// purposes of access checking, the injected-class-name is treated
// as if it were a public member name.
- PushOnScopeChains(CXXRecordDecl::Create(Context, Dcl->getTagKind(),
- CurContext, Dcl->getLocation(),
- Dcl->getIdentifier(), Dcl), S);
+ RecordDecl *InjectedClassName
+ = CXXRecordDecl::Create(Context, Dcl->getTagKind(),
+ CurContext, Dcl->getLocation(),
+ Dcl->getIdentifier(), Dcl);
+ InjectedClassName->setImplicit();
+ PushOnScopeChains(InjectedClassName, S);
}
}
@@ -789,6 +792,7 @@
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
+ DefaultCon->setImplicit();
ClassDecl->addDecl(Context, DefaultCon);
// Notify the class that we've added a constructor.
@@ -860,6 +864,7 @@
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
+ CopyConstructor->setImplicit();
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
@@ -936,6 +941,7 @@
false, 0),
/*isStatic=*/false, /*isInline=*/true, 0);
CopyAssignment->setAccess(AS_public);
+ CopyAssignment->setImplicit();
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
@@ -964,6 +970,7 @@
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
+ Destructor->setImplicit();
ClassDecl->addDecl(Context, Destructor);
}
}
Modified: cfe/trunk/test/SemaCXX/anonymous-union.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/anonymous-union.cpp?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/anonymous-union.cpp (original)
+++ cfe/trunk/test/SemaCXX/anonymous-union.cpp Wed Jan 7 13:46:03 2009
@@ -66,11 +66,11 @@
union {
int x; // expected-error{{member of anonymous union redeclares 'x'}}
float y;
- double z; // FIXME: note here
+ double z; // expected-note{{previous definition is here}}
double zz; // expected-note{{previous definition is here}}
};
- int z; // FIXME: should complain here!
+ int z; // expected-error{{duplicate member 'z'}}
void zz(); // expected-error{{redefinition of 'zz' as different kind of symbol}}
};
@@ -92,8 +92,19 @@
void g() {
union {
int i;
- float f;
+ float f2;
};
i = 0;
- f = 0.0;
+ f2 = 0.0;
}
+
+struct BadMembers {
+ union {
+ struct X { }; // expected-error {{types cannot be declared in an anonymous union}}
+ struct { int x; int y; } y;
+
+ void f(); // expected-error{{functions cannot be declared in an anonymous union}}
+ private: int x1; // expected-error{{anonymous union cannot contain a private data member}}
+ protected: float x2; // expected-error{{anonymous union cannot contain a protected data member}}
+ };
+};
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=61878&r1=61877&r2=61878&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Jan 7 13:46:03 2009
@@ -1077,10 +1077,10 @@
<tr>
<td> 9.5 [class.union]</td>
<td class="complete" align="center">✓</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="complete" align="center">✓</td>
+ <td class="medium"></td>
+ <td class="medium"></td>
+ <td>Semantic analysis does not yet check all of the requirements placed on the members of unions.</td>
</tr>
<tr>
<td> 9.6 [class.bit]</td>
More information about the cfe-commits
mailing list