[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">&#x2713;</td>  
-  <td></td>
-  <td></td>
-  <td></td>
-  <td></td>
+  <td class="complete" align="center">&#x2713;</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