r214390 - PR18097: Support initializing an _Atomic(T) from an object of C++ class type T

Richard Smith richard at metafoo.co.uk
Thu Jul 31 00:02:55 PDT 2014


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 <richard-llvm at metafoo.co.uk>
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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140731/a96b39bb/attachment.html>


More information about the cfe-commits mailing list