]> granicus.if.org Git - clang/commitdiff
Compute standard conversion sequences for conversions to atomic
authorDouglas Gregor <dgregor@apple.com>
Thu, 12 Apr 2012 17:51:55 +0000 (17:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 12 Apr 2012 17:51:55 +0000 (17:51 +0000)
types. The second and third conversions in the sequence are based on
the conversion for the underlying type, so that we get sensible
overloading behavior for, e.g., _Atomic(int) vs. _Atomic(float).

As part of this, actually implement the lvalue-to-rvalue conversion
for atomic types. There is probably a pile of code in SemaExpr that
can now be deleted, but I haven't tracked it down yet.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154596 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/atomic-type.cxx

index 7748b8c8a66eaee2420ca3750ce9aae98cb21c01..104134cdb0e4c53a5e83c2610972273cb7f4dee8 100644 (file)
@@ -374,10 +374,6 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   QualType T = E->getType();
   assert(!T.isNull() && "r-value conversion on typeless expression?");
 
-  // We can't do lvalue-to-rvalue on atomics yet.
-  if (T->isAtomicType())
-    return Owned(E);
-
   // We don't want to throw lvalue-to-rvalue casts on top of
   // expressions of certain types in C++.
   if (getLangOpts().CPlusPlus &&
@@ -413,6 +409,15 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
                                                   E, 0, VK_RValue));
 
+  // C11 6.3.2.1p2:
+  //   ... if the lvalue has atomic type, the value has the non-atomic version 
+  //   of the type of the lvalue ...
+  if (const AtomicType *Atomic = T->getAs<AtomicType>()) {
+    T = Atomic->getValueType().getUnqualifiedType();
+    Res = Owned(ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic,
+                                         Res.get(), 0, VK_RValue));
+  }
+  
   return Res;
 }
 
index 40fb01ac30d78ba41ee4132f86467dcba48dc1ac..89d4179fceb04cb5c197052cbfb72e0ab82266c7 100644 (file)
@@ -1294,6 +1294,11 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
   return false;
 }
 
+static bool isAtomicConversion(Sema &S, Expr *From, QualType ToType,
+                               bool InOverloadResolution,
+                               StandardConversionSequence &SCS,
+                               bool CStyle);
+  
 /// IsStandardConversion - Determines whether there is a standard
 /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
 /// expression From to the type ToType. Standard conversion sequences
@@ -1389,6 +1394,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
       S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
     SCS.First = ICK_Lvalue_To_Rvalue;
 
+    // C11 6.3.2.1p2:
+    //   ... if the lvalue has atomic type, the value has the non-atomic version 
+    //   of the type of the lvalue ...
+    if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
+      FromType = Atomic->getValueType();
+
     // If T is a non-class type, the type of the rvalue is the
     // cv-unqualified version of T. Otherwise, the type of the rvalue
     // is T (C++ 4.1p1). C++ can't get here with class types; in C, we
@@ -1520,13 +1531,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                              SCS, CStyle)) {
     SCS.Second = ICK_TransparentUnionConversion;
     FromType = ToType;
-  }  else if (const AtomicType *ToAtomicType = ToType->getAs<AtomicType>()) {
-    // Allow conversion to _Atomic types.  These are C11 and are provided as an
-    // extension in C++ mode.  
-    if (S.Context.hasSameUnqualifiedType(ToAtomicType->getValueType(),
-                                         FromType))
-    SCS.Second = ICK_Identity;
-    FromType = ToType;
+  } else if (isAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
+                                CStyle)) {
+    // isAtomicConversion has updated the standard conversion sequence 
+    // appropriately.
+    return true;
   } else {
     // No second conversion required.
     SCS.Second = ICK_Identity;
@@ -2765,6 +2774,34 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
   return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
 }
 
+/// \brief - Determine whether this is a conversion from a scalar type to an
+/// atomic type.
+///
+/// If successful, updates \c SCS's second and third steps in the conversion
+/// sequence to finish the conversion.
+static bool isAtomicConversion(Sema &S, Expr *From, QualType ToType,
+                               bool InOverloadResolution,
+                               StandardConversionSequence &SCS,
+                               bool CStyle) {
+  const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
+  if (!ToAtomic)
+    return false;
+  
+  StandardConversionSequence InnerSCS;
+  if (!IsStandardConversion(S, From, ToAtomic->getValueType(), 
+                            InOverloadResolution, InnerSCS,
+                            CStyle, /*AllowObjCWritebackConversion=*/false))
+    return false;
+  
+  SCS.Second = InnerSCS.Second;
+  SCS.setToType(1, InnerSCS.getToType(1));
+  SCS.Third = InnerSCS.Third;
+  SCS.QualificationIncludesObjCLifetime
+    = InnerSCS.QualificationIncludesObjCLifetime;
+  SCS.setToType(2, InnerSCS.getToType(2));
+  return true;
+}
+
 static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
                                               CXXConstructorDecl *Constructor,
                                               QualType Type) {
index adaff2a0a2f32a834f238a62a3c6c4c8dbb61f44..18707eb8c5ca2376be67734d3827802a08ed4e40 100644 (file)
@@ -10,3 +10,26 @@ template<typename T> struct user {
 };
 
 user<int> u;
+
+// Test overloading behavior of atomics.
+struct A { };
+
+int &ovl1(_Atomic(int));
+long &ovl1(_Atomic(long));
+float &ovl1(_Atomic(float));
+double &ovl1(_Atomic(A const *const *));
+short &ovl1(_Atomic(A **));
+
+void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
+                      long l, _Atomic(long) al, A const *const *acc,
+                      A const ** ac, A **a) {
+  int& ir1 = ovl1(i);
+  int& ir2 = ovl1(ai);
+  long& lr1 = ovl1(l);
+  long& lr2 = ovl1(al);
+  float &fr1 = ovl1(f);
+  float &fr2 = ovl1(af);
+  double &dr1 = ovl1(acc);
+  double &dr2 = ovl1(ac);
+  short &sr1 = ovl1(a);
+}