This fixes a bug marked as being a release blocker and should be put on the 3.5 branch.
On Wed, Jul 30, 2014 at 11:31 PM, Richard Smith <[email protected]> wrote: > Author: rsmith > Date: Thu Jul 31 01:31:19 2014 > New Revision: 214390 > > URL: http://llvm.org/viewvc/llvm-project?rev=214390&view=rev > Log: > PR18097: Support initializing an _Atomic(T) from an object of C++ class > type T > or a class derived from T. We already supported this when initializing > _Atomic(T) from T for most (and maybe all) other reasonable values of T. > > Modified: > cfe/trunk/include/clang/Sema/Initialization.h > cfe/trunk/lib/AST/ExprConstant.cpp > cfe/trunk/lib/CodeGen/CGExprAgg.cpp > cfe/trunk/lib/CodeGen/CGExprConstant.cpp > cfe/trunk/lib/Sema/SemaInit.cpp > cfe/trunk/test/CodeGen/c11atomics.c > cfe/trunk/test/CodeGenCXX/atomicinit.cpp > cfe/trunk/test/SemaCXX/atomic-type.cpp > > Modified: cfe/trunk/include/clang/Sema/Initialization.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Sema/Initialization.h (original) > +++ cfe/trunk/include/clang/Sema/Initialization.h Thu Jul 31 01:31:19 2014 > @@ -663,6 +663,8 @@ public: > SK_QualificationConversionXValue, > /// \brief Perform a qualification conversion, producing an lvalue. > SK_QualificationConversionLValue, > + /// \brief Perform a conversion adding _Atomic to a type. > + SK_AtomicConversion, > /// \brief Perform a load from a glvalue, producing an rvalue. > SK_LValueToRValue, > /// \brief Perform an implicit conversion sequence. > @@ -999,7 +1001,11 @@ public: > /// given type. > void AddQualificationConversionStep(QualType Ty, > ExprValueKind Category); > - > + > + /// \brief Add a new step that performs conversion from non-atomic to > atomic > + /// type. > + void AddAtomicConversionStep(QualType Ty); > + > /// \brief Add a new step that performs a load of the given type. > /// > /// Although the term "LValueToRValue" is conventional, this applies to > both > > Modified: cfe/trunk/lib/AST/ExprConstant.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/ExprConstant.cpp (original) > +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jul 31 01:31:19 2014 > @@ -1353,6 +1353,11 @@ static bool CheckConstantExpression(Eval > return false; > } > > + // We allow _Atomic(T) to be initialized from anything that T can be > + // initialized from. > + if (const AtomicType *AT = Type->getAs<AtomicType>()) > + Type = AT->getValueType(); > + > // Core issue 1454: For a literal constant expression of array or class > type, > // each subobject of its value shall have been initialized by a constant > // expression. > > Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Thu Jul 31 01:31:19 2014 > @@ -1137,6 +1137,16 @@ void AggExprEmitter::VisitInitListExpr(I > return; > } > > + if (E->getType()->isAtomicType()) { > + // An _Atomic(T) object can be list-initialized from an expression > + // of the same type. > + assert(E->getNumInits() == 1 && > + > CGF.getContext().hasSameUnqualifiedType(E->getInit(0)->getType(), > + E->getType()) && > + "unexpected list initialization for atomic object"); > + return Visit(E->getInit(0)); > + } > + > assert(E->getType()->isRecordType() && "Only support structs/unions > here!"); > > // Do struct initialization; this code just sets each individual member > > Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Jul 31 01:31:19 2014 > @@ -1045,6 +1045,25 @@ llvm::Constant *CodeGenModule::EmitConst > llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, > QualType DestType, > CodeGenFunction *CGF) { > + // For an _Atomic-qualified constant, we may need to add tail padding. > + if (auto *AT = DestType->getAs<AtomicType>()) { > + QualType InnerType = AT->getValueType(); > + auto *Inner = EmitConstantValue(Value, InnerType, CGF); > + > + uint64_t InnerSize = Context.getTypeSize(InnerType); > + uint64_t OuterSize = Context.getTypeSize(DestType); > + if (InnerSize == OuterSize) > + return Inner; > + > + assert(InnerSize < OuterSize && "emitted over-large constant for > atomic"); > + llvm::Constant *Elts[] = { > + Inner, > + llvm::ConstantAggregateZero::get( > + llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8)) > + }; > + return llvm::ConstantStruct::getAnon(Elts); > + } > + > switch (Value.getKind()) { > case APValue::Uninitialized: > llvm_unreachable("Constant expressions should be initialized."); > > Modified: cfe/trunk/lib/Sema/SemaInit.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaInit.cpp (original) > +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jul 31 01:31:19 2014 > @@ -2767,6 +2767,7 @@ void InitializationSequence::Step::Destr > case SK_QualificationConversionRValue: > case SK_QualificationConversionXValue: > case SK_QualificationConversionLValue: > + case SK_AtomicConversion: > case SK_LValueToRValue: > case SK_ListInitialization: > case SK_UnwrapInitList: > @@ -2919,6 +2920,13 @@ void InitializationSequence::AddQualific > Steps.push_back(S); > } > > +void InitializationSequence::AddAtomicConversionStep(QualType Ty) { > + Step S; > + S.Kind = SK_AtomicConversion; > + S.Type = Ty; > + Steps.push_back(S); > +} > + > void InitializationSequence::AddLValueToRValueStep(QualType Ty) { > assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers"); > > @@ -4174,12 +4182,11 @@ static void TryDefaultInitialization(Sem > /// which enumerates all conversion functions and performs overload > resolution > /// to select the best. > static void TryUserDefinedConversion(Sema &S, > - const InitializedEntity &Entity, > + QualType DestType, > const InitializationKind &Kind, > Expr *Initializer, > InitializationSequence &Sequence, > bool TopLevelOfInitList) { > - QualType DestType = Entity.getType(); > assert(!DestType->isReferenceType() && "References are handled > elsewhere"); > QualType SourceType = Initializer->getType(); > assert((DestType->isRecordType() || SourceType->isRecordType()) && > @@ -4596,7 +4603,6 @@ void InitializationSequence::InitializeF > Initializer) || > S.ConversionToObjCStringLiteralCheck(DestType, Initializer)) > Args[0] = Initializer; > - > } > if (!isa<InitListExpr>(Initializer)) > SourceType = Initializer->getType(); > @@ -4741,7 +4747,7 @@ void InitializationSequence::InitializeF > (Context.hasSameUnqualifiedType(SourceType, DestType) || > S.IsDerivedFrom(SourceType, DestType)))) > TryConstructorInitialization(S, Entity, Kind, Args, > - Entity.getType(), *this); > + DestType, *this); > // - Otherwise (i.e., for the remaining copy-initialization > cases), > // user-defined conversion sequences that can convert from the > source > // type to the destination type or (when a conversion function > is > @@ -4749,7 +4755,7 @@ void InitializationSequence::InitializeF > // 13.3.1.4, and the best one is chosen through overload > resolution > // (13.3). > else > - TryUserDefinedConversion(S, Entity, Kind, Initializer, *this, > + TryUserDefinedConversion(S, DestType, Kind, Initializer, *this, > TopLevelOfInitList); > return; > } > @@ -4763,9 +4769,22 @@ void InitializationSequence::InitializeF > // - Otherwise, if the source type is a (possibly cv-qualified) class > // type, conversion functions are considered. > if (!SourceType.isNull() && SourceType->isRecordType()) { > - TryUserDefinedConversion(S, Entity, Kind, Initializer, *this, > + // For a conversion to _Atomic(T) from either T or a class type > derived > + // from T, initialize the T object then convert to _Atomic type. > + bool NeedAtomicConversion = false; > + if (const AtomicType *Atomic = DestType->getAs<AtomicType>()) { > + if (Context.hasSameUnqualifiedType(SourceType, > Atomic->getValueType()) || > + S.IsDerivedFrom(SourceType, Atomic->getValueType())) { > + DestType = Atomic->getValueType(); > + NeedAtomicConversion = true; > + } > + } > + > + TryUserDefinedConversion(S, DestType, Kind, Initializer, *this, > TopLevelOfInitList); > MaybeProduceObjCObject(S, *this, Entity); > + if (!Failed() && NeedAtomicConversion) > + AddAtomicConversionStep(Entity.getType()); > return; > } > > @@ -4774,16 +4793,16 @@ void InitializationSequence::InitializeF > // conversions (Clause 4) will be used, if necessary, to convert > the > // initializer expression to the cv-unqualified version of the > // destination type; no user-defined conversions are considered. > - > + > ImplicitConversionSequence ICS > - = S.TryImplicitConversion(Initializer, Entity.getType(), > + = S.TryImplicitConversion(Initializer, DestType, > /*SuppressUserConversions*/true, > /*AllowExplicitConversions*/ false, > /*InOverloadResolution*/ false, > /*CStyle=*/Kind.isCStyleOrFunctionalCast(), > allowObjCWritebackConversion); > - > - if (ICS.isStandard() && > + > + if (ICS.isStandard() && > ICS.Standard.Second == ICK_Writeback_Conversion) { > // Objective-C ARC writeback conversion. > > @@ -4804,7 +4823,7 @@ void InitializationSequence::InitializeF > AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0)); > } > > - AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); > + AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy); > } else if (ICS.isBad()) { > DeclAccessPair dap; > if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) { > @@ -4816,7 +4835,7 @@ void InitializationSequence::InitializeF > else > SetFailed(InitializationSequence::FK_ConversionFailed); > } else { > - AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList); > + AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList); > > MaybeProduceObjCObject(S, *this, Entity); > } > @@ -5772,6 +5791,7 @@ InitializationSequence::Perform(Sema &S, > case SK_QualificationConversionLValue: > case SK_QualificationConversionXValue: > case SK_QualificationConversionRValue: > + case SK_AtomicConversion: > case SK_LValueToRValue: > case SK_ConversionSequence: > case SK_ConversionSequenceNoNarrowing: > @@ -6062,6 +6082,13 @@ InitializationSequence::Perform(Sema &S, > break; > } > > + case SK_AtomicConversion: { > + assert(CurInit.get()->isRValue() && "cannot convert glvalue to > atomic"); > + CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type, > + CK_NonAtomicToAtomic, VK_RValue); > + break; > + } > + > case SK_LValueToRValue: { > assert(CurInit.get()->isGLValue() && "cannot load from a prvalue"); > CurInit = ImplicitCastExpr::Create(S.Context, Step->Type, > @@ -7033,6 +7060,10 @@ void InitializationSequence::dump(raw_os > OS << "qualification conversion (lvalue)"; > break; > > + case SK_AtomicConversion: > + OS << "non-atomic-to-atomic conversion"; > + break; > + > case SK_LValueToRValue: > OS << "load (lvalue to rvalue)"; > break; > > Modified: cfe/trunk/test/CodeGen/c11atomics.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/c11atomics.c?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGen/c11atomics.c (original) > +++ cfe/trunk/test/CodeGen/c11atomics.c Thu Jul 31 01:31:19 2014 > @@ -12,6 +12,9 @@ > // they're sufficiently rare that it's not worth making sure that the > semantics > // are correct. > > +// CHECK: @testStructGlobal = global {{.*}} { i16 1, i16 2, i16 3, i16 4 } > +// CHECK: @testPromotedStructGlobal = global {{.*}} { %{{.*}} { i16 1, > i16 2, i16 3 }, [2 x i8] zeroinitializer } > + > typedef int __attribute__((vector_size(16))) vector; > > _Atomic(_Bool) b; > @@ -224,6 +227,7 @@ void testComplexFloat(_Atomic(_Complex f > } > > typedef struct { short x, y, z, w; } S; > +_Atomic S testStructGlobal = (S){1, 2, 3, 4}; > // CHECK: define arm_aapcscc void @testStruct([[S:.*]]* > void testStruct(_Atomic(S) *fp) { > // CHECK: [[FP:%.*]] = alloca [[S]]*, align 4 > @@ -272,6 +276,7 @@ void testStruct(_Atomic(S) *fp) { > } > > typedef struct { short x, y, z; } PS; > +_Atomic PS testPromotedStructGlobal = (PS){1, 2, 3}; > // CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]* > void testPromotedStruct(_Atomic(PS) *fp) { > // CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4 > > Modified: cfe/trunk/test/CodeGenCXX/atomicinit.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/atomicinit.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/atomicinit.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/atomicinit.cpp Thu Jul 31 01:31:19 2014 > @@ -1,4 +1,10 @@ > -// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 | > FileCheck %s > +// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 > -std=c++11 | FileCheck %s > + > +// CHECK-DAG: @_ZN7PR180978constant1aE = global {{.*}} { i16 1, i8 6, i8 > undef }, align 4 > +// CHECK-DAG: @_ZN7PR180978constant1bE = global {{.*}} { i16 2, i8 6, i8 > undef }, align 4 > +// CHECK-DAG: @_ZN7PR180978constant1cE = global {{.*}} { i16 3, i8 6, i8 > undef }, align 4 > +// CHECK-DAG: @_ZN7PR180978constant1yE = global {{.*}} { {{.*}} { i16 4, > i8 6, i8 undef }, i32 5 }, align 4 > + > struct A { > _Atomic(int) i; > A(int j); > @@ -46,3 +52,51 @@ struct AtomicBoolMember { > // CHECK-NEXT: ret void > AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { } > > +namespace PR18097 { > + namespace dynamic { > + struct X { > + X(int); > + short n; > + char c; > + }; > + > + // CHECK-LABEL: define {{.*}} @__cxx_global_var_init > + // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* > @_ZN7PR180977dynamic1aE, i32 1) > + _Atomic(X) a = X(1); > + > + // CHECK-LABEL: define {{.*}} @__cxx_global_var_init > + // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* > @_ZN7PR180977dynamic1bE, i32 2) > + _Atomic(X) b(X(2)); > + > + // CHECK-LABEL: define {{.*}} @__cxx_global_var_init > + // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* > @_ZN7PR180977dynamic1cE, i32 3) > + _Atomic(X) c{X(3)}; > + > + struct Y { > + _Atomic(X) a; > + _Atomic(int) b; > + }; > + // CHECK-LABEL: define {{.*}} @__cxx_global_var_init > + // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* getelementptr > inbounds ({{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 0), i32 4) > + // CHECK: store i32 5, i32* getelementptr inbounds ({{.*}}* > @_ZN7PR180977dynamic1yE, i32 0, i32 1) > + Y y = { X(4), 5 }; > + } > + > + // CHECKs at top of file. > + namespace constant { > + struct X { > + constexpr X(int n) : n(n) {} > + short n; > + char c = 6; > + }; > + _Atomic(X) a = X(1); > + _Atomic(X) b(X(2)); > + _Atomic(X) c{X(3)}; > + > + struct Y { > + _Atomic(X) a; > + _Atomic(int) b; > + }; > + Y y = { X(4), 5 }; > + } > +} > > Modified: cfe/trunk/test/SemaCXX/atomic-type.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/atomic-type.cpp?rev=214390&r1=214389&r2=214390&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaCXX/atomic-type.cpp (original) > +++ cfe/trunk/test/SemaCXX/atomic-type.cpp Thu Jul 31 01:31:19 2014 > @@ -1,4 +1,5 @@ > -// RUN: %clang_cc1 -verify -pedantic %s > +// RUN: %clang_cc1 -verify -pedantic %s -std=c++98 > +// RUN: %clang_cc1 -verify -pedantic %s -std=c++11 > > template<typename T> struct atomic { > _Atomic(T) value; > @@ -56,3 +57,29 @@ typedef _Atomic(int &) atomic_reference_ > struct S { > _Atomic union { int n; }; // expected-warning {{anonymous union cannot > be '_Atomic'}} > }; > + > +namespace copy_init { > + struct X { > + X(int); > + int n; > + }; > + _Atomic(X) y = X(0); > + _Atomic(X) z(X(0)); > + void f() { y = X(0); } > + > + _Atomic(X) e1(0); // expected-error {{cannot initialize}} > +#if __cplusplus >= 201103L > + _Atomic(X) e2{0}; // expected-error {{illegal initializer}} > + _Atomic(X) a{X(0)}; > +#endif > + > + struct Y { > + _Atomic(X) a; > + _Atomic(int) b; > + }; > + Y y1 = { X(0), 4 }; > + Y y2 = { 0, 4 }; // expected-error {{cannot initialize}} > + // FIXME: It's not really clear if we should allow these. Generally, > C++11 > + // allows extraneous braces around initializers. > + Y y3 = { { X(0) }, { 4 } }; // expected-error 2{{illegal initializer > type}} > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
