/// \brief Is the default C++ member function calling convention
/// the same as the default calling convention?
bool isMemberFunctionCCDefault() const {
- // Right now, this is always true for Microsoft.
+ // Right now, this is always false for Microsoft.
return !isMicrosoft();
}
+ /// Are temporary objects passed by value to a call destroyed by 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 {
+ return isMicrosoft();
+ }
+
/// \brief Does this ABI have different entrypoints for complete-object
/// and base-subobject constructors?
bool hasConstructorVariants() const {
emitWriteback(CGF, *i);
}
+static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF,
+ const CallArgList &CallArgs) {
+ assert(CGF.getTarget().getCXXABI().isArgumentDestroyedByCallee());
+ ArrayRef<CallArgList::CallArgCleanup> Cleanups =
+ CallArgs.getCleanupsToDeactivate();
+ // Iterate in reverse to increase the likelihood of popping the cleanup.
+ for (ArrayRef<CallArgList::CallArgCleanup>::reverse_iterator
+ I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) {
+ CGF.DeactivateCleanupBlock(I->Cleanup, I->IsActiveIP);
+ I->IsActiveIP->eraseFromParent();
+ }
+}
+
static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
if (uop->getOpcode() == UO_AddrOf)
return args.add(EmitReferenceBindingToExpr(E), type);
}
- if (hasAggregateEvaluationKind(type) &&
- isa<ImplicitCastExpr>(E) &&
+ bool HasAggregateEvalKind = hasAggregateEvaluationKind(type);
+
+ // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
+ // 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()) {
+ const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+ if (RD && RD->hasNonTrivialDestructor()) {
+ AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp");
+ Slot.setExternallyDestructed();
+ EmitAggExpr(E, Slot);
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+
+ pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject,
+ /*useEHCleanupForArray*/ true);
+ // This unreachable is a temporary marker which will be removed later.
+ llvm::Instruction *IsActive = Builder.CreateUnreachable();
+ args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive);
+ return;
+ }
+ }
+
+ if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
assert(L.isSimple());
}
}
+ if (!CallArgs.getCleanupsToDeactivate().empty())
+ deactivateArgCleanupsBeforeCall(*this, CallArgs);
+
// If the callee is a bitcast of a function to a varargs pointer to function
// type, check to see if we can remove the bitcast. This handles some cases
// with unprototyped functions.
#define CLANG_CODEGEN_CGCALL_H
#include "CGValue.h"
+#include "EHScopeStack.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/FoldingSet.h"
llvm::Value *ToUse;
};
+ struct CallArgCleanup {
+ EHScopeStack::stable_iterator Cleanup;
+
+ /// The "is active" insertion point. This instruction is temporary and
+ /// will be removed after insertion.
+ llvm::Instruction *IsActiveIP;
+ };
+
void add(RValue rvalue, QualType type, bool needscopy = false) {
push_back(CallArg(rvalue, type, needscopy));
}
writeback_iterator writeback_begin() const { return Writebacks.begin(); }
writeback_iterator writeback_end() const { return Writebacks.end(); }
+ void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
+ llvm::Instruction *IsActiveIP) {
+ CallArgCleanup ArgCleanup;
+ ArgCleanup.Cleanup = Cleanup;
+ ArgCleanup.IsActiveIP = IsActiveIP;
+ CleanupsToDeactivate.push_back(ArgCleanup);
+ }
+
+ ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const {
+ return CleanupsToDeactivate;
+ }
+
private:
SmallVector<Writeback, 1> Writebacks;
+
+ /// Deactivate these cleanups immediately before making the call. This
+ /// is used to cleanup objects that are owned by the callee once the call
+ /// occurs.
+ SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
};
/// A class for recording the number of arguments that a function
}
llvm::Value *DeclPtr;
+ bool HasNonScalarEvalKind = !CodeGenFunction::hasScalarEvaluationKind(Ty);
// If this is an aggregate or variable sized value, reuse the input pointer.
- if (!Ty->isConstantSizeType() ||
- !CodeGenFunction::hasScalarEvaluationKind(Ty)) {
+ if (HasNonScalarEvalKind || !Ty->isConstantSizeType()) {
DeclPtr = Arg;
+ // Push a destructor cleanup for this parameter if the ABI requires it.
+ if (HasNonScalarEvalKind &&
+ getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ if (const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
+ if (RD->hasNonTrivialDestructor())
+ pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
+ }
+ }
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
}
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
- if (RD->hasNonTrivialCopyConstructor())
+ if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
return RAA_DirectInMemory;
return RAA_Default;
}
}
PType= AT->getElementType();
}
+
+ // 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 (const RecordType *RT = Param->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(Param, RT);
+ }
}
return HasInvalidParm;
--- /dev/null
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -cxx-abi microsoft -fexceptions | FileCheck -check-prefix WIN32 %s
+
+struct A {
+ A();
+ ~A();
+ int a;
+};
+
+A getA();
+
+int TakesTwo(A a, A b);
+void HasEHCleanup() {
+ TakesTwo(getA(), getA());
+}
+
+// With exceptions, we need to clean up at least one of these temporaries.
+// WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
+// First one doesn't have any cleanups, no need for invoke.
+// WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
+// If this call throws, we have to cleanup the first temporary.
+// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
+// If this call throws, we already popped our cleanups
+// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// WIN32: ret void
+//
+// There should be one dtor call for unwinding from the second getA.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: }
+
+void TakeRef(const A &a);
+int HasDeactivatedCleanups() {
+ return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
+}
+
+// WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
+// WIN32: %[[isactive:.*]] = alloca i1
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]])
+// WIN32: store i1 true, i1* %[[isactive]]
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 false, i1* %[[isactive]]
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// Destroy the two const ref temporaries.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: ret i32
+//
+// Conditionally destroy arg1.
+// WIN32: %[[cond:.*]] = load i1* %[[isactive]]
+// WIN32: br i1 %[[cond]]
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
+
+// Test putting the cleanups inside a conditional.
+int CouldThrow();
+int HasConditionalCleanup(bool cond) {
+ return (cond ? TakesTwo(A(), A()) : CouldThrow());
+}
+
+// WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} {
+// WIN32: store i1 false
+// WIN32: br i1
+// No cleanups, so we call and then activate a cleanup if it succeeds.
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]])
+// WIN32: store i1 true
+// Now we have a cleanup for the first aggregate, so we invoke.
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
+// Now we have no cleanups because TakeTwo will destruct both args.
+// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// Still no cleanups, so call.
+// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()
+// Somewhere in the landing pad for our single invoke, call the dtor.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
+
+// Now test both.
+int HasConditionalDeactivatedCleanups(bool cond) {
+ return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
+}
+
+// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {
+// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4
+// WIN32: alloca i1
+// WIN32: %[[arg1_cond:.*]] = alloca i1
+// Start all four cleanups as deactivated.
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: store i1 false
+// WIN32: br i1
+// True condition.
+// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: store i1 true, i1* %[[arg1_cond]]
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
+// WIN32: store i1 true
+// WIN32: store i1 false, i1* %[[arg1_cond]]
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
+// False condition.
+// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
+// Two normal cleanups for TakeRef args.
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
+// WIN32: ret i32
+//
+// Somewhere in the landing pad soup, we conditionally destroy arg1.
+// WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]]
+// WIN32: br i1 %[[isactive]]
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
+// WIN32: }
int x;
};
+struct SmallWithDtor {
+ SmallWithDtor();
+ ~SmallWithDtor();
+ int x;
+};
+
struct SmallWithVftable {
int x;
virtual void foo();
// WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(%struct.SmallWithCtor* byval align 4 %s)
// WIN64: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce)
+// Test that dtors are invoked in the callee.
+void small_arg_with_dtor(SmallWithDtor s) {}
+// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %s)
+// WIN32: }
+// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} {
+// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s)
+// WIN64: }
+
+// Test that references aren't destroyed in the callee.
+void ref_small_arg_with_dtor(const SmallWithDtor &s) { }
+// WIN32: define void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} {
+// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
+// Test that temporaries passed by reference are destroyed in the caller.
+void temporary_ref_with_dtor() {
+ ref_small_arg_with_dtor(SmallWithDtor());
+}
+// WIN32: define void @"\01?temporary_ref_with_dtor@@YAXXZ"() {{.*}} {
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"
+// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
+void takes_two_by_val_with_dtor(SmallWithDtor a, SmallWithDtor b);
+void eh_cleanup_arg_with_dtor() {
+ takes_two_by_val_with_dtor(SmallWithDtor(), SmallWithDtor());
+}
+// When exceptions are off, we don't have any cleanups. See
+// microsoft-abi-exceptions.cpp for these cleanups.
+// WIN32: define void @"\01?eh_cleanup_arg_with_dtor@@YAXXZ"() {{.*}} {
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
+// WIN32: call void @"\01?takes_two_by_val_with_dtor@@YAXUSmallWithDtor@@0@Z"
+// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
+// WIN32: }
+
void small_arg_with_vftable(SmallWithVftable s) {}
// LINUX: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s)
c.thiscall_method_arg(SmallWithCtor());
c.thiscall_method_arg(Big());
}
+
+struct X {
+ X();
+ ~X();
+};
+void g(X) {
+}
+// WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* %0)
+// WIN32: }
+void f() {
+ g(X());
+}
+// WIN32: define void @"\01?f@@YAXXZ"() {{.*}} {
+// WIN32-NOT: call {{.*}} @"\01??1X@@QAE@XZ"
+// WIN32: }
// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi itanium -fsyntax-only %s
-// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -verify %s
+// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -verify -DMSVC_ABI %s
+
+namespace Test1 {
// Should be accepted under the Itanium ABI (first RUN line) but rejected
// under the Microsoft ABI (second RUN line), as Microsoft ABI requires
struct VC : A, B {
virtual ~VC(); // expected-error {{member 'operator delete' found in multiple base classes of different types}}
};
+
+}
+
+namespace Test2 {
+
+// In the MSVC ABI, functions must destroy their aggregate arguments. foo
+// requires a dtor for B, but we can't implicitly define it because ~A is
+// private. bar should be able to call A's private dtor without error, even
+// though MSVC rejects bar.
+
+class A {
+private:
+ ~A(); // expected-note 2{{declared private here}}
+ int a;
+};
+
+struct B : public A { // expected-error {{base class 'Test2::A' has private destructor}}
+ int b;
+};
+
+struct C {
+ ~C();
+ int c;
+};
+
+struct D {
+ // D has a non-trivial implicit dtor that destroys C.
+ C o;
+};
+
+void foo(B b) { } // expected-note {{implicit destructor for 'Test2::B' first required here}}
+void bar(A a) { } // expected-error {{variable of type 'Test2::A' has private destructor}}
+void baz(D d) { } // no error
+
+}
+
+#ifdef MSVC_ABI
+namespace Test3 {
+
+class A {
+ A();
+ ~A(); // expected-note 2{{implicitly declared private here}}
+ friend void bar(A);
+ int a;
+};
+
+void bar(A a) { }
+void baz(A a) { } // expected-error {{variable of type 'Test3::A' has private destructor}}
+
+// MSVC accepts foo() but we reject it for consistency with Itanium. MSVC also
+// rejects this if A has a copy ctor or if we call A's ctor.
+void foo(A *a) {
+ bar(*a); // expected-error {{temporary of type 'Test3::A' has private destructor}}
+}
+}
+#endif
+
+namespace Test4 {
+// Don't try to access the dtor of an incomplete on a function declaration.
+class A;
+void foo(A a);
+}