diff options
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 51 | ||||
-rw-r--r-- | test/SemaCXX/atomic-type.cxx | 23 |
3 files changed, 76 insertions, 11 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7748b8c8a6..104134cdb0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 40fb01ac30..89d4179fce 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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) { diff --git a/test/SemaCXX/atomic-type.cxx b/test/SemaCXX/atomic-type.cxx index adaff2a0a2..18707eb8c5 100644 --- a/test/SemaCXX/atomic-type.cxx +++ b/test/SemaCXX/atomic-type.cxx @@ -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); +} |