From dbee3411a22b0dbb03267f5445f7b796104991bb Mon Sep 17 00:00:00 2001 From: Francois Pichet Date: Tue, 18 Jan 2011 05:04:39 +0000 Subject: [PATCH] Add support for explicit constructor calls in Microsoft mode. For example: class A{ public: A& operator=(const A& that) { if (this != &that) { this->A::~A(); this->A::A(that); // <=== explicit constructor call. } return *this; } }; More work will be needed to support an explicit call to a template constructor. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123735 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 + lib/CodeGen/CGExprCXX.cpp | 48 ++++++++++++----- lib/Parse/ParseExpr.cpp | 4 +- lib/Sema/SemaExpr.cpp | 6 +++ lib/Sema/SemaOverload.cpp | 6 ++- test/CodeGenCXX/constructor-direct-call.cpp | 60 +++++++++++++++++++++ test/Parser/MicrosoftExtensions.cpp | 18 +++++++ 7 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 test/CodeGenCXX/constructor-direct-call.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f4cc7deedf..1c1600a735 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -738,6 +738,8 @@ def warn_no_constructor_for_refconst : Warning< "initialize its non-modifiable members">; def note_refconst_member_not_initialized : Note< "%select{const|reference}0 member %1 will never be initialized">; +def ext_ms_explicit_constructor_call : ExtWarn< + "explicit constructor calls are a Microsoft extension">, InGroup; // C++ destructors def err_destructor_not_member : Error< diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 77ccdd0d72..246ecb2d2c 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -93,6 +93,8 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base, return false; } +// Note: This function also emit constructor calls to support a MSVC +// extensions allowing explicit constructor function call. RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, ReturnValueSlot ReturnValue) { if (isa(CE->getCallee()->IgnoreParens())) @@ -127,25 +129,42 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, if (MD->isTrivial()) { if (isa(MD)) return RValue::get(0); - - assert(MD->isCopyAssignmentOperator() && "unknown trivial member function"); - // We don't like to generate the trivial copy assignment operator when - // it isn't necessary; just produce the proper effect here. - llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); - EmitAggregateCopy(This, RHS, CE->getType()); - return RValue::get(This); + if (isa(MD) && + cast(MD)->isDefaultConstructor()) + return RValue::get(0); + + if (MD->isCopyAssignmentOperator()) { + // We don't like to generate the trivial copy assignment operator when + // it isn't necessary; just produce the proper effect here. + llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); + EmitAggregateCopy(This, RHS, CE->getType()); + return RValue::get(This); + } + + if (isa(MD) && + cast(MD)->isCopyConstructor()) { + llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); + EmitSynthesizedCXXCopyCtorCall(cast(MD), This, RHS, + CE->arg_begin(), CE->arg_end()); + return RValue::get(This); + } + llvm_unreachable("unknown trivial member function"); } // Compute the function type we're calling. - const CGFunctionInfo &FInfo = - (isa(MD) - ? CGM.getTypes().getFunctionInfo(cast(MD), - Dtor_Complete) - : CGM.getTypes().getFunctionInfo(MD)); + const CGFunctionInfo *FInfo = 0; + if (isa(MD)) + FInfo = &CGM.getTypes().getFunctionInfo(cast(MD), + Dtor_Complete); + else if (isa(MD)) + FInfo = &CGM.getTypes().getFunctionInfo(cast(MD), + Ctor_Complete); + else + FInfo = &CGM.getTypes().getFunctionInfo(MD); const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty - = CGM.getTypes().GetFunctionType(FInfo, FPT->isVariadic()); + = CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic()); // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the @@ -163,6 +182,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } else { Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty); } + } else if (const CXXConstructorDecl *Ctor = + dyn_cast(MD)) { + Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty); } else if (UseVirtualCall) { Callee = BuildVirtualCall(MD, This, Ty); } else { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f48b7a5faa..acbf3a5a92 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1171,11 +1171,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it // names a real destructor. + // Allow explicit constructor calls in Microsoft mode. + // FIXME: Add support for explicit call of template constructor. UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/false, + /*AllowConstructorName=*/ getLang().Microsoft, ObjectType, Name)) LHS = ExprError(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 26fdb2e059..45e0c3377b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3902,6 +3902,12 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, if (SS.isSet() && SS.isInvalid()) return ExprError(); + // Warn about the explicit constructor calls Microsoft extension. + if (getLangOptions().Microsoft && + Id.getKind() == UnqualifiedId::IK_ConstructorName) + Diag(Id.getSourceRange().getBegin(), + diag::ext_ms_explicit_constructor_call); + TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the name into its component parts. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 80ef65e433..4bb95912e6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -7904,7 +7904,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (isa(Func)) Func = cast(Func)->getTargetDecl(); - if ((Method = dyn_cast(Func))) { + // Microsoft supports direct constructor calls. + if (getLangOptions().Microsoft && isa(Func)) { + AddOverloadCandidate(cast(Func), I.getPair(), Args, NumArgs, + CandidateSet); + } else if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. if (TemplateArgs) diff --git a/test/CodeGenCXX/constructor-direct-call.cpp b/test/CodeGenCXX/constructor-direct-call.cpp new file mode 100644 index 0000000000..0c969bc832 --- /dev/null +++ b/test/CodeGenCXX/constructor-direct-call.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -fms-extensions -Wmicrosoft %s -emit-llvm -o - | FileCheck %s + +class Test1 { +public: + int a; +}; + +void f1() { + Test1 var; + var.Test1::Test1(); + + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 4, i32 4, i1 false) + var.Test1::Test1(var); +} + +class Test2 { +public: + Test2() { a = 10; b = 10; } + int a; + int b; +}; + +void f2() { + // CHECK: %var = alloca %class.Test2, align 4 + // CHECK-NEXT: call void @_ZN5Test2C1Ev(%class.Test2* %var) + Test2 var; + + // CHECK-NEXT: call void @_ZN5Test2C1Ev(%class.Test2* %var) + var.Test2::Test2(); + + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 8, i32 4, i1 false) + var.Test2::Test2(var); +} + + + + +class Test3 { +public: + Test3() { a = 10; b = 15; c = 20; } + Test3(const Test3& that) { a = that.a; b = that.b; c = that.c; } + int a; + int b; + int c; +}; + +void f3() { + // CHECK: call void @_ZN5Test3C1Ev(%class.Test3* %var) + Test3 var; + + // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var2) + Test3 var2; + + // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var) + var.Test3::Test3(); + + // CHECK-NEXT: call void @_ZN5Test3C1ERKS_(%class.Test3* %var, %class.Test3* %var2) + var.Test3::Test3(var2); +} + diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index bc8e88d64b..1d5811496a 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -85,3 +85,21 @@ void template_uuid() __uuidof(T); __uuidof(expr); } + + + +class CtorCall { +public: + CtorCall& operator=(const CtorCall& that); + + int a; +}; + +CtorCall& CtorCall::operator=(const CtorCall& that) +{ + if (this != &that) { + this->CtorCall::~CtorCall(); + this->CtorCall::CtorCall(that); // expected-warning {{explicit constructor calls are a Microsoft extension}} + } + return *this; +} -- 2.40.0