Skip to content

Commit a560ccf

Browse files
committed
Switch to a different workaround for unimplementability of P0145R3 in MS ABIs.
Instead of ignoring the evaluation order rule, ignore the "destroy parameters in reverse construction order" rule for the small number of problematic cases. This only causes incorrect behavior in the rare case where both parameters to an overloaded operator <<, >>, ->*, &&, ||, or comma are of class type with non-trivial destructor, and the program is depending on those parameters being destroyed in reverse construction order. We could do a little better here by reversing the order of parameter destruction for those functions (and reversing the argument evaluation order for all direct calls, not just those with operator syntax), but that is not a complete solution to the problem, as the same situation can be reached by an indirect function call. Approach reviewed off-line by rnk. llvm-svn: 282777
1 parent b1b9546 commit a560ccf

File tree

6 files changed

+90
-76
lines changed

6 files changed

+90
-76
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,7 +3173,7 @@ void CodeGenFunction::EmitCallArgs(
31733173
CallArgList &Args, ArrayRef<QualType> ArgTypes,
31743174
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
31753175
const FunctionDecl *CalleeDecl, unsigned ParamsToSkip,
3176-
bool ForceRightToLeftEvaluation) {
3176+
EvaluationOrder Order) {
31773177
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
31783178

31793179
auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg) {
@@ -3191,42 +3191,43 @@ void CodeGenFunction::EmitCallArgs(
31913191
};
31923192

31933193
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
3194-
// because arguments are destroyed left to right in the callee.
3195-
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee() ||
3196-
ForceRightToLeftEvaluation) {
3197-
// Insert a stack save if we're going to need any inalloca args.
3198-
bool HasInAllocaArgs = false;
3194+
// because arguments are destroyed left to right in the callee. As a special
3195+
// case, there are certain language constructs that require left-to-right
3196+
// evaluation, and in those cases we consider the evaluation order requirement
3197+
// to trump the "destruction order is reverse construction order" guarantee.
3198+
bool LeftToRight =
3199+
CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()
3200+
? Order == EvaluationOrder::ForceLeftToRight
3201+
: Order != EvaluationOrder::ForceRightToLeft;
3202+
3203+
// Insert a stack save if we're going to need any inalloca args.
3204+
bool HasInAllocaArgs = false;
3205+
if (CGM.getTarget().getCXXABI().isMicrosoft()) {
31993206
for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();
32003207
I != E && !HasInAllocaArgs; ++I)
32013208
HasInAllocaArgs = isInAllocaArgument(CGM.getCXXABI(), *I);
32023209
if (HasInAllocaArgs) {
32033210
assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
32043211
Args.allocateArgumentMemory(*this);
32053212
}
3213+
}
32063214

3207-
// Evaluate each argument.
3208-
size_t CallArgsStart = Args.size();
3209-
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
3210-
CallExpr::const_arg_iterator Arg = ArgRange.begin() + I;
3211-
MaybeEmitImplicitObjectSize(I, *Arg);
3212-
EmitCallArg(Args, *Arg, ArgTypes[I]);
3213-
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
3214-
CalleeDecl, ParamsToSkip + I);
3215-
}
3215+
// Evaluate each argument in the appropriate order.
3216+
size_t CallArgsStart = Args.size();
3217+
for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
3218+
unsigned Idx = LeftToRight ? I : E - I - 1;
3219+
CallExpr::const_arg_iterator Arg = ArgRange.begin() + Idx;
3220+
if (!LeftToRight) MaybeEmitImplicitObjectSize(Idx, *Arg);
3221+
EmitCallArg(Args, *Arg, ArgTypes[Idx]);
3222+
EmitNonNullArgCheck(Args.back().RV, ArgTypes[Idx], (*Arg)->getExprLoc(),
3223+
CalleeDecl, ParamsToSkip + Idx);
3224+
if (LeftToRight) MaybeEmitImplicitObjectSize(Idx, *Arg);
3225+
}
32163226

3227+
if (!LeftToRight) {
32173228
// Un-reverse the arguments we just evaluated so they match up with the LLVM
32183229
// IR function.
32193230
std::reverse(Args.begin() + CallArgsStart, Args.end());
3220-
return;
3221-
}
3222-
3223-
for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
3224-
CallExpr::const_arg_iterator Arg = ArgRange.begin() + I;
3225-
assert(Arg != ArgRange.end());
3226-
EmitCallArg(Args, *Arg, ArgTypes[I]);
3227-
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
3228-
CalleeDecl, ParamsToSkip + I);
3229-
MaybeEmitImplicitObjectSize(I, *Arg);
32303231
}
32313232
}
32323233

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4123,15 +4123,33 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
41234123
CGM.getContext().VoidPtrTy);
41244124

41254125
// 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();
4126+
// right-to-left, and that we evaluate arguments to certain other operators
4127+
// left-to-right. Note that we allow this to override the order dictated by
4128+
// the calling convention on the MS ABI, which means that parameter
4129+
// destruction order is not necessarily reverse construction order.
4130+
// FIXME: Revisit this based on C++ committee response to unimplementability.
4131+
EvaluationOrder Order = EvaluationOrder::Default;
4132+
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
4133+
if (OCE->isAssignmentOp())
4134+
Order = EvaluationOrder::ForceRightToLeft;
4135+
else {
4136+
switch (OCE->getOperator()) {
4137+
case OO_LessLess:
4138+
case OO_GreaterGreater:
4139+
case OO_AmpAmp:
4140+
case OO_PipePipe:
4141+
case OO_Comma:
4142+
case OO_ArrowStar:
4143+
Order = EvaluationOrder::ForceLeftToRight;
4144+
break;
4145+
default:
4146+
break;
4147+
}
4148+
}
4149+
}
41324150

41334151
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), E->arguments(),
4134-
E->getDirectCallee(), /*ParamsToSkip*/ 0, ForceRightToLeft);
4152+
E->getDirectCallee(), /*ParamsToSkip*/ 0, Order);
41354153

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

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
184184
RtlArgs = &RtlArgStorage;
185185
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
186186
drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
187-
/*ParamsToSkip*/0, /*ForceRightToLeftEvaluation*/true);
187+
/*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
188188
}
189189
}
190190

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3318,13 +3318,22 @@ class CodeGenFunction : public CodeGenTypeCache {
33183318
static bool isObjCMethodWithTypeParams(const T *) { return false; }
33193319
#endif
33203320

3321+
enum class EvaluationOrder {
3322+
///! No language constraints on evaluation order.
3323+
Default,
3324+
///! Language semantics require left-to-right evaluation.
3325+
ForceLeftToRight,
3326+
///! Language semantics require right-to-left evaluation.
3327+
ForceRightToLeft
3328+
};
3329+
33213330
/// EmitCallArgs - Emit call arguments for a function.
33223331
template <typename T>
33233332
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
33243333
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
33253334
const FunctionDecl *CalleeDecl = nullptr,
33263335
unsigned ParamsToSkip = 0,
3327-
bool ForceRightToLeftEvaluation = false) {
3336+
EvaluationOrder Order = EvaluationOrder::Default) {
33283337
SmallVector<QualType, 16> ArgTypes;
33293338
CallExpr::const_arg_iterator Arg = ArgRange.begin();
33303339

@@ -3364,15 +3373,14 @@ class CodeGenFunction : public CodeGenTypeCache {
33643373
for (auto *A : llvm::make_range(Arg, ArgRange.end()))
33653374
ArgTypes.push_back(getVarArgType(A));
33663375

3367-
EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip,
3368-
ForceRightToLeftEvaluation);
3376+
EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip, Order);
33693377
}
33703378

33713379
void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
33723380
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
33733381
const FunctionDecl *CalleeDecl = nullptr,
33743382
unsigned ParamsToSkip = 0,
3375-
bool ForceRightToLeftEvaluation = false);
3383+
EvaluationOrder Order = EvaluationOrder::Default);
33763384

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

clang/test/CodeGenCXX/cxx1z-eval-order.cpp

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,15 @@ int dotstar_lhs_before_rhs() {
151151
// CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
152152
make_c()->*make_a();
153153

154-
// FIXME: The corresponding case for Windows ABIs is unimplementable if the
155-
// operand has a non-trivially-destructible type, because the order of
156-
// construction of function arguments is defined by the ABI there (it's the
157-
// reverse of the order in which the parameters are destroyed in the callee).
158-
// But we could follow the C++17 rule in the case where the operand type is
159-
// trivially-destructible.
160-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
161-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
162-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
163-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
154+
// FIXME: For MS ABI, the order of destruction of parameters here will not be
155+
// reverse construction order (parameters are destroyed left-to-right in the
156+
// callee). That sadly seems unavoidable; the rules are not implementable as
157+
// specified. If we changed parameter destruction order for these functions
158+
// to right-to-left, we could make the destruction order match for all cases
159+
// other than indirect calls, but we can't completely avoid the problem.
160+
//
161+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
162+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
164163
make_c()->*make_b();
165164

166165
// CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
@@ -228,17 +227,13 @@ void shift_lhs_before_rhs() {
228227
// CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
229228
make_c() >> make_a();
230229

231-
// FIXME: This is unimplementable for Windows ABIs, see above.
232-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
233-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
234-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
235-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
230+
// FIXME: This is not correct for Windows ABIs, see above.
231+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
232+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
236233
make_c() << make_b();
237234

238-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
239-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
240-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
241-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
235+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
236+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
242237
make_c() >> make_b();
243238
// CHECK: }
244239
}
@@ -249,11 +244,9 @@ void comma_lhs_before_rhs() {
249244
// CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
250245
make_c() , make_a();
251246

252-
// FIXME: This is unimplementable for Windows ABIs, see above.
253-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
254-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
255-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
256-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
247+
// FIXME: This is not correct for Windows ABIs, see above.
248+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
249+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
257250
make_c() , make_b();
258251
}
259252

@@ -267,16 +260,12 @@ void andor_lhs_before_rhs() {
267260
// CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
268261
make_c() || make_a();
269262

270-
// FIXME: This is unimplementable for Windows ABIs, see above.
271-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
272-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
273-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
274-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
263+
// FIXME: This is not correct for Windows ABIs, see above.
264+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
265+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
275266
make_c() && make_b();
276267

277-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_c{{.*}}(
278-
// CHECK-ITANIUM: call {{.*}}@{{.*}}make_b{{.*}}(
279-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_b{{.*}}(
280-
// CHECK-WINDOWS: call {{.*}}@{{.*}}make_c{{.*}}(
268+
// CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
269+
// CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
281270
make_c() || make_b();
282271
}

clang/www/cxx_status.html

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -740,14 +740,12 @@ <h2 id="cxx17">C++1z implementation status</h2>
740740
<span id="p0136">(9): This is the resolution to a Defect Report, so is applied
741741
to all language versions supporting inheriting constructors.
742742
</span><br>
743-
<span id="p0145">(10): Under the MS ABI, this feature is not fully implementable,
744-
because the calling convention requires that function parameters are destroyed
745-
from left to right in the callee. In order to guarantee that destruction order
746-
is reverse construction order, the operands of overloaded
743+
<span id="p0145">(10): Under the MS ABI, function parameters are destroyed from
744+
left to right in the callee. As a result, function parameters in calls to
747745
<tt>operator&lt;&lt;</tt>, <tt>operator&gt;&gt;</tt>, <tt>operator-&gt;*</tt>,
748746
<tt>operator&amp;&amp;</tt>, <tt>operator||</tt>, and <tt>operator,</tt>
749-
functions are evaluated right-to-left under the MS ABI when called using operator
750-
syntax, not left-to-right as P0145R3 requires.
747+
functions using expression syntax are no longer guaranteed to be destroyed in
748+
reverse construction order in that ABI.
751749
</span>
752750
</p>
753751
</details>

0 commit comments

Comments
 (0)