Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -13662,11 +13662,32 @@ CandidateSet.exclude(DefaultedFn); LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL); - bool HadMultipleCandidates = (CandidateSet.size() > 1); - // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { + OverloadingResult BestViableFunctionResult = + CandidateSet.BestViableFunction(*this, OpLoc, Best); + + // Fallback for C11 atomics in gnu++ mode. + if (LangStandard::getLangStandardForKind(getLangOpts().LangStd).isGNUMode()) { + // Ignore the atomic keyword on LHS and retry the lookup. + if (BestViableFunctionResult == OR_No_Viable_Function) { + if (const AtomicType *AtomicTy = + dyn_cast(Args[0]->getType())) { + Expr *DeatomizedArg0 = + AssertSuccess(ImpCastExprToType(Args[0], AtomicTy->getValueType(), + CK_AtomicToNonAtomic, VK_LValue)); + Expr *DeatomizedArgs[2] = {DeatomizedArg0, Args[1]}; + LookupOverloadedBinOp(CandidateSet, Op, Fns, DeatomizedArgs, + PerformADL); + BestViableFunctionResult = + CandidateSet.BestViableFunction(*this, OpLoc, Best); + } + } + } + + bool HadMultipleCandidates = (CandidateSet.size() > 1); + + switch (BestViableFunctionResult) { case OR_Success: { // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; Index: clang/test/CodeGenCXX/atomic-builtin-compound-assignment-overload.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/atomic-builtin-compound-assignment-overload.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=gnu++11 -emit-llvm -triple=x86_64-linux-gnu -o - %s | FileCheck %s + +_Atomic unsigned an_atomic_uint; + +enum { an_enum_value = 1 }; + +// CHECK-LABEL: define {{.*}}void @_Z5enum1v() +void enum1() { + an_atomic_uint += an_enum_value; + // CHECK: atomicrmw add ptr +} + +// CHECK-LABEL: define {{.*}}void @_Z5enum2v() +void enum2() { + an_atomic_uint |= an_enum_value; + // CHECK: atomicrmw or ptr +} + +// CHECK-LABEL: define {{.*}}void @_Z5enum3RU7_Atomicj({{.*}}) +void enum3(_Atomic unsigned &an_atomic_uint_param) { + an_atomic_uint_param += an_enum_value; + // CHECK: atomicrmw add ptr +} + +// CHECK-LABEL: define {{.*}}void @_Z5enum4RU7_Atomicj({{.*}}) +void enum4(_Atomic unsigned &an_atomic_uint_param) { + an_atomic_uint_param |= an_enum_value; + // CHECK: atomicrmw or ptr +} Index: clang/test/SemaCXX/atomic-builtin-compound-assignment-overload.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/atomic-builtin-compound-assignment-overload.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=gnu++98 -fsyntax-only -verify %s +// expected-no-diagnostics + +_Atomic unsigned an_atomic_uint; + +enum { an_enum_value = 1 }; + +void enum1() { an_atomic_uint += an_enum_value; } + +void enum2() { an_atomic_uint |= an_enum_value; }