Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6122,6 +6122,9 @@ def err_atomic_op_needs_non_const_atomic : Error< "address argument to atomic operation must be a pointer to non-const _Atomic " "type (%0 invalid)">; +def err_atomic_load_needs_non_const_dest : Error< + "address argument to atomic load must be a pointer to non-const %0 " + "(%1 invalid)">; def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1620,6 +1620,24 @@ if (!IsC11 && !IsN) ByValType = Ptr->getType(); + if (Op == AtomicExpr::AO__atomic_load) { + Expr *SecondPtr = TheCall->getArg(1); + SecondPtr = DefaultFunctionArrayLvalueConversion(SecondPtr).get(); + const PointerType *SecondPointerType = SecondPtr->getType()->getAs(); + if (!SecondPointerType) { + Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) + << SecondPtr->getType() << SecondPtr->getSourceRange(); + return ExprError(); + } + QualType SecondPointeeType = SecondPointerType->getPointeeType(); + if (SecondPointeeType.isConstQualified()) { + Diag(DRE->getLocStart(), diag::err_atomic_load_needs_non_const_dest) + << ByValType->getPointeeType() << SecondPtr->getType() + << SecondPtr->getSourceRange(); + return ExprError(); + } + } + // 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. Index: test/Sema/atomic-ops.c =================================================================== --- test/Sema/atomic-ops.c +++ test/Sema/atomic-ops.c @@ -86,7 +86,7 @@ _Static_assert(__atomic_always_lock_free(8, &i64), ""); void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d, - int *I, int **P, float *D, struct S *s1, struct S *s2) { + int *I, const int *CI, int **P, float *D, struct S *s1, struct S *s2) { __c11_atomic_init(I, 5); // expected-error {{pointer to _Atomic}} __c11_atomic_load(0); // expected-error {{too few arguments to function}} __c11_atomic_load(0,0,0); // expected-error {{too many arguments to function}} @@ -103,6 +103,9 @@ __atomic_load_n(s1, memory_order_relaxed); // expected-error {{must be a pointer to integer or pointer}} __atomic_load(i, I, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}} + __atomic_load(CI, I, memory_order_relaxed); + __atomic_load(I, CI, memory_order_relaxed); // expected-error {{address argument to atomic load must be a pointer to non-const 'int' ('const int *' invalid}} + __atomic_load(I, 42, memory_order_relaxed); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}} __atomic_load(I, i, memory_order_relaxed); // expected-warning {{passing '_Atomic(int) *' to parameter of type 'int *'}} __atomic_load(I, *P, memory_order_relaxed); __atomic_load(I, *P, memory_order_relaxed, 42); // expected-error {{too many arguments}}