// 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,
// 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,
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;
return ExprError();
}
ValType = AtomTy->getAs<AtomicType>()->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();
// 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;
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.
case Load:
SubExprs.push_back(TheCall->getArg(1)); // Order
break;
+ case LoadCopy:
case Copy:
case Arithmetic:
case Xchg:
__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'}}