diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4637,9 +4637,12 @@ MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); - ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, - SourceLocation RParenLoc, MultiExprArg Args, - AtomicExpr::AtomicOp Op); + enum class AtomicArgumentOrder { API, AST }; + ExprResult + BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op, + AtomicArgumentOrder ArgOrder = AtomicArgumentOrder::API); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4473,7 +4473,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, SourceLocation RParenLoc, MultiExprArg Args, - AtomicExpr::AtomicOp Op) { + AtomicExpr::AtomicOp Op, + AtomicArgumentOrder ArgOrder) { // All the non-OpenCL operations take one of the following forms. // The OpenCL operations take the __c11 forms with one extra argument for // synchronization scope. @@ -4754,19 +4755,56 @@ IsPassedByAddress = true; } + SmallVector APIOrderedArgs; + if (ArgOrder == Sema::AtomicArgumentOrder::AST) { + APIOrderedArgs.push_back(Args[0]); + switch (Form) { + case Init: + case Load: + APIOrderedArgs.push_back(Args[1]); // Val1/Order + break; + case LoadCopy: + case Copy: + case Arithmetic: + case Xchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case GNUXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[3]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case C11CmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + case GNUCmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[5]); // Weak + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + } + } else + APIOrderedArgs.append(Args.begin(), Args.end()); + // 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 != Args.size(); ++i) { + for (unsigned i = 0; i != APIOrderedArgs.size(); ++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, Args[i], ExprRange.getBegin()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); // Nothing else to do: we already know all we want about this pointer. continue; case 1: @@ -4778,14 +4816,16 @@ if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; else if (Form == Copy || Form == Xchg) { - if (IsPassedByAddress) + if (IsPassedByAddress) { // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, Args[i], ExprRange.getBegin()); + CheckNonNullArgument(*this, APIOrderedArgs[i], + ExprRange.getBegin()); + } Ty = ByValType; } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { - Expr *ValArg = Args[i]; + Expr *ValArg = APIOrderedArgs[i]; // The value pointer is always dereferenced, a nullptr is undefined. CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); LangAS AS = LangAS::Default; @@ -4802,7 +4842,7 @@ // The third argument to compare_exchange / GNU exchange is the desired // value, either by-value (for the C11 and *_n variant) or as a pointer. if (IsPassedByAddress) - CheckNonNullArgument(*this, Args[i], ExprRange.getBegin()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); Ty = ByValType; break; case 3: @@ -4817,11 +4857,11 @@ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Ty, false); - ExprResult Arg = Args[i]; + ExprResult Arg = APIOrderedArgs[i]; Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; - Args[i] = Arg.get(); + APIOrderedArgs[i] = Arg.get(); } // Permute the arguments into a 'consistent' order. @@ -4830,36 +4870,36 @@ switch (Form) { case Init: // Note, AtomicExpr::getVal1() has a special case for this atomic. - SubExprs.push_back(Args[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case Load: - SubExprs.push_back(Args[1]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Order break; case LoadCopy: case Copy: case Arithmetic: case Xchg: - SubExprs.push_back(Args[2]); // Order - SubExprs.push_back(Args[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case GNUXchg: // Note, AtomicExpr::getVal2() has a special case for this atomic. - SubExprs.push_back(Args[3]); // Order - SubExprs.push_back(Args[1]); // Val1 - SubExprs.push_back(Args[2]); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case C11CmpXchg: - SubExprs.push_back(Args[3]); // Order - SubExprs.push_back(Args[1]); // Val1 - SubExprs.push_back(Args[4]); // OrderFail - SubExprs.push_back(Args[2]); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[4]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case GNUCmpXchg: - SubExprs.push_back(Args[4]); // Order - SubExprs.push_back(Args[1]); // Val1 - SubExprs.push_back(Args[5]); // OrderFail - SubExprs.push_back(Args[2]); // Val2 - SubExprs.push_back(Args[3]); // Weak + SubExprs.push_back(APIOrderedArgs[4]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[5]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Weak break; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3308,14 +3308,15 @@ /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, - MultiExprArg SubExprs, + ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs, AtomicExpr::AtomicOp Op, SourceLocation RParenLoc) { // Use this for all of the locations, since we don't know the difference // between the call and the expr at this point. SourceRange Range{BuiltinLoc, RParenLoc}; - return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op); + return getSema().BuildAtomicExpr( + Range, Range, RParenLoc, SubExprs, Op, + /*AtomicArgumentOrder*/ Sema::AtomicArgumentOrder::AST); } private: diff --git a/clang/test/AST/atomic-expr.cpp b/clang/test/AST/atomic-expr.cpp --- a/clang/test/AST/atomic-expr.cpp +++ b/clang/test/AST/atomic-expr.cpp @@ -3,7 +3,7 @@ template void pr43370() { int arr[2]; - __atomic_store_n(arr, 0, 0); + __atomic_store_n(arr, 0, 5); } void useage(){ pr43370(); @@ -13,7 +13,13 @@ // CHECK: AtomicExpr // CHECK-NEXT: ImplicitCastExpr // CHECK-SAME: +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <{{[^:]+}}:20> 'int [2]' lvalue Var 0x{{[0-9a-f]+}} 'arr' 'int [2]' +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-f]+}} <{{[^:]+}}:28> 'int' 5 +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-f]+}} <{{[^:]+}}:25> 'int' 0 // CHECK:FunctionDecl 0x{{[0-9a-f]+}} line:4:6 used pr43370 // CHECK: AtomicExpr // CHECK-NEXT: ImplicitCastExpr // CHECK-SAME: +// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <{{[^:]+}}:20> 'int [2]' lvalue Var 0x{{[0-9a-f]+}} 'arr' 'int [2]' +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-f]+}} <{{[^:]+}}:28> 'int' 5 +// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-f]+}} <{{[^:]+}}:25> 'int' 0