Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1513,6 +1513,8 @@ // C __c11_atomic_load(A *, int) Load, // void __atomic_load(A *, CP, int) + LoadCopy, + // void __atomic_store(A *, CP, int) Copy, // C __c11_atomic_add(A *, M, int) Arithmetic, @@ -1525,8 +1527,8 @@ // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) GNUCmpXchg } Form = Init; - const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 4, 5, 6 }; - const unsigned NumVals[] = { 1, 0, 1, 1, 1, 2, 2, 3 }; + const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; + const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: // C is an appropriate type, // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, @@ -1556,8 +1558,11 @@ Form = Load; break; - case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_load: + Form = LoadCopy; + break; + + case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; @@ -1644,7 +1649,7 @@ return ExprError(); } ValType = AtomTy->getAs()->getValueType(); - } else if (Form != Load && Op != AtomicExpr::AO__atomic_load) { + } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); @@ -1705,10 +1710,11 @@ // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the // volatile-ness of the pointee-type inject itself into the result or the - // other operands. + // other operands. Similarly atomic_load can take a pointer to a const 'A'. ValType.removeLocalVolatile(); + ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == GNUXchg || Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; @@ -1719,10 +1725,6 @@ if (!IsC11 && !IsN) ByValType = Ptr->getType(); - // FIXME: __atomic_load allows the first argument to be a a pointer to const - // but not the second argument. We need to manually remove possible const - // qualifiers. - // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. @@ -1780,6 +1782,7 @@ case Load: SubExprs.push_back(TheCall->getArg(1)); // Order break; + case LoadCopy: case Copy: case Arithmetic: case Xchg: Index: test/Sema/atomic-ops.c =================================================================== --- test/Sema/atomic-ops.c +++ test/Sema/atomic-ops.c @@ -118,7 +118,10 @@ __atomic_load(I, *P, memory_order_relaxed, 42); // expected-error {{too many arguments}} (int)__atomic_load(I, I, memory_order_seq_cst); // expected-error {{operand of type 'void'}} __atomic_load(s1, s2, memory_order_acquire); - (void)__atomic_load(I, CI, memory_order_relaxed); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}} + __atomic_load(CI, I, memory_order_relaxed); + __atomic_load(I, CI, memory_order_relaxed); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}} + __atomic_load(CI, CI, memory_order_relaxed); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}} + __c11_atomic_store(i, 1, memory_order_seq_cst); __c11_atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}} (int)__c11_atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}}