aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancois Pichet <pichet2000@gmail.com>2011-01-18 05:04:39 +0000
committerFrancois Pichet <pichet2000@gmail.com>2011-01-18 05:04:39 +0000
commitdbee3411a22b0dbb03267f5445f7b796104991bb (patch)
treeaa3c7e4cf0f0f5e7f1e4617715e10efbf1cfaa9d
parent4dccb90e92ba9e4abffe0177493b6db9949678dd (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/CodeGen/CGExprCXX.cpp48
-rw-r--r--lib/Parse/ParseExpr.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaOverload.cpp6
-rw-r--r--test/CodeGenCXX/constructor-direct-call.cpp60
-rw-r--r--test/Parser/MicrosoftExtensions.cpp18
7 files changed, 129 insertions, 15 deletions
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<Microsoft>;
// 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<BinaryOperator>(CE->getCallee()->IgnoreParens()))
@@ -127,25 +129,42 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (MD->isTrivial()) {
if (isa<CXXDestructorDecl>(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<CXXConstructorDecl>(MD) &&
+ cast<CXXConstructorDecl>(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<CXXConstructorDecl>(MD) &&
+ cast<CXXConstructorDecl>(MD)->isCopyConstructor()) {
+ llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
+ EmitSynthesizedCXXCopyCtorCall(cast<CXXConstructorDecl>(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<CXXDestructorDecl>(MD)
- ? CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
- Dtor_Complete)
- : CGM.getTypes().getFunctionInfo(MD));
+ const CGFunctionInfo *FInfo = 0;
+ if (isa<CXXDestructorDecl>(MD))
+ FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
+ Dtor_Complete);
+ else if (isa<CXXConstructorDecl>(MD))
+ FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXConstructorDecl>(MD),
+ Ctor_Complete);
+ else
+ FInfo = &CGM.getTypes().getFunctionInfo(MD);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
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<CXXConstructorDecl>(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<UsingShadowDecl>(Func))
Func = cast<UsingShadowDecl>(Func)->getTargetDecl();
- if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
+ // Microsoft supports direct constructor calls.
+ if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) {
+ AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs,
+ CandidateSet);
+ } else if ((Method = dyn_cast<CXXMethodDecl>(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;
+}