summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorJF Bastien <jfbastien@apple.com>2018-05-25 00:07:09 +0000
committerJF Bastien <jfbastien@apple.com>2018-05-25 00:07:09 +0000
commit7f0a05ada547b73a33f55d00a3fa984b2cd45a17 (patch)
tree2334b179bdf397a9fd3bb745d2f1746e19f1ca4a /clang/lib
parent698b0a674d26abffb8ad0cbc9f4f316d359f5a53 (diff)
downloadbcm5719-llvm-7f0a05ada547b73a33f55d00a3fa984b2cd45a17.tar.gz
bcm5719-llvm-7f0a05ada547b73a33f55d00a3fa984b2cd45a17.zip
Make atomic non-member functions as nonnull
Summary: As a companion to libc++ patch https://reviews.llvm.org/D47225, mark builtin atomic non-member functions which accept pointers as nonnull. The atomic non-member functions accept pointers to std::atomic / std::atomic_flag as well as to the non-atomic value. These are all dereferenced unconditionally when lowered, and therefore will fault if null. It's a tiny gotcha for new users, especially when they pass in NULL as expected value (instead of passing a pointer to a NULL value). <rdar://problem/18473124> Reviewers: arphaman Subscribers: aheejin, cfe-commits Differential Revision: https://reviews.llvm.org/D47229 llvm-svn: 333246
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp46
1 files changed, 31 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bf95c22e99e..6f956b42f02 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3451,9 +3451,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
return ExprError();
}
- // 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. Similarly atomic_load can take a pointer to a const 'A'.
+ // All atomic operations have an overload which 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. Similarly atomic_load takes a
+ // pointer to a const 'A'.
ValType.removeLocalVolatile();
ValType.removeLocalConst();
QualType ResultType = ValType;
@@ -3466,16 +3467,27 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// The type of a parameter passed 'by value'. In the GNU atomics, such
// arguments are actually passed as pointers.
QualType ByValType = ValType; // 'CP'
- if (!IsC11 && !IsN)
+ bool IsPassedByAddress = false;
+ if (!IsC11 && !IsN) {
ByValType = Ptr->getType();
+ IsPassedByAddress = true;
+ }
- // 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.
- for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) {
+ // The first argument's non-CV pointer type is used to deduce the type of
+ // subsequent arguments, except for:
+ // - weak flag (always converted to bool)
+ // - memory order (always converted to int)
+ // - scope (always converted to int)
+ for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) {
QualType Ty;
if (i < NumVals[Form] + 1) {
switch (i) {
+ case 0:
+ // The first argument is always a pointer. It has a fixed type.
+ // It is always dereferenced, a nullptr is undefined.
+ CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
+ // Nothing else to do: we already know all we want about this pointer.
+ continue;
case 1:
// The second argument is the non-atomic operand. For arithmetic, this
// is always passed by value, and for a compare_exchange it is always
@@ -3484,14 +3496,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
assert(Form != Load);
if (Form == Init || (Form == Arithmetic && ValType->isIntegerType()))
Ty = ValType;
- else if (Form == Copy || Form == Xchg)
+ else if (Form == Copy || Form == Xchg) {
+ if (IsPassedByAddress)
+ // The value pointer is always dereferenced, a nullptr is undefined.
+ CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
Ty = ByValType;
- else if (Form == Arithmetic)
+ } else if (Form == Arithmetic)
Ty = Context.getPointerDiffType();
else {
Expr *ValArg = TheCall->getArg(i);
- // Treat this argument as _Nonnull as we want to show a warning if
- // NULL is passed into it.
+ // The value pointer is always dereferenced, a nullptr is undefined.
CheckNonNullArgument(*this, ValArg, DRE->getLocStart());
LangAS AS = LangAS::Default;
// Keep address space of non-atomic pointer type.
@@ -3504,8 +3518,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
}
break;
case 2:
- // The third argument to compare_exchange / GNU exchange is a
- // (pointer to a) desired value.
+ // The third argument to compare_exchange / GNU exchange is the desired
+ // value, either by-value (for the *_n variant) or as a pointer.
+ if (!IsN)
+ CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart());
Ty = ByValType;
break;
case 3:
@@ -3887,7 +3903,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
ResultType = Context.BoolTy;
break;
- case Builtin::BI__sync_lock_test_and_set:
+ case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
OpenPOWER on IntegriCloud