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

Richard Smith richard-llvm at metafoo.co.uk
Wed Jul 30 23:31:19 PDT 2014


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}}
+}





More information about the cfe-commits mailing list