r196892 - Implement DR1460: fix handling of default initializers in unions; don't allow

Richard Smith richard-llvm at metafoo.co.uk
Tue Dec 10 00:25:01 PST 2013


Author: rsmith
Date: Tue Dec 10 02:25:00 2013
New Revision: 196892

URL: http://llvm.org/viewvc/llvm-project?rev=196892&view=rev
Log:
Implement DR1460: fix handling of default initializers in unions; don't allow
more than one such initializer in a union, make mem-initializers override
default initializers for other union members, handle anonymous unions with
anonymous struct members better. Fix a couple of semi-related bugs exposed by
the tests for same.

Added:
    cfe/trunk/test/CXX/class/class.union/p8.cpp
    cfe/trunk/test/CXX/drs/dr14xx.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp
    cfe/trunk/test/CodeGenCXX/member-init-anon-union.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Dec 10 02:25:00 2013
@@ -350,10 +350,15 @@ class CXXRecordDecl : public RecordDecl
     /// \brief True if this class (or any subobject) has mutable fields.
     bool HasMutableFields : 1;
 
+    /// \brief True if this class (or any nested anonymous struct or union)
+    /// has variant members.
+    bool HasVariantMembers : 1;
+
     /// \brief True if there no non-field members declared by the user.
     bool HasOnlyCMembers : 1;
 
-    /// \brief True if any field has an in-class initializer.
+    /// \brief True if any field has an in-class initializer, including those
+    /// within anonymous unions or structs.
     bool HasInClassInitializer : 1;
 
     /// \brief True if any field is of reference type, and does not have an
@@ -1058,7 +1063,8 @@ public:
   bool isAggregate() const { return data().Aggregate; }
 
   /// \brief Whether this class has any in-class initializers
-  /// for non-static data members.
+  /// for non-static data members (including those in anonymous unions or
+  /// structs).
   bool hasInClassInitializer() const { return data().HasInClassInitializer; }
 
   /// \brief Whether this class or any of its subobjects has any members of
@@ -1117,6 +1123,9 @@ public:
   /// contains a mutable field.
   bool hasMutableFields() const { return data().HasMutableFields; }
 
+  /// \brief Determine whether this class has any variant members.
+  bool hasVariantMembers() const { return data().HasVariantMembers; }
+
   /// \brief Determine whether this class has a trivial default constructor
   /// (C++11 [class.ctor]p5).
   bool hasTrivialDefaultConstructor() const {
@@ -1144,7 +1153,7 @@ public:
   /// would be constexpr.
   bool defaultedDefaultConstructorIsConstexpr() const {
     return data().DefaultedDefaultConstructorIsConstexpr &&
-           (!isUnion() || hasInClassInitializer());
+           (!isUnion() || hasInClassInitializer() || !hasVariantMembers());
   }
 
   /// \brief Determine whether this class has a constexpr default constructor.

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Dec 10 02:25:00 2013
@@ -1947,6 +1947,7 @@ bool ASTNodeImporter::ImportDefinition(R
     ToData.HasProtectedFields = FromData.HasProtectedFields;
     ToData.HasPublicFields = FromData.HasPublicFields;
     ToData.HasMutableFields = FromData.HasMutableFields;
+    ToData.HasVariantMembers = FromData.HasVariantMembers;
     ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
     ToData.HasInClassInitializer = FromData.HasInClassInitializer;
     ToData.HasUninitializedReferenceMember

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Dec 10 02:25:00 2013
@@ -50,7 +50,7 @@ CXXRecordDecl::DefinitionData::Definitio
     Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
     Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
     HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
-    HasMutableFields(false), HasOnlyCMembers(true),
+    HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true),
     HasInClassInitializer(false), HasUninitializedReferenceMember(false),
     NeedOverloadResolutionForMoveConstructor(false),
     NeedOverloadResolutionForMoveAssignment(false),
@@ -653,7 +653,13 @@ void CXXRecordDecl::addedMember(Decl *D)
     // Keep track of the presence of mutable fields.
     if (Field->isMutable())
       data().HasMutableFields = true;
-    
+
+    // C++11 [class.union]p8, DR1460:
+    //   If X is a union, a non-static data member of X that is not an anonymous
+    //   union is a variant member of X.
+    if (isUnion() && !Field->isAnonymousStructOrUnion())
+      data().HasVariantMembers = true;
+
     // C++0x [class]p9:
     //   A POD struct is a class that is both a trivial class and a 
     //   standard-layout class, and has no non-static data members of type 
@@ -689,7 +695,9 @@ void CXXRecordDecl::addedMember(Decl *D)
     if (!T->isLiteralType(Context) || T.isVolatileQualified())
       data().HasNonLiteralTypeFieldsOrBases = true;
 
-    if (Field->hasInClassInitializer()) {
+    if (Field->hasInClassInitializer() ||
+        (Field->isAnonymousStructOrUnion() &&
+         Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
       data().HasInClassInitializer = true;
 
       // C++11 [class]p5:
@@ -806,7 +814,7 @@ void CXXRecordDecl::addedMember(Decl *D)
         // Virtual bases and virtual methods make a class non-empty, but they
         // also make it non-standard-layout so we needn't check here.
         // A non-empty base class may leave the class standard-layout, but not
-        // if we have arrived here, and have at least on non-static data
+        // if we have arrived here, and have at least one non-static data
         // member. If IsStandardLayout remains true, then the first non-static
         // data member must come through here with Empty still true, and Empty
         // will subsequently be set to false below.
@@ -859,6 +867,13 @@ void CXXRecordDecl::addedMember(Decl *D)
         if (FieldRec->hasUninitializedReferenceMember() &&
             !Field->hasInClassInitializer())
           data().HasUninitializedReferenceMember = true;
+
+        // C++11 [class.union]p8, DR1460:
+        //   a non-static data member of an anonymous union that is a member of
+        //   X is also a variant member of X.
+        if (FieldRec->hasVariantMembers() &&
+            Field->isAnonymousStructOrUnion())
+          data().HasVariantMembers = true;
       }
     } else {
       // Base element type of field is a non-class type.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 10 02:25:00 2013
@@ -3547,6 +3547,39 @@ StorageClassSpecToVarDeclStorageClass(co
   llvm_unreachable("unknown storage class specifier");
 }
 
+static SourceLocation findDefaultInitializer(const CXXRecordDecl *Record) {
+  assert(Record->hasInClassInitializer());
+
+  for (DeclContext::decl_iterator I = Record->decls_begin(),
+                                  E = Record->decls_end();
+       I != E; ++I) {
+    FieldDecl *FD = dyn_cast<FieldDecl>(*I);
+    if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*I))
+      FD = IFD->getAnonField();
+    if (FD && FD->hasInClassInitializer())
+      return FD->getLocation();
+  }
+
+  llvm_unreachable("couldn't find in-class initializer");
+}
+
+static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent,
+                                      SourceLocation DefaultInitLoc) {
+  if (!Parent->isUnion() || !Parent->hasInClassInitializer())
+    return;
+
+  S.Diag(DefaultInitLoc, diag::err_multiple_mem_union_initialization);
+  S.Diag(findDefaultInitializer(Parent), diag::note_previous_initializer) << 0;
+}
+
+static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent,
+                                      CXXRecordDecl *AnonUnion) {
+  if (!Parent->isUnion() || !Parent->hasInClassInitializer())
+    return;
+
+  checkDuplicateDefaultInit(S, Parent, findDefaultInitializer(AnonUnion));
+}
+
 /// BuildAnonymousStructOrUnion - Handle the declaration of an
 /// anonymous structure or union. Anonymous unions are a C++ feature
 /// (C++ [class.union]) and a C11 feature; anonymous structures
@@ -3704,6 +3737,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(
         }
       }
     }
+
+    // C++11 [class.union]p8 (DR1460):
+    //   At most one variant member of a union may have a
+    //   brace-or-equal-initializer.
+    if (cast<CXXRecordDecl>(Record)->hasInClassInitializer() &&
+        Owner->isRecord())
+      checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Owner),
+                                cast<CXXRecordDecl>(Record));
   }
 
   if (!Record->isUnion() && !Owner->isRecord()) {
@@ -3756,11 +3797,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(
   }
   Anon->setImplicit();
 
+  // Mark this as an anonymous struct/union type.
+  Record->setAnonymousStructOrUnion(true);
+
   // Add the anonymous struct/union object to the current
   // context. We'll be referencing this object when we refer to one of
   // its members.
   Owner->addDecl(Anon);
-  
+
   // Inject the members of the anonymous struct/union into the owning
   // context and into the identifier resolver chain for name lookup
   // purposes.
@@ -3771,14 +3815,6 @@ Decl *Sema::BuildAnonymousStructOrUnion(
                                           Chain, false))
     Invalid = true;
 
-  // Mark this as an anonymous struct/union type. Note that we do not
-  // do this until after we have already checked and injected the
-  // members of this anonymous struct/union type, because otherwise
-  // the members could be injected twice: once by DeclContext when it
-  // builds its lookup table, and once by
-  // InjectAnonymousStructOrUnionMembers.
-  Record->setAnonymousStructOrUnion(true);
-
   if (Invalid)
     Anon->setInvalidDecl();
 
@@ -11516,6 +11552,12 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
     }
   }
 
+  // C++11 [class.union]p8 (DR1460):
+  //   At most one variant member of a union may have a
+  //   brace-or-equal-initializer.
+  if (InitStyle != ICIS_NoInit)
+    checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc);
+
   FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
                                        BitWidth, Mutable, InitStyle);
   if (InvalidDecl)

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 10 02:25:00 2013
@@ -880,7 +880,8 @@ static bool CheckConstexprDeclStmt(Sema
               diag::err_constexpr_local_var_non_literal_type,
               isa<CXXConstructorDecl>(Dcl)))
           return false;
-        if (!VD->hasInit() && !VD->isCXXForRangeDecl()) {
+        if (!VD->getType()->isDependentType() &&
+            !VD->hasInit() && !VD->isCXXForRangeDecl()) {
           SemaRef.Diag(VD->getLocation(),
                        diag::err_constexpr_local_var_no_init)
             << isa<CXXConstructorDecl>(Dcl);
@@ -932,8 +933,13 @@ static void CheckConstexprCtorInitialize
   if (Field->isUnnamedBitfield())
     return;
 
+  // Anonymous unions with no variant members and empty anonymous structs do not
+  // need to be explicitly initialized. FIXME: Anonymous structs that contain no
+  // indirect fields don't need initializing.
   if (Field->isAnonymousStructOrUnion() &&
-      Field->getType()->getAsCXXRecordDecl()->isEmpty())
+      (Field->getType()->isUnionType()
+           ? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
+           : Field->getType()->getAsCXXRecordDecl()->isEmpty()))
     return;
 
   if (!Inits.count(Field)) {
@@ -1116,11 +1122,12 @@ bool Sema::CheckConstexprFunctionBody(co
     // DR1359:
     // - every non-variant non-static data member and base class sub-object
     //   shall be initialized;
-    // - if the class is a non-empty union, or for each non-empty anonymous
-    //   union member of a non-union class, exactly one non-static data member
+    // DR1460:
+    // - if the class is a union having variant members, exactly one of them
     //   shall be initialized;
     if (RD->isUnion()) {
-      if (Constructor->getNumCtorInitializers() == 0 && !RD->isEmpty()) {
+      if (Constructor->getNumCtorInitializers() == 0 &&
+          RD->hasVariantMembers()) {
         Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
         return false;
       }
@@ -1139,6 +1146,10 @@ bool Sema::CheckConstexprFunctionBody(co
           break;
         }
       }
+      // DR1460:
+      // - if the class is a union-like class, but is not a union, for each of
+      //   its anonymous union members having variant members, exactly one of
+      //   them shall be initialized;
       if (AnyAnonStructUnionMembers ||
           Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) {
         // Check initialization of non-static data members. Base classes are
@@ -3320,6 +3331,7 @@ struct BaseAndFieldInfo {
   ImplicitInitializerKind IIK;
   llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields;
   SmallVector<CXXCtorInitializer*, 8> AllToInit;
+  llvm::DenseMap<TagDecl*, FieldDecl*> ActiveUnionMember;
 
   BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
     : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
@@ -3357,20 +3369,50 @@ struct BaseAndFieldInfo {
 
     return false;
   }
-};
-}
 
-/// \brief Determine whether the given indirect field declaration is somewhere
-/// within an anonymous union.
-static bool isWithinAnonymousUnion(IndirectFieldDecl *F) {
-  for (IndirectFieldDecl::chain_iterator C = F->chain_begin(), 
-                                      CEnd = F->chain_end();
-       C != CEnd; ++C)
-    if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((*C)->getDeclContext()))
-      if (Record->isUnion())
+  bool isInactiveUnionMember(FieldDecl *Field) {
+    RecordDecl *Record = Field->getParent();
+    if (!Record->isUnion())
+      return false;
+
+    FieldDecl *Active = ActiveUnionMember.lookup(Record->getCanonicalDecl());
+    if (Active)
+      return Active != Field->getCanonicalDecl();
+
+    // In an implicit copy or move constructor, ignore any in-class initializer.
+    if (isImplicitCopyOrMove())
+      return true;
+
+    // If there's no explicit initialization, the field is active only if it
+    // has an in-class initializer...
+    if (Field->hasInClassInitializer())
+      return false;
+    // ... or it's an anonymous struct or union whose class has an in-class
+    // initializer.
+    if (!Field->isAnonymousStructOrUnion())
+      return true;
+    CXXRecordDecl *FieldRD = Field->getType()->getAsCXXRecordDecl();
+    return !FieldRD->hasInClassInitializer();
+  }
+
+  /// \brief Determine whether the given field is, or is within, a union member
+  /// that is inactive (because there was an initializer given for a different
+  /// member of the union, or because the union was not initialized at all).
+  bool isWithinInactiveUnionMember(FieldDecl *Field,
+                                   IndirectFieldDecl *Indirect) {
+    if (!Indirect)
+      return isInactiveUnionMember(Field);
+
+    for (IndirectFieldDecl::chain_iterator C = Indirect->chain_begin(),
+                                           CEnd = Indirect->chain_end();
+         C != CEnd; ++C) {
+      FieldDecl *Field = dyn_cast<FieldDecl>(*C);
+      if (Field && isInactiveUnionMember(Field))
         return true;
-        
-  return false;
+    }
+    return false;
+  }
+};
 }
 
 /// \brief Determine whether the given type is an incomplete or zero-lenfgth
@@ -3399,9 +3441,21 @@ static bool CollectFieldInitializer(Sema
   if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
     return Info.addFieldInitializer(Init);
 
-  // C++11 [class.base.init]p8: if the entity is a non-static data member that
-  // has a brace-or-equal-initializer, the entity is initialized as specified
-  // in [dcl.init].
+  // C++11 [class.base.init]p8:
+  //   if the entity is a non-static data member that has a
+  //   brace-or-equal-initializer and either
+  //   -- the constructor's class is a union and no other variant member of that
+  //      union is designated by a mem-initializer-id or
+  //   -- the constructor's class is not a union, and, if the entity is a member
+  //      of an anonymous union, no other member of that union is designated by
+  //      a mem-initializer-id,
+  //   the entity is initialized as specified in [dcl.init].
+  //
+  // We also apply the same rules to handle anonymous structs within anonymous
+  // unions.
+  if (Info.isWithinInactiveUnionMember(Field, Indirect))
+    return false;
+
   if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
     Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
                                            Info.Ctor->getLocation(), Field);
@@ -3419,12 +3473,6 @@ static bool CollectFieldInitializer(Sema
     return Info.addFieldInitializer(Init);
   }
 
-  // Don't build an implicit initializer for union members if none was
-  // explicitly specified.
-  if (Field->getParent()->isUnion() ||
-      (Indirect && isWithinAnonymousUnion(Indirect)))
-    return false;
-
   // Don't initialize incomplete or zero-length arrays.
   if (isIncompleteOrZeroLengthArrayType(SemaRef.Context, Field->getType()))
     return false;
@@ -3502,8 +3550,24 @@ bool Sema::SetCtorInitializers(CXXConstr
 
     if (Member->isBaseInitializer())
       Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
-    else
+    else {
       Info.AllBaseFields[Member->getAnyMember()] = Member;
+
+      if (IndirectFieldDecl *F = Member->getIndirectMember()) {
+        for (IndirectFieldDecl::chain_iterator C = F->chain_begin(),
+                                            CEnd = F->chain_end();
+             C != CEnd; ++C) {
+          FieldDecl *FD = dyn_cast<FieldDecl>(*C);
+          if (FD && FD->getParent()->isUnion())
+            Info.ActiveUnionMember.insert(std::make_pair(
+                FD->getParent()->getCanonicalDecl(), FD->getCanonicalDecl()));
+        }
+      } else if (FieldDecl *FD = Member->getMember()) {
+        if (FD->getParent()->isUnion())
+          Info.ActiveUnionMember.insert(std::make_pair(
+              FD->getParent()->getCanonicalDecl(), FD->getCanonicalDecl()));
+      }
+    }
   }
 
   // Keep track of the direct virtual bases.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Dec 10 02:25:00 2013
@@ -11184,37 +11184,34 @@ void Sema::MarkFunctionReferenced(Source
 
   // Note that this declaration has been used.
   if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+    Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
     if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
       if (Constructor->isDefaultConstructor()) {
         if (Constructor->isTrivial())
           return;
-        if (!Constructor->isUsed(false))
-          DefineImplicitDefaultConstructor(Loc, Constructor);
+        DefineImplicitDefaultConstructor(Loc, Constructor);
       } else if (Constructor->isCopyConstructor()) {
-        if (!Constructor->isUsed(false))
-          DefineImplicitCopyConstructor(Loc, Constructor);
+        DefineImplicitCopyConstructor(Loc, Constructor);
       } else if (Constructor->isMoveConstructor()) {
-        if (!Constructor->isUsed(false))
-          DefineImplicitMoveConstructor(Loc, Constructor);
+        DefineImplicitMoveConstructor(Loc, Constructor);
       }
     } else if (Constructor->getInheritedConstructor()) {
-      if (!Constructor->isUsed(false))
-        DefineInheritingConstructor(Loc, Constructor);
+      DefineInheritingConstructor(Loc, Constructor);
     }
 
     MarkVTableUsed(Loc, Constructor->getParent());
   } else if (CXXDestructorDecl *Destructor =
                  dyn_cast<CXXDestructorDecl>(Func)) {
-    if (Destructor->isDefaulted() && !Destructor->isDeleted() &&
-        !Destructor->isUsed(false))
+    Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+    if (Destructor->isDefaulted() && !Destructor->isDeleted())
       DefineImplicitDestructor(Loc, Destructor);
     if (Destructor->isVirtual())
       MarkVTableUsed(Loc, Destructor->getParent());
   } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
-    if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted() &&
-        MethodDecl->isOverloadedOperator() &&
+    if (MethodDecl->isOverloadedOperator() &&
         MethodDecl->getOverloadedOperator() == OO_Equal) {
-      if (!MethodDecl->isUsed(false)) {
+      MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+      if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
         if (MethodDecl->isCopyAssignmentOperator())
           DefineImplicitCopyAssignment(Loc, MethodDecl);
         else
@@ -11222,7 +11219,8 @@ void Sema::MarkFunctionReferenced(Source
       }
     } else if (isa<CXXConversionDecl>(MethodDecl) &&
                MethodDecl->getParent()->isLambda()) {
-      CXXConversionDecl *Conversion = cast<CXXConversionDecl>(MethodDecl);
+      CXXConversionDecl *Conversion =
+          cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
       if (Conversion->isLambdaToBlockPointerConversion())
         DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
       else

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Dec 10 02:25:00 2013
@@ -1187,6 +1187,7 @@ void ASTDeclReader::ReadCXXDefinitionDat
   Data.HasProtectedFields = Record[Idx++];
   Data.HasPublicFields = Record[Idx++];
   Data.HasMutableFields = Record[Idx++];
+  Data.HasVariantMembers = Record[Idx++];
   Data.HasOnlyCMembers = Record[Idx++];
   Data.HasInClassInitializer = Record[Idx++];
   Data.HasUninitializedReferenceMember = Record[Idx++];

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Dec 10 02:25:00 2013
@@ -5092,6 +5092,7 @@ void ASTWriter::AddCXXDefinitionData(con
   Record.push_back(Data.HasProtectedFields);
   Record.push_back(Data.HasPublicFields);
   Record.push_back(Data.HasMutableFields);
+  Record.push_back(Data.HasVariantMembers);
   Record.push_back(Data.HasOnlyCMembers);
   Record.push_back(Data.HasInClassInitializer);
   Record.push_back(Data.HasUninitializedReferenceMember);

Added: cfe/trunk/test/CXX/class/class.union/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.union/p8.cpp?rev=196892&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class/class.union/p8.cpp (added)
+++ cfe/trunk/test/CXX/class/class.union/p8.cpp Tue Dec 10 02:25:00 2013
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+union U {
+  int x = 0; // expected-note {{previous initialization is here}}
+  union {};
+  union {
+    int z;
+    int y = 1; // expected-error {{initializing multiple members of union}}
+  };
+};

Added: cfe/trunk/test/CXX/drs/dr14xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=196892&view=auto
==============================================================================
--- cfe/trunk/test/CXX/drs/dr14xx.cpp (added)
+++ cfe/trunk/test/CXX/drs/dr14xx.cpp Tue Dec 10 02:25:00 2013
@@ -0,0 +1,196 @@
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+#if __cplusplus < 201103L
+// expected-no-diagnostics
+#endif
+
+namespace dr1460 { // dr1460: 3.5
+#if __cplusplus >= 201103L
+  namespace DRExample {
+    union A {
+      union {};
+      union {};
+      constexpr A() {}
+    };
+    constexpr A a = A();
+
+    union B {
+      union {};
+      union {};
+      constexpr B() = default;
+    };
+    constexpr B b = B();
+
+    union C {
+      union {};
+      union {};
+    };
+    constexpr C c = C();
+#if __cplusplus > 201103L
+    constexpr void f() { C c; }
+    static_assert((f(), true), "");
+#endif
+  }
+
+  union A {};
+  union B { int n; }; // expected-note +{{here}}
+  union C { int n = 0; };
+  struct D { union {}; };
+  struct E { union { int n; }; }; // expected-note +{{here}}
+  struct F { union { int n = 0; }; };
+
+  struct X {
+    friend constexpr A::A() noexcept;
+    friend constexpr B::B() noexcept; // expected-error {{follows non-constexpr declaration}}
+    friend constexpr C::C() noexcept;
+    friend constexpr D::D() noexcept;
+    friend constexpr E::E() noexcept; // expected-error {{follows non-constexpr declaration}}
+    friend constexpr F::F() noexcept;
+  };
+
+  // These are OK, because value-initialization doesn't actually invoke the
+  // constructor.
+  constexpr A a = A();
+  constexpr B b = B();
+  constexpr C c = C();
+  constexpr D d = D();
+  constexpr E e = E();
+  constexpr F f = F();
+
+  namespace Defaulted {
+    union A { constexpr A() = default; };
+    union B { int n; constexpr B() = default; }; // expected-error {{not constexpr}}
+    union C { int n = 0; constexpr C() = default; };
+    struct D { union {}; constexpr D() = default; };
+    struct E { union { int n; }; constexpr E() = default; }; // expected-error {{not constexpr}}
+    struct F { union { int n = 0; }; constexpr F() = default; };
+
+    struct G { union { int n = 0; }; union { int m; }; constexpr G() = default; }; // expected-error {{not constexpr}}
+    struct H {
+      union {
+        int n = 0;
+      };
+      union { // expected-note 2{{member not initialized}}
+        int m;
+      };
+      constexpr H() {} // expected-error {{must initialize all members}}
+      constexpr H(bool) : m(1) {}
+      constexpr H(char) : n(1) {} // expected-error {{must initialize all members}}
+      constexpr H(double) : m(1), n(1) {}
+    };
+  }
+
+#if __cplusplus > 201103L
+  template<typename T> constexpr bool check() {
+    T t; // expected-note-re 2{{non-constexpr constructor '[BE]'}}
+    return true;
+  }
+  static_assert(check<A>(), "");
+  static_assert(check<B>(), ""); // expected-error {{constant}} expected-note {{in call}}
+  static_assert(check<C>(), "");
+  static_assert(check<D>(), "");
+  static_assert(check<E>(), ""); // expected-error {{constant}} expected-note {{in call}}
+  static_assert(check<F>(), "");
+#endif
+
+  union G {
+    int a = 0; // expected-note {{previous initialization is here}}
+    int b = 0; // expected-error {{initializing multiple members of union}}
+  };
+  union H {
+    union {
+      int a = 0; // expected-note {{previous initialization is here}}
+    };
+    union {
+      int b = 0; // expected-error {{initializing multiple members of union}}
+    };
+  };
+  struct I {
+    union {
+      int a = 0; // expected-note {{previous initialization is here}}
+      int b = 0; // expected-error {{initializing multiple members of union}}
+    };
+  };
+  struct J {
+    union { int a = 0; };
+    union { int b = 0; };
+  };
+
+  namespace Overriding {
+    struct A {
+      int a = 1, b, c = 3;
+      constexpr A() : b(2) {}
+    };
+    static_assert(A().a == 1 && A().b == 2 && A().c == 3, "");
+
+    union B {
+      int a, b = 2, c;
+      constexpr B() : a(1) {}
+      constexpr B(char) : b(4) {}
+      constexpr B(int) : c(3) {}
+      constexpr B(const char*) {}
+    };
+    static_assert(B().a == 1, "");
+    static_assert(B().b == 2, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(B('x').a == 0, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(B('x').b == 4, "");
+    static_assert(B(123).b == 2, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(B(123).c == 3, "");
+    static_assert(B("").a == 1, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(B("").b == 2, "");
+    static_assert(B("").c == 3, ""); // expected-error {{constant}} expected-note {{read of}}
+
+    struct C {
+      union { int a, b = 2, c; };
+      union { int d, e = 5, f; };
+      constexpr C() : a(1) {}
+      constexpr C(char) : c(3) {}
+      constexpr C(int) : d(4) {}
+      constexpr C(float) : f(6) {}
+      constexpr C(const char*) {}
+    };
+
+    static_assert(C().a == 1, "");
+    static_assert(C().b == 2, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C().d == 4, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C().e == 5, "");
+
+    static_assert(C('x').b == 2, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C('x').c == 3, "");
+    static_assert(C('x').d == 4, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C('x').e == 5, "");
+
+    static_assert(C(1).b == 2, "");
+    static_assert(C(1).c == 3, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C(1).d == 4, "");
+    static_assert(C(1).e == 5, ""); // expected-error {{constant}} expected-note {{read of}}
+
+    static_assert(C(1.f).b == 2, "");
+    static_assert(C(1.f).c == 3, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C(1.f).e == 5, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C(1.f).f == 6, "");
+
+    static_assert(C("").a == 1, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C("").b == 2, "");
+    static_assert(C("").c == 3, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C("").d == 4, ""); // expected-error {{constant}} expected-note {{read of}}
+    static_assert(C("").e == 5, "");
+    static_assert(C("").f == 6, ""); // expected-error {{constant}} expected-note {{read of}}
+
+    struct D;
+    extern const D d;
+    struct D {
+      int a;
+      union {
+        int b = const_cast<D&>(d).a = 1; // not evaluated
+        int c;
+      };
+      constexpr D() : a(0), c(0) {}
+    };
+    constexpr D d {};
+    static_assert(d.a == 0, "");
+  }
+#endif
+}

Modified: cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp Tue Dec 10 02:25:00 2013
@@ -16,16 +16,13 @@ struct S {
 } s(0);
 
 union U {
-  int a = 0; // desired-note 5 {{previous initialization is here}}
-  char b = 'x';
+  int a = 0; // expected-note {{previous initialization}}
+  char b = 'x'; // expected-error {{initializing multiple members of union}}
 
-  // FIXME: these should all be rejected
-  U() {} // desired-error {{initializing multiple members of union}}
-  U(int) : a(1) {} // desired-error {{initializing multiple members of union}}
-  U(char) : b('y') {} // desired-error {{initializing multiple members of union}}
-  // this expected note should be removed & the note should appear on the 
-  // declaration of 'a' when this set of cases is handled correctly.
-  U(double) : a(1), // expected-note{{previous initialization is here}} desired-error {{initializing multiple members of union}}
+  U() {}
+  U(int) : a(1) {}
+  U(char) : b('y') {}
+  U(double) : a(1), // expected-note{{previous initialization is here}}
               b('y') {} // expected-error{{initializing multiple members of union}}
 };
 

Modified: cfe/trunk/test/CodeGenCXX/member-init-anon-union.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-anon-union.cpp?rev=196892&r1=196891&r2=196892&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-init-anon-union.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/member-init-anon-union.cpp Tue Dec 10 02:25:00 2013
@@ -21,12 +21,42 @@ int g() {
     int a;
     int b = 81;
   };
-  // CHECK: define {{.*}}_Z1gv
+  // CHECK-LABEL: define {{.*}}_Z1gv
   // CHECK-NOT: }
   // CHECK: call {{.*}}@"[[CONSTRUCT_LOCAL:.*]]C1Ev"
   return b;
 }
 
+struct A {
+  A();
+};
+union B {
+  int k;
+  struct {
+    A x;
+    int y = 123;
+  };
+  B() {}
+  B(int n) : k(n) {}
+};
+
+B b1;
+B b2(0);
+
+
+// CHECK-LABEL: define {{.*}} @_ZN1BC2Ei(
+// CHECK-NOT: call void @_ZN1AC1Ev(
+// CHECK-NOT: store i32 123,
+// CHECK: store i32 %
+// CHECK-NOT: call void @_ZN1AC1Ev(
+// CHECK-NOT: store i32 123,
+// CHECK: }
+
+// CHECK-LABEL: define {{.*}} @_ZN1BC2Ev(
+// CHECK: call void @_ZN1AC1Ev(
+// CHECK: store i32 123,
+// CHECK: }
+
 
 // CHECK: define {{.*}}@"[[CONSTRUCT_LOCAL]]C2Ev"
 // CHECK-NOT: }





More information about the cfe-commits mailing list