Skip to content

Commit 762672a

Browse files
committed
Re-commit r282556, reverted in r282564, with a fix to CallArgList::addFrom to
function correctly when targeting MS ABIs (this appears to have never mattered prior to this change). Update test case to always cover both 32-bit and 64-bit Windows ABIs, since they behave somewhat differently from each other here. Update test case to also cover operators , && and ||, which it appears are also affected by P0145R3 (they're not explicitly called out by the design document, but this is the emergent behavior of the existing wording). Original commit message: P0145R3 (C++17 evaluation order tweaks): evaluate the right-hand side of assignment and compound-assignment operators before the left-hand side. (Even if it's an overloaded operator.) This completes the implementation of P0145R3 + P0400R0 for all targets except Windows, where the evaluation order guarantees for <<, >>, and ->* are unimplementable as the ABI requires the function arguments are evaluated from right to left (because parameter destructors are run from left to right in the callee). llvm-svn: 282619
1 parent 10d0abb commit 762672a

File tree

10 files changed

+193
-64
lines changed

10 files changed

+193
-64
lines changed

clang/include/clang/AST/ExprCXX.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ class CXXOperatorCallExpr : public CallExpr {
7676
/// expression refers to.
7777
OverloadedOperatorKind getOperator() const { return Operator; }
7878

79+
static bool isAssignmentOp(OverloadedOperatorKind Opc) {
80+
return Opc == OO_Equal || Opc == OO_StarEqual ||
81+
Opc == OO_SlashEqual || Opc == OO_PercentEqual ||
82+
Opc == OO_PlusEqual || Opc == OO_MinusEqual ||
83+
Opc == OO_LessLessEqual || Opc == OO_GreaterGreaterEqual ||
84+
Opc == OO_AmpEqual || Opc == OO_CaretEqual ||
85+
Opc == OO_PipeEqual;
86+
}
87+
bool isAssignmentOp() const { return isAssignmentOp(getOperator()); }
88+
7989
/// \brief Returns the location of the operator symbol in the expression.
8090
///
8191
/// When \c getOperator()==OO_Call, this is the location of the right

clang/lib/CodeGen/CGCall.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3129,7 +3129,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
31293129
}
31303130

31313131
void CallArgList::allocateArgumentMemory(CodeGenFunction &CGF) {
3132-
assert(!StackBase && !StackCleanup.isValid());
3132+
assert(!StackBase);
31333133

31343134
// Save the stack.
31353135
llvm::Function *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stacksave);
@@ -3172,7 +3172,8 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
31723172
void CodeGenFunction::EmitCallArgs(
31733173
CallArgList &Args, ArrayRef<QualType> ArgTypes,
31743174
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
3175-
const FunctionDecl *CalleeDecl, unsigned ParamsToSkip) {
3175+
const FunctionDecl *CalleeDecl, unsigned ParamsToSkip,
3176+
bool ForceRightToLeftEvaluation) {
31763177
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
31773178

31783179
auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg) {
@@ -3191,7 +3192,8 @@ void CodeGenFunction::EmitCallArgs(
31913192

31923193
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
31933194
// because arguments are destroyed left to right in the callee.
3194-
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
3195+
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee() ||
3196+
ForceRightToLeftEvaluation) {
31953197
// Insert a stack save if we're going to need any inalloca args.
31963198
bool HasInAllocaArgs = false;
31973199
for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();

clang/lib/CodeGen/CGCall.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,19 @@ namespace CodeGen {
8181
push_back(CallArg(rvalue, type, needscopy));
8282
}
8383

84+
/// Add all the arguments from another CallArgList to this one. After doing
85+
/// this, the old CallArgList retains its list of arguments, but must not
86+
/// be used to emit a call.
8487
void addFrom(const CallArgList &other) {
8588
insert(end(), other.begin(), other.end());
8689
Writebacks.insert(Writebacks.end(),
8790
other.Writebacks.begin(), other.Writebacks.end());
91+
CleanupsToDeactivate.insert(CleanupsToDeactivate.end(),
92+
other.CleanupsToDeactivate.begin(),
93+
other.CleanupsToDeactivate.end());
94+
assert(!(StackBase && other.StackBase) && "can't merge stackbases");
95+
if (!StackBase)
96+
StackBase = other.StackBase;
8897
}
8998

9099
void addWriteback(LValue srcLV, Address temporary,
@@ -132,11 +141,6 @@ namespace CodeGen {
132141

133142
/// The stacksave call. It dominates all of the argument evaluation.
134143
llvm::CallInst *StackBase;
135-
136-
/// The iterator pointing to the stack restore cleanup. We manually run and
137-
/// deactivate this cleanup after the call in the unexceptional case because
138-
/// it doesn't run in the normal order.
139-
EHScopeStack::stable_iterator StackCleanup;
140144
};
141145

142146
/// FunctionArgList - Type for representing both the decl and type

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4121,8 +4121,17 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
41214121
if (Chain)
41224122
Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)),
41234123
CGM.getContext().VoidPtrTy);
4124+
4125+
// C++17 requires that we evaluate arguments to a call using assignment syntax
4126+
// right-to-left. It also requires that we evaluate arguments to operators
4127+
// <<, >>, and ->* left-to-right, but that is not possible under the MS ABI,
4128+
// so there is no corresponding "force left-to-right" case.
4129+
bool ForceRightToLeft = false;
4130+
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E))
4131+
ForceRightToLeft = OCE->isAssignmentOp();
4132+
41244133
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), E->arguments(),
4125-
E->getDirectCallee(), /*ParamsToSkip*/ 0);
4134+
E->getDirectCallee(), /*ParamsToSkip*/ 0, ForceRightToLeft);
41264135

41274136
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
41284137
Args, FnType, /*isChainCall=*/Chain);

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static RequiredArgs
2828
commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
2929
llvm::Value *This, llvm::Value *ImplicitParam,
3030
QualType ImplicitParamTy, const CallExpr *CE,
31-
CallArgList &Args) {
31+
CallArgList &Args, CallArgList *RtlArgs) {
3232
assert(CE == nullptr || isa<CXXMemberCallExpr>(CE) ||
3333
isa<CXXOperatorCallExpr>(CE));
3434
assert(MD->isInstance() &&
@@ -61,7 +61,12 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
6161
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD);
6262

6363
// And the rest of the call args.
64-
if (CE) {
64+
if (RtlArgs) {
65+
// Special case: if the caller emitted the arguments right-to-left already
66+
// (prior to emitting the *this argument), we're done. This happens for
67+
// assignment operators.
68+
Args.addFrom(*RtlArgs);
69+
} else if (CE) {
6570
// Special case: skip first argument of CXXOperatorCall (it is "this").
6671
unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
6772
CGF.EmitCallArgs(Args, FPT, drop_begin(CE->arguments(), ArgsToSkip),
@@ -77,11 +82,11 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
7782
RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
7883
const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
7984
llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
80-
const CallExpr *CE) {
85+
const CallExpr *CE, CallArgList *RtlArgs) {
8186
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
8287
CallArgList Args;
8388
RequiredArgs required = commonEmitCXXMemberOrOperatorCall(
84-
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args);
89+
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
8590
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
8691
Callee, ReturnValue, Args, MD);
8792
}
@@ -92,7 +97,7 @@ RValue CodeGenFunction::EmitCXXDestructorCall(
9297
StructorType Type) {
9398
CallArgList Args;
9499
commonEmitCXXMemberOrOperatorCall(*this, DD, This, ImplicitParam,
95-
ImplicitParamTy, CE, Args);
100+
ImplicitParamTy, CE, Args, nullptr);
96101
return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(DD, Type),
97102
Callee, ReturnValueSlot(), Args, DD);
98103
}
@@ -170,6 +175,19 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
170175
}
171176
}
172177

178+
// C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
179+
// operator before the LHS.
180+
CallArgList RtlArgStorage;
181+
CallArgList *RtlArgs = nullptr;
182+
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
183+
if (OCE->isAssignmentOp()) {
184+
RtlArgs = &RtlArgStorage;
185+
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
186+
drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
187+
/*ParamsToSkip*/0, /*ForceRightToLeftEvaluation*/true);
188+
}
189+
}
190+
173191
Address This = Address::invalid();
174192
if (IsArrow)
175193
This = EmitPointerWithAlignment(Base);
@@ -187,10 +205,12 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
187205
if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
188206
// We don't like to generate the trivial copy/move assignment operator
189207
// when it isn't necessary; just produce the proper effect here.
190-
// Special case: skip first argument of CXXOperatorCall (it is "this").
191-
unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
192-
Address RHS = EmitLValue(*(CE->arg_begin() + ArgsToSkip)).getAddress();
193-
EmitAggregateAssign(This, RHS, CE->getType());
208+
LValue RHS = isa<CXXOperatorCallExpr>(CE)
209+
? MakeNaturalAlignAddrLValue(
210+
(*RtlArgs)[0].RV.getScalarVal(),
211+
(*(CE->arg_begin() + 1))->getType())
212+
: EmitLValue(*CE->arg_begin());
213+
EmitAggregateAssign(This, RHS.getAddress(), CE->getType());
194214
return RValue::get(This.getPointer());
195215
}
196216

@@ -249,7 +269,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
249269
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
250270
}
251271
EmitCXXMemberOrOperatorCall(MD, Callee, ReturnValue, This.getPointer(),
252-
/*ImplicitParam=*/nullptr, QualType(), CE);
272+
/*ImplicitParam=*/nullptr, QualType(), CE,
273+
nullptr);
253274
}
254275
return RValue::get(nullptr);
255276
}
@@ -282,7 +303,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
282303
}
283304

284305
return EmitCXXMemberOrOperatorCall(MD, Callee, ReturnValue, This.getPointer(),
285-
/*ImplicitParam=*/nullptr, QualType(), CE);
306+
/*ImplicitParam=*/nullptr, QualType(), CE,
307+
RtlArgs);
286308
}
287309

288310
RValue

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,7 +2867,8 @@ class CodeGenFunction : public CodeGenTypeCache {
28672867
EmitCXXMemberOrOperatorCall(const CXXMethodDecl *MD, llvm::Value *Callee,
28682868
ReturnValueSlot ReturnValue, llvm::Value *This,
28692869
llvm::Value *ImplicitParam,
2870-
QualType ImplicitParamTy, const CallExpr *E);
2870+
QualType ImplicitParamTy, const CallExpr *E,
2871+
CallArgList *RtlArgs);
28712872
RValue EmitCXXDestructorCall(const CXXDestructorDecl *DD, llvm::Value *Callee,
28722873
llvm::Value *This, llvm::Value *ImplicitParam,
28732874
QualType ImplicitParamTy, const CallExpr *E,
@@ -3322,7 +3323,8 @@ class CodeGenFunction : public CodeGenTypeCache {
33223323
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
33233324
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
33243325
const FunctionDecl *CalleeDecl = nullptr,
3325-
unsigned ParamsToSkip = 0) {
3326+
unsigned ParamsToSkip = 0,
3327+
bool ForceRightToLeftEvaluation = false) {
33263328
SmallVector<QualType, 16> ArgTypes;
33273329
CallExpr::const_arg_iterator Arg = ArgRange.begin();
33283330

@@ -3362,13 +3364,15 @@ class CodeGenFunction : public CodeGenTypeCache {
33623364
for (auto *A : llvm::make_range(Arg, ArgRange.end()))
33633365
ArgTypes.push_back(getVarArgType(A));
33643366

3365-
EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip);
3367+
EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip,
3368+
ForceRightToLeftEvaluation);
33663369
}
33673370

33683371
void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
33693372
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
33703373
const FunctionDecl *CalleeDecl = nullptr,
3371-
unsigned ParamsToSkip = 0);
3374+
unsigned ParamsToSkip = 0,
3375+
bool ForceRightToLeftEvaluation = false);
33723376

33733377
/// EmitPointerWithAlignment - Given an expression with a pointer
33743378
/// type, emit the value and compute our best estimate of the

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,7 +1456,8 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
14561456
Callee = CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type));
14571457

14581458
CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(),
1459-
This.getPointer(), VTT, VTTTy, nullptr);
1459+
This.getPointer(), VTT, VTTTy,
1460+
nullptr, nullptr);
14601461
}
14611462

14621463
void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -1636,7 +1637,7 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
16361637

16371638
CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(),
16381639
This.getPointer(), /*ImplicitParam=*/nullptr,
1639-
QualType(), CE);
1640+
QualType(), CE, nullptr);
16401641
return nullptr;
16411642
}
16421643

0 commit comments

Comments
 (0)