r196402 - [ms-cxxabi] Construct and destroy call arguments in the correct order
Reid Kleckner
reid at kleckner.net
Wed Dec 4 11:23:12 PST 2013
Author: rnk
Date: Wed Dec 4 13:23:12 2013
New Revision: 196402
URL: http://llvm.org/viewvc/llvm-project?rev=196402&view=rev
Log:
[ms-cxxabi] Construct and destroy call arguments in the correct order
Summary:
MSVC destroys arguments in the callee from left to right. Because C++
objects have to be destroyed in the reverse order of construction, Clang
has to construct arguments from right to left and destroy arguments from
left to right.
This patch fixes the ordering by reversing the order of evaluation of
all call arguments under the MS C++ ABI.
Fixes PR18035.
Reviewers: rsmith
Differential Revision: http://llvm-reviews.chandlerc.com/D2275
Added:
cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp
cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
Modified:
cfe/trunk/include/clang/Basic/TargetCXXABI.h
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/test/CodeGen/tbaa-ms-abi.cpp
Modified: cfe/trunk/include/clang/Basic/TargetCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetCXXABI.h?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetCXXABI.h (original)
+++ cfe/trunk/include/clang/Basic/TargetCXXABI.h Wed Dec 4 13:23:12 2013
@@ -135,14 +135,14 @@ public:
return !isMicrosoft();
}
- /// Are temporary objects passed by value to a call destroyed by the callee?
+ /// Are arguments to a call destroyed left to right in the callee?
/// This is a fundamental language change, since it implies that objects
/// passed by value do *not* live to the end of the full expression.
/// Temporaries passed to a function taking a const reference live to the end
/// of the full expression as usual. Both the caller and the callee must
/// have access to the destructor, while only the caller needs the
/// destructor if this is false.
- bool isArgumentDestroyedByCallee() const {
+ bool areArgsDestroyedLeftToRightInCallee() const {
return isMicrosoft();
}
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Dec 4 13:23:12 2013
@@ -1246,6 +1246,12 @@ void CodeGenFunction::EmitFunctionProlog
++AI;
}
+ // Create a pointer value for every parameter declaration. This usually
+ // entails copying one or more LLVM IR arguments into an alloca. Don't push
+ // any cleanups or do anything that might unwind. We do that separately, so
+ // we can push the cleanups in the correct order for the ABI.
+ SmallVector<llvm::Value *, 16> ArgVals;
+ ArgVals.reserve(Args.size());
assert(FI.arg_size() == Args.size() &&
"Mismatch between function signature & arguments.");
unsigned ArgNo = 1;
@@ -1299,7 +1305,7 @@ void CodeGenFunction::EmitFunctionProlog
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
}
- EmitParmDecl(*Arg, V, ArgNo);
+ ArgVals.push_back(V);
break;
}
@@ -1340,7 +1346,7 @@ void CodeGenFunction::EmitFunctionProlog
if (V->getType() != LTy)
V = Builder.CreateBitCast(V, LTy);
- EmitParmDecl(*Arg, V, ArgNo);
+ ArgVals.push_back(V);
break;
}
@@ -1413,7 +1419,7 @@ void CodeGenFunction::EmitFunctionProlog
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
}
- EmitParmDecl(*Arg, V, ArgNo);
+ ArgVals.push_back(V);
continue; // Skip ++AI increment, already done.
}
@@ -1426,7 +1432,7 @@ void CodeGenFunction::EmitFunctionProlog
Alloca->setAlignment(Align.getQuantity());
LValue LV = MakeAddrLValue(Alloca, Ty, Align);
llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LV, AI);
- EmitParmDecl(*Arg, Alloca, ArgNo);
+ ArgVals.push_back(Alloca);
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
@@ -1438,10 +1444,9 @@ void CodeGenFunction::EmitFunctionProlog
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (!hasScalarEvaluationKind(Ty))
- EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
+ ArgVals.push_back(CreateMemTemp(Ty));
else
- EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
- ArgNo);
+ ArgVals.push_back(llvm::UndefValue::get(ConvertType(Arg->getType())));
// Skip increment, no matching LLVM parameter.
continue;
@@ -1450,6 +1455,14 @@ void CodeGenFunction::EmitFunctionProlog
++AI;
}
assert(AI == Fn->arg_end() && "Argument mismatch!");
+
+ if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ for (int I = Args.size() - 1; I >= 0; --I)
+ EmitParmDecl(*Args[I], ArgVals[I], I + 1);
+ } else {
+ for (unsigned I = 0, E = Args.size(); I != E; ++I)
+ EmitParmDecl(*Args[I], ArgVals[I], I + 1);
+ }
}
static void eraseUnusedBitCasts(llvm::Instruction *insn) {
@@ -1859,7 +1872,7 @@ static void emitWritebacks(CodeGenFuncti
static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF,
const CallArgList &CallArgs) {
- assert(CGF.getTarget().getCXXABI().isArgumentDestroyedByCallee());
+ assert(CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee());
ArrayRef<CallArgList::CallArgCleanup> Cleanups =
CallArgs.getCleanupsToDeactivate();
// Iterate in reverse to increase the likelihood of popping the cleanup.
@@ -2004,6 +2017,41 @@ static void emitWritebackArg(CodeGenFunc
args.add(RValue::get(finalArgument), CRE->getType());
}
+void CodeGenFunction::EmitCallArgs(CallArgList &Args,
+ ArrayRef<QualType> ArgTypes,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo) {
+ CGDebugInfo *DI = getDebugInfo();
+ SourceLocation CallLoc;
+ if (DI) CallLoc = DI->getLocation();
+
+ // We *have* to evaluate arguments from right to left in the MS C++ ABI,
+ // because arguments are destroyed left to right in the callee.
+ if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ size_t CallArgsStart = Args.size();
+ for (int I = ArgTypes.size() - 1; I >= 0; --I) {
+ CallExpr::const_arg_iterator Arg = ArgBeg + I;
+ EmitCallArg(Args, *Arg, ArgTypes[I]);
+ // Restore the debug location.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
+ }
+
+ // Un-reverse the arguments we just evaluated so they match up with the LLVM
+ // IR function.
+ std::reverse(Args.begin() + CallArgsStart, Args.end());
+ return;
+ }
+
+ for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
+ CallExpr::const_arg_iterator Arg = ArgBeg + I;
+ assert(Arg != ArgEnd);
+ EmitCallArg(Args, *Arg, ArgTypes[I]);
+ // Restore the debug location.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
+ }
+}
+
void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
@@ -2027,7 +2075,7 @@ void CodeGenFunction::EmitCallArg(CallAr
// However, we still have to push an EH-only cleanup in case we unwind before
// we make it to the call.
if (HasAggregateEvalKind &&
- CGM.getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
if (RD && RD->hasNonTrivialDestructor()) {
AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp");
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Dec 4 13:23:12 2013
@@ -1703,38 +1703,23 @@ CodeGenFunction::EmitSynthesizedCXXCopyC
assert(D->isInstance() &&
"Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
CallArgList Args;
// Push the this ptr.
Args.add(RValue::get(This), D->getThisType(getContext()));
-
// Push the src ptr.
QualType QT = *(FPT->arg_type_begin());
llvm::Type *t = CGM.getTypes().ConvertType(QT);
Src = Builder.CreateBitCast(Src, t);
Args.add(RValue::get(Src), QT);
-
+
// Skip over first argument (Src).
- ++ArgBeg;
- CallExpr::const_arg_iterator Arg = ArgBeg;
- for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1,
- E = FPT->arg_type_end(); I != E; ++I, ++Arg) {
- assert(Arg != ArgEnd && "Running over edge of argument list!");
- EmitCallArg(Args, *Arg, *I);
- }
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((Arg == ArgEnd || FPT->isVariadic()) &&
- "Extra arguments in non-variadic function!");
- // If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg) {
- QualType ArgType = Arg->getType();
- EmitCallArg(Args, *Arg, ArgType);
- }
-
+ EmitCallArgs(Args, FPT->isVariadic(), FPT->arg_type_begin() + 1,
+ FPT->arg_type_end(), ArgBeg + 1, ArgEnd);
+
EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, RequiredArgs::All),
Callee, ReturnValueSlot(), Args, D);
}
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Dec 4 13:23:12 2013
@@ -1647,7 +1647,7 @@ void CodeGenFunction::EmitParmDecl(const
DeclPtr = Arg;
// Push a destructor cleanup for this parameter if the ABI requires it.
if (HasNonScalarEvalKind &&
- getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
if (const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (RD->hasNonTrivialDestructor())
pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Dec 4 13:23:12 2013
@@ -1129,35 +1129,12 @@ llvm::Value *CodeGenFunction::EmitCXXNew
allocatorArgs.add(RValue::get(allocSize), sizeType);
- // Emit the rest of the arguments.
- // FIXME: Ideally, this should just use EmitCallArgs.
- CXXNewExpr::const_arg_iterator placementArg = E->placement_arg_begin();
-
- // First, use the types from the function type.
// We start at 1 here because the first argument (the allocation size)
// has already been emitted.
- for (unsigned i = 1, e = allocatorType->getNumArgs(); i != e;
- ++i, ++placementArg) {
- QualType argType = allocatorType->getArgType(i);
-
- assert(getContext().hasSameUnqualifiedType(argType.getNonReferenceType(),
- placementArg->getType()) &&
- "type mismatch in call argument!");
-
- EmitCallArg(allocatorArgs, *placementArg, argType);
- }
-
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((placementArg == E->placement_arg_end() ||
- allocatorType->isVariadic()) &&
- "Extra arguments to non-variadic function!");
-
- // If we still have any arguments, emit them using the type of the argument.
- for (CXXNewExpr::const_arg_iterator placementArgsEnd = E->placement_arg_end();
- placementArg != placementArgsEnd; ++placementArg) {
- EmitCallArg(allocatorArgs, *placementArg, placementArg->getType());
- }
+ EmitCallArgs(allocatorArgs, allocatorType->isVariadic(),
+ allocatorType->arg_type_begin() + 1,
+ allocatorType->arg_type_end(), E->placement_arg_begin(),
+ E->placement_arg_end());
// Emit the allocation call. If the allocator is a global placement
// operator, just "inline" it directly.
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Dec 4 13:23:12 2013
@@ -2493,68 +2493,78 @@ private:
SourceLocation Loc);
/// EmitCallArgs - Emit call arguments for a function.
- /// The CallArgTypeInfo parameter is used for iterating over the known
- /// argument types of the function being called.
- template<typename T>
- void EmitCallArgs(CallArgList& Args, const T* CallArgTypeInfo,
+ template <typename T>
+ void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
bool ForceColumnInfo = false) {
- CGDebugInfo *DI = getDebugInfo();
- SourceLocation CallLoc;
- if (DI) CallLoc = DI->getLocation();
+ if (CallArgTypeInfo) {
+ EmitCallArgs(Args, CallArgTypeInfo->isVariadic(),
+ CallArgTypeInfo->arg_type_begin(),
+ CallArgTypeInfo->arg_type_end(), ArgBeg, ArgEnd,
+ ForceColumnInfo);
+ } else {
+ // T::arg_type_iterator might not have a default ctor.
+ const QualType *NoIter = 0;
+ EmitCallArgs(Args, /*AllowExtraArguments=*/true, NoIter, NoIter, ArgBeg,
+ ArgEnd, ForceColumnInfo);
+ }
+ }
+ template<typename ArgTypeIterator>
+ void EmitCallArgs(CallArgList& Args,
+ bool AllowExtraArguments,
+ ArgTypeIterator ArgTypeBeg,
+ ArgTypeIterator ArgTypeEnd,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo = false) {
+ SmallVector<QualType, 16> ArgTypes;
CallExpr::const_arg_iterator Arg = ArgBeg;
// First, use the argument types that the type info knows about
- if (CallArgTypeInfo) {
- for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(),
- E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) {
- assert(Arg != ArgEnd && "Running over edge of argument list!");
- QualType ArgType = *I;
+ for (ArgTypeIterator I = ArgTypeBeg, E = ArgTypeEnd; I != E; ++I, ++Arg) {
+ assert(Arg != ArgEnd && "Running over edge of argument list!");
#ifndef NDEBUG
- QualType ActualArgType = Arg->getType();
- if (ArgType->isPointerType() && ActualArgType->isPointerType()) {
- QualType ActualBaseType =
+ QualType ArgType = *I;
+ QualType ActualArgType = Arg->getType();
+ if (ArgType->isPointerType() && ActualArgType->isPointerType()) {
+ QualType ActualBaseType =
ActualArgType->getAs<PointerType>()->getPointeeType();
- QualType ArgBaseType =
+ QualType ArgBaseType =
ArgType->getAs<PointerType>()->getPointeeType();
- if (ArgBaseType->isVariableArrayType()) {
- if (const VariableArrayType *VAT =
- getContext().getAsVariableArrayType(ActualBaseType)) {
- if (!VAT->getSizeExpr())
- ActualArgType = ArgType;
- }
+ if (ArgBaseType->isVariableArrayType()) {
+ if (const VariableArrayType *VAT =
+ getContext().getAsVariableArrayType(ActualBaseType)) {
+ if (!VAT->getSizeExpr())
+ ActualArgType = ArgType;
}
}
- assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
- getTypePtr() ==
- getContext().getCanonicalType(ActualArgType).getTypePtr() &&
- "type mismatch in call argument!");
-#endif
- EmitCallArg(Args, *Arg, ArgType);
-
- // Each argument expression could modify the debug
- // location. Restore it.
- if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
}
-
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) &&
- "Extra arguments in non-variadic function!");
-
+ assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
+ getTypePtr() ==
+ getContext().getCanonicalType(ActualArgType).getTypePtr() &&
+ "type mismatch in call argument!");
+#endif
+ ArgTypes.push_back(*I);
}
+ // Either we've emitted all the call args, or we have a call to variadic
+ // function or some other call that allows extra arguments.
+ assert((Arg == ArgEnd || AllowExtraArguments) &&
+ "Extra arguments in non-variadic function!");
+
// If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg) {
- EmitCallArg(Args, *Arg, Arg->getType());
+ for (; Arg != ArgEnd; ++Arg)
+ ArgTypes.push_back(Arg->getType());
- // Restore the debug location.
- if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
- }
+ EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, ForceColumnInfo);
}
+ void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd, bool ForceColumnInfo);
+
const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Dec 4 13:23:12 2013
@@ -6190,8 +6190,9 @@ bool Sema::CheckParmsForFunctionDef(Parm
// MSVC destroys objects passed by value in the callee. Therefore a
// function definition which takes such a parameter must be able to call the
// object's destructor.
- if (getLangOpts().CPlusPlus &&
- Context.getTargetInfo().getCXXABI().isArgumentDestroyedByCallee()) {
+ if (getLangOpts().CPlusPlus && Context.getTargetInfo()
+ .getCXXABI()
+ .areArgsDestroyedLeftToRightInCallee()) {
if (const RecordType *RT = Param->getType()->getAs<RecordType>())
FinalizeVarWithDestructor(Param, RT);
}
Modified: cfe/trunk/test/CodeGen/tbaa-ms-abi.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/tbaa-ms-abi.cpp?rev=196402&r1=196401&r2=196402&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/tbaa-ms-abi.cpp (original)
+++ cfe/trunk/test/CodeGen/tbaa-ms-abi.cpp Wed Dec 4 13:23:12 2013
@@ -16,7 +16,7 @@ StructB::StructB() {
// CHECK: store i32 42, i32* {{.*}}, !tbaa [[TAG_A_i32:!.*]]
}
-// CHECK: [[TYPE_CHAR:!.*]] = metadata !{metadata !"omnipotent char", metadata
-// CHECK: [[TYPE_INT:!.*]] = metadata !{metadata !"int", metadata [[TYPE_CHAR]], i64 0}
+// CHECK: [[TYPE_INT:!.*]] = metadata !{metadata !"int", metadata [[TYPE_CHAR:!.*]], i64 0}
+// CHECK: [[TYPE_CHAR]] = metadata !{metadata !"omnipotent char", metadata
// CHECK: [[TAG_A_i32]] = metadata !{metadata [[TYPE_A:!.*]], metadata [[TYPE_INT]], i64 0}
// CHECK: [[TYPE_A]] = metadata !{metadata !"?AUStructA@@", metadata [[TYPE_INT]], i64 0}
Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp?rev=196402&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp Wed Dec 4 13:23:12 2013
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -mconstructor-aliases -std=c++11 -fexceptions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct A {
+ A(int a);
+ ~A();
+ int a;
+};
+
+void foo(A a, A b, A c) {
+}
+
+// Order of destruction should be left to right.
+//
+// CHECK-LABEL: define void @"\01?foo@@YAXUA@@00 at Z"
+// CHECK: ({{.*}} %[[a:.*]], {{.*}} %[[b:.*]], {{.*}} %[[c:.*]])
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[a]])
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[b]])
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[c]])
+// CHECK: ret void
+
+
+void call_foo() {
+ foo(A(1), A(2), A(3));
+}
+
+// Order of evaluation should be right to left, and we should clean up the right
+// things as we unwind.
+//
+// CHECK-LABEL: define void @"\01?call_foo@@YAXXZ"()
+// CHECK: call x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg3:.*]], i32 3)
+// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg2:.*]], i32 2)
+// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg1:.*]], i32 1)
+// CHECK: call void @"\01?foo@@YAXUA@@00 at Z"({{.*}} %[[arg1]], {{.*}} %[[arg2]], {{.*}} %[[arg3]])
+// CHECK: ret void
+//
+// lpad2:
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[arg2]])
+// CHECK: br label
+//
+// ehcleanup:
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[arg3]])
Added: cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm?rev=196402&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm Wed Dec 4 13:23:12 2013
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -cxx-abi microsoft -mconstructor-aliases -fobjc-arc -triple i686-pc-win32 -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+ A();
+ A(const A &);
+ ~A();
+ int a;
+};
+
+// Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d.
+//
+// CHECK-LABEL: define void @"\01?test_arc_order@@YAXUA@@PAAAPAUobjc_object@@01 at Z"
+// CHECK: ({{.*}} %[[a:.*]], {{.*}}, {{.*}} %[[c:.*]], {{.*}})
+void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) {
+ // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[a]])
+ // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null)
+ // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[c]])
+ // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null)
+ // CHECK: ret void
+}
More information about the cfe-commits
mailing list