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

David Blaikie dblaikie at gmail.com
Tue Dec 10 12:50:10 PST 2013


On Tue, Dec 10, 2013 at 12:25 AM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> 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)

Collapse the initialization into the conditional here?

> +      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: }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list