]> granicus.if.org Git - clang/commitdiff
PR24595: Ignore calling convention modifiers for structors in MS ABI.
authorAndrey Bokhanko <andreybokhanko@gmail.com>
Mon, 14 Sep 2015 21:29:57 +0000 (21:29 +0000)
committerAndrey Bokhanko <andreybokhanko@gmail.com>
Mon, 14 Sep 2015 21:29:57 +0000 (21:29 +0000)
MS compiler ignores calling convention modifiers for structors. This patch makes
clang do the same (for MS ABI). This fixes PR24595 and makes vswriter.h header
(from Windows SDK 8.1) compilable.

Differential Revision: http://reviews.llvm.org/D12402

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247619 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/DeclSpec.h
include/clang/Sema/Sema.h
lib/Sema/DeclSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
test/CodeGenCXX/microsoft-abi-structors.cpp
test/SemaCXX/decl-microsoft-call-conv.cpp

index de34acca37f2e20d711ba72eeceb66e23cc01f9f..71d1ab32e44e73ae5f76a0fb880b3926b5157f42 100644 (file)
@@ -2375,6 +2375,9 @@ def err_cconv_varargs : Error<
 def warn_cconv_varargs : Warning<
   "%0 calling convention ignored on variadic function">,
   InGroup<IgnoredAttributes>;
+def warn_cconv_structors : Warning<
+  "%0 calling convention ignored on constructor/destructor">,
+  InGroup<IgnoredAttributes>;
 def err_regparm_mismatch : Error<"function declared with regparm(%0) "
   "attribute was previously declared "
   "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
index 980ac5514019aef134a859b7456b1a1e4e2d7568..1bd2bb8d92105884d11b8910e3f36b1ef501e495 100644 (file)
@@ -2208,6 +2208,9 @@ public:
   /// redeclaration time if the decl is static.
   bool isStaticMember();
 
+  /// Returns true if this declares a constructor or a destructor.
+  bool isCtorOrDtor();
+
   void setRedeclaration(bool Val) { Redeclaration = Val; }
   bool isRedeclaration() const { return Redeclaration; }
 };
index 9e9e2bbacb4c9af09321bc51054356354dec7aee..57bf65e7cecf867b99a6b87296070058a10cef98 100644 (file)
@@ -2919,7 +2919,8 @@ public:
   /// Adjust the calling convention of a method to be the ABI default if it
   /// wasn't specified explicitly.  This handles method types formed from
   /// function type typedefs and typename template arguments.
-  void adjustMemberFunctionCC(QualType &T, bool IsStatic);
+  void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
+                              SourceLocation Loc);
 
   // Check if there is an explicit attribute, but only look through parens.
   // The intent is to look for an attribute on the current declarator, but not
index 357f2d3a030189b004c50c0d2e42195055977081..2cf35b9d280b3b11ed395280147fd036ca71f516 100644 (file)
@@ -351,6 +351,11 @@ bool Declarator::isStaticMember() {
               getName().OperatorFunctionId.Operator));
 }
 
+bool Declarator::isCtorOrDtor() {
+  return (getName().getKind() == UnqualifiedId::IK_ConstructorName) ||
+         (getName().getKind() == UnqualifiedId::IK_DestructorName);
+}
+
 bool DeclSpec::hasTagDefinition() const {
   if (!TypeSpecOwned)
     return false;
index 43aa2d73fc6a083e9fa5b1a66f481c1e36871db3..8501bc5b2242cbfb2d465ee6ee3c40c51f5812f7 100644 (file)
@@ -7244,7 +7244,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       << DeclSpec::getSpecifierName(TSCS);
 
   if (D.isFirstDeclarationOfMember())
-    adjustMemberFunctionCC(R, D.isStaticMember());
+    adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(),
+                           D.getIdentifierLoc());
 
   bool isFriend = false;
   FunctionTemplateDecl *FunctionTemplate = nullptr;
index 012b65b799f976f1bd4ace299b3589cfea9d60e8..6304599227654322a77971dea41e44b0ef6e1fe4 100644 (file)
@@ -2269,8 +2269,11 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
 
   // Adjust the default free function calling convention to the default method
   // calling convention.
+  bool IsCtorOrDtor =
+      (Entity.getNameKind() == DeclarationName::CXXConstructorName) ||
+      (Entity.getNameKind() == DeclarationName::CXXDestructorName);
   if (T->isFunctionType())
-    adjustMemberFunctionCC(T, /*IsStatic=*/false);
+    adjustMemberFunctionCC(T, /*IsStatic=*/false, IsCtorOrDtor, Loc);
 
   return Context.getMemberPointerType(T, Class.getTypePtr());
 }
@@ -5842,25 +5845,41 @@ bool Sema::hasExplicitCallingConv(QualType &T) {
   return false;
 }
 
-void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
+void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
+                                  SourceLocation Loc) {
   FunctionTypeUnwrapper Unwrapped(*this, T);
   const FunctionType *FT = Unwrapped.get();
   bool IsVariadic = (isa<FunctionProtoType>(FT) &&
                      cast<FunctionProtoType>(FT)->isVariadic());
-
-  // Only adjust types with the default convention.  For example, on Windows we
-  // should adjust a __cdecl type to __thiscall for instance methods, and a
-  // __thiscall type to __cdecl for static methods.
   CallingConv CurCC = FT->getCallConv();
-  CallingConv FromCC =
-      Context.getDefaultCallingConvention(IsVariadic, IsStatic);
   CallingConv ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
-  if (CurCC != FromCC || FromCC == ToCC)
-    return;
 
-  if (hasExplicitCallingConv(T))
+  if (CurCC == ToCC)
     return;
 
+  // MS compiler ignores explicit calling convention attributes on structors. We
+  // should do the same.
+  if (Context.getTargetInfo().getCXXABI().isMicrosoft() && IsCtorOrDtor) {
+    // Issue a warning on ignored calling convention -- except of __stdcall.
+    // Again, this is what MS compiler does.
+    if (CurCC != CC_X86StdCall)
+      Diag(Loc, diag::warn_cconv_structors)
+          << FunctionType::getNameForCallConv(CurCC);
+  // Default adjustment.
+  } else {
+    // Only adjust types with the default convention.  For example, on Windows
+    // we should adjust a __cdecl type to __thiscall for instance methods, and a
+    // __thiscall type to __cdecl for static methods.
+    CallingConv DefaultCC =
+        Context.getDefaultCallingConvention(IsVariadic, IsStatic);
+
+    if (CurCC != DefaultCC || DefaultCC == ToCC)
+      return;
+
+    if (hasExplicitCallingConv(T))
+      return;
+  }
+
   FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(ToCC));
   QualType Wrapped = Unwrapped.wrap(*this, FT);
   T = Context.getAdjustedType(T, Wrapped);
index 0e44efa8d0adec7f8f238071e34233ee862c04e9..3fb97b9a363228bbf79f1dd9f39a4212187bc3f0 100644 (file)
@@ -5,6 +5,7 @@
 // RUN: FileCheck --check-prefix DTORS %s < %t
 // RUN: FileCheck --check-prefix DTORS2 %s < %t
 // RUN: FileCheck --check-prefix DTORS3 %s < %t
+// RUN: FileCheck --check-prefix DTORS4 %s < %t
 //
 // RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s
 
@@ -407,9 +408,7 @@ B::B(short *a) {}
 // CHECK:               (%"struct.test1::B"* returned %this, i32* %a, i32 %is_most_derived)
 // CHECK: define %"struct.test1::B"* @"\01??0B@test1@@QAA@PBDZZ"
 // CHECK:               (%"struct.test1::B"* returned %this, i32 %is_most_derived, i8* %a, ...)
-
-// FIXME: This should be x86_thiscallcc.  MSVC ignores explicit CCs on structors.
-// CHECK: define %"struct.test1::B"* @"\01??0B@test1@@QAA@PAF@Z"
+// CHECK: define x86_thiscallcc %"struct.test1::B"* @"\01??0B@test1@@QAE@PAF@Z"
 // CHECK:               (%"struct.test1::B"* returned %this, i16* %a, i32 %is_most_derived)
 
 void construct_b() {
@@ -458,3 +457,18 @@ void *getA() {
 // CHECK:               (%"struct.(anonymous namespace)::A"* %this, i32 %should_call_delete)
 // CHECK: define internal x86_thiscallcc void @"\01??1A@?A@@UAE@XZ"
 // CHECK:               (%"struct.(anonymous namespace)::A"* %this)
+
+// Check that we correctly transform __stdcall to __thiscall for ctors and
+// dtors.
+class G {
+ public:
+  __stdcall G() {};
+// DTORS4: define linkonce_odr x86_thiscallcc %class.G* @"\01??0G@@QAE@XZ"
+  __stdcall ~G() {};
+// DTORS4: define linkonce_odr x86_thiscallcc void @"\01??1G@@QAE@XZ"
+};
+
+extern void testG() {
+  G g;
+}
+
index 6c392ea9420df32a30b057c2a4d0e6b929e6b492..acd9b0720b6202bb89cba6b8231b892d3bae1dbe 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++14 -triple i686-pc-win32 -fms-extensions -verify %s
+// RUN: %clang_cc1 -std=c++14 -triple i686-pc-win32 -fms-extensions -DMSABI -verify %s
 // RUN: %clang_cc1 -std=c++14 -triple i686-pc-mingw32 -verify %s
 // RUN: %clang_cc1 -std=c++14 -triple i686-pc-mingw32 -fms-extensions -verify %s
 
@@ -74,6 +74,11 @@ struct S {
 
   static void            static_member_variadic_default(int x, ...);
   static void __cdecl    static_member_variadic_cdecl(int x, ...);
+
+  // Structors can't be other than default in MS ABI environment
+#ifdef MSABI
+  __vectorcall S(); // expected-warning {{vectorcall calling convention ignored on constructor/destructor}}
+#endif
 };
 
 void __cdecl    S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}