]> granicus.if.org Git - clang/commitdiff
Add support for explicit constructor calls in Microsoft mode.
authorFrancois Pichet <pichet2000@gmail.com>
Tue, 18 Jan 2011 05:04:39 +0000 (05:04 +0000)
committerFrancois Pichet <pichet2000@gmail.com>
Tue, 18 Jan 2011 05:04:39 +0000 (05:04 +0000)
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
lib/CodeGen/CGExprCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
test/CodeGenCXX/constructor-direct-call.cpp [new file with mode: 0644]
test/Parser/MicrosoftExtensions.cpp

index f4cc7deedfc8f2e3caf16c50617154b72d7e4c09..1c1600a735de5c314a30131edaa90103df6a6200 100644 (file)
@@ -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<
index 77ccdd0d720a12c300488b081217f6ed2f95142f..246ecb2d2cda78feb7c3edf8228c522e1da4a5f0 100644 (file)
@@ -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 {
index f48b7a5faa49f089128286a40ecc91ccb1b6c0c0..acbf3a5a927490956fe72642cf52e71bb978a7f5 100644 (file)
@@ -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();
index 26fdb2e059cde3156ef917c2e005c8b6f411d175..45e0c3377b830ba0b097310467bb13a9603b83e8 100644 (file)
@@ -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.
index 80ef65e43359dc0ac0aa9d9d5df098c01e2dad38..4bb95912e6682e3d504b4ac8ae1ef496efb631ab 100644 (file)
@@ -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 (file)
index 0000000..0c969bc
--- /dev/null
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fms-extensions -Wmicrosoft %s -emit-llvm -o - | FileCheck %s\r
+\r
+class Test1 {\r
+public:\r
+   int a;\r
+};\r
+\r
+void f1() {\r
+  Test1 var;\r
+  var.Test1::Test1();\r
+\r
+  // CHECK:   call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 4, i32 4, i1 false)\r
+  var.Test1::Test1(var);\r
+}\r
+\r
+class Test2 {\r
+public:\r
+  Test2() { a = 10; b = 10; }\r
+   int a;\r
+   int b;\r
+};\r
+\r
+void f2() {\r
+  // CHECK:  %var = alloca %class.Test2, align 4\r
+  // CHECK-NEXT:  call void @_ZN5Test2C1Ev(%class.Test2* %var)\r
+  Test2 var;\r
+\r
+  // CHECK-NEXT:  call void @_ZN5Test2C1Ev(%class.Test2* %var)\r
+  var.Test2::Test2();\r
+\r
+  // CHECK:  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 8, i32 4, i1 false)\r
+  var.Test2::Test2(var);\r
+}\r
+\r
+\r
+\r
+\r
+class Test3 {\r
+public:\r
+  Test3() { a = 10; b = 15; c = 20; }\r
+  Test3(const Test3& that) { a = that.a; b = that.b; c = that.c; }\r
+   int a;\r
+   int b;\r
+   int c;\r
+};\r
+\r
+void f3() {\r
+  // CHECK: call void @_ZN5Test3C1Ev(%class.Test3* %var)\r
+  Test3 var;\r
+\r
+  // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var2)\r
+  Test3 var2;\r
+\r
+  // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var)\r
+  var.Test3::Test3();\r
+\r
+  // CHECK-NEXT: call void @_ZN5Test3C1ERKS_(%class.Test3* %var, %class.Test3* %var2)\r
+  var.Test3::Test3(var2);\r
+}\r
+\r
index bc8e88d64bbe721559695a4d55a9bdff7adcae94..1d5811496a76bf279e0c8fa2fb62a442497dfcc8 100644 (file)
@@ -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;
+}