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