r192150 - [ms-cxxabi] Fix the calling convention for operator new in records

Reid Kleckner reid at kleckner.net
Mon Oct 7 17:58:57 PDT 2013


Author: rnk
Date: Mon Oct  7 19:58:57 2013
New Revision: 192150

URL: http://llvm.org/viewvc/llvm-project?rev=192150&view=rev
Log:
[ms-cxxabi] Fix the calling convention for operator new in records

Summary:
Operator new, new[], delete, and delete[] are all implicitly static when
declared inside a record.  CXXMethodDecl already knows this, but we need
to account for that before we pick the calling convention for the
function type.

Fixes PR17371.

Reviewers: rsmith

CC: cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D1761

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/OperatorKinds.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CodeGenCXX/mangle-ms.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Oct  7 19:58:57 2013
@@ -1677,6 +1677,18 @@ public:
   bool isStatic() const;
   bool isInstance() const { return !isStatic(); }
 
+  /// Returns true if the given operator is implicitly static in a record
+  /// context.
+  static bool isStaticOverloadedOperator(OverloadedOperatorKind OOK) {
+    // [class.free]p1:
+    // Any allocation function for a class T is a static member
+    // (even if not explicitly declared static).
+    // [class.free]p6 Any deallocation function for a class X is a static member
+    // (even if not explicitly declared static).
+    return OOK == OO_New || OOK == OO_Array_New || OOK == OO_Delete ||
+           OOK == OO_Array_Delete;
+  }
+
   bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
   bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); }
 

Modified: cfe/trunk/include/clang/Basic/OperatorKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorKinds.h?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/OperatorKinds.h (original)
+++ cfe/trunk/include/clang/Basic/OperatorKinds.h Mon Oct  7 19:58:57 2013
@@ -30,7 +30,7 @@ enum OverloadedOperatorKind {
 /// \brief Retrieve the spelling of the given overloaded operator, without 
 /// the preceding "operator" keyword.
 const char *getOperatorSpelling(OverloadedOperatorKind Operator);
-  
+
 } // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Oct  7 19:58:57 2013
@@ -2078,6 +2078,16 @@ public:
     return (FunctionDefinitionKind)FunctionDefinition; 
   }
 
+  /// Returns true if this declares a real member and not a friend.
+  bool isFirstDeclarationOfMember() {
+    return getContext() == MemberContext && !getDeclSpec().isFriendSpecified();
+  }
+
+  /// Returns true if this declares a static member.  This cannot be called on a
+  /// declarator outside of a MemberContext because we won't know until
+  /// redeclaration time if the decl is static.
+  bool isStaticMember();
+
   void setRedeclaration(bool Val) { Redeclaration = Val; }
   bool isRedeclaration() const { return Redeclaration; }
 };

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct  7 19:58:57 2013
@@ -2553,7 +2553,7 @@ 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);
+  void adjustMemberFunctionCC(QualType &T, bool IsStatic);
 
   /// Get the outermost AttributedType node that sets a calling convention.
   /// Valid types should not have multiple attributes with different CCs.

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Oct  7 19:58:57 2013
@@ -1327,21 +1327,8 @@ bool CXXMethodDecl::isStatic() const {
   if (MD->getStorageClass() == SC_Static)
     return true;
 
-  DeclarationName Name = getDeclName();
-  // [class.free]p1:
-  // Any allocation function for a class T is a static member
-  // (even if not explicitly declared static).
-  if (Name.getCXXOverloadedOperator() == OO_New ||
-      Name.getCXXOverloadedOperator() == OO_Array_New)
-    return true;
-
-  // [class.free]p6 Any deallocation function for a class X is a static member
-  // (even if not explicitly declared static).
-  if (Name.getCXXOverloadedOperator() == OO_Delete ||
-      Name.getCXXOverloadedOperator() == OO_Array_Delete)
-    return true;
-
-  return false;
+  OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator();
+  return isStaticOverloadedOperator(OOK);
 }
 
 static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Mon Oct  7 19:58:57 2013
@@ -316,9 +316,7 @@ void MicrosoftCXXNameMangler::mangleFunc
 
   // We should never ever see a FunctionNoProtoType at this point.
   // We don't even know how to mangle their types anyway :).
-  TypeSourceInfo *TSI = FD->getTypeSourceInfo();
-  QualType T = TSI ? TSI->getType() : FD->getType();
-  const FunctionProtoType *FT = T->castAs<FunctionProtoType>();
+  const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
 
   // extern "C" functions can hold entities that must be mangled.
   // As it stands, these functions still need to get expressed in the full

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Oct  7 19:58:57 2013
@@ -13,6 +13,7 @@
 
 #include "clang/Sema/DeclSpec.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/TypeLoc.h"
@@ -325,6 +326,13 @@ bool Declarator::isDeclarationOfFunction
   llvm_unreachable("Invalid TypeSpecType!");
 }
 
+bool Declarator::isStaticMember() {
+  assert(getContext() == MemberContext);
+  return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+         CXXMethodDecl::isStaticOverloadedOperator(
+             getName().OperatorFunctionId.Operator);
+}
+
 /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
 /// declaration specifier includes.
 ///

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Oct  7 19:58:57 2013
@@ -6494,10 +6494,8 @@ Sema::ActOnFunctionDeclarator(Scope *S,
          diag::err_invalid_thread)
       << DeclSpec::getSpecifierName(TSCS);
 
-  if (DC->isRecord() &&
-      D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
-      !D.getDeclSpec().isFriendSpecified())
-    adjustMemberFunctionCC(R);
+  if (D.isFirstDeclarationOfMember())
+    adjustMemberFunctionCC(R, D.isStaticMember());
 
   bool isFriend = false;
   FunctionTemplateDecl *FunctionTemplate = 0;

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Oct  7 19:58:57 2013
@@ -2494,12 +2494,11 @@ getCCForDeclaratorChunk(Sema &S, Declara
       assert(D.isFunctionDeclarator());
 
       // If we're inside a record, we're declaring a method, but it could be
-      // static.
+      // explicitly or implicitly static.
       IsCXXInstanceMethod =
-          (D.getContext() == Declarator::MemberContext &&
-           D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
-           D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
-           !D.getDeclSpec().isFriendSpecified());
+          D.isFirstDeclarationOfMember() &&
+          D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+          !D.isStaticMember();
     }
   }
 
@@ -4580,13 +4579,17 @@ static bool handleFunctionTypeAttr(TypeP
   return true;
 }
 
-void Sema::adjustMemberFunctionCC(QualType &T) {
+void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
   const FunctionType *FT = T->castAs<FunctionType>();
   bool IsVariadic = (isa<FunctionProtoType>(FT) &&
                      cast<FunctionProtoType>(FT)->isVariadic());
   CallingConv CC = FT->getCallConv();
+
+  // 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, /*IsCXXMethod=*/false);
+      Context.getDefaultCallingConvention(IsVariadic, IsStatic);
   if (CC != DefaultCC)
     return;
 
@@ -4602,7 +4605,7 @@ void Sema::adjustMemberFunctionCC(QualTy
 
   // FIXME: This loses sugar.  This should probably be fixed with an implicit
   // AttributedType node that adjusts the convention.
-  CC = Context.getDefaultCallingConvention(IsVariadic, /*IsCXXMethod=*/true);
+  CC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
   FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC));
   FunctionTypeUnwrapper Unwrapped(*this, T);
   T = Unwrapped.wrap(*this, FT);

Modified: cfe/trunk/test/CodeGenCXX/mangle-ms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-ms.cpp?rev=192150&r1=192149&r2=192150&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-ms.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-ms.cpp Mon Oct  7 19:58:57 2013
@@ -304,3 +304,55 @@ inline int templated_inline_function_wit
 int call_templated_inline_function_with_local_type() {
   return templated_inline_function_with_local_type<int>();
 }
+
+// PR17371
+struct OverloadedNewDelete {
+  // __cdecl
+  void *operator new(__SIZE_TYPE__);
+  void *operator new[](__SIZE_TYPE__);
+  void operator delete(void *);
+  void operator delete[](void *);
+  // __thiscall
+  int operator+(int);
+};
+
+void *OverloadedNewDelete::operator new(__SIZE_TYPE__ s) { return 0; }
+void *OverloadedNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; }
+void OverloadedNewDelete::operator delete(void *) { }
+void OverloadedNewDelete::operator delete[](void *) { }
+int OverloadedNewDelete::operator+(int x) { return x; };
+
+// CHECK-DAG: ??2OverloadedNewDelete@@SAPAXI at Z
+// CHECK-DAG: ??_UOverloadedNewDelete@@SAPAXI at Z
+// CHECK-DAG: ??3OverloadedNewDelete@@SAXPAX at Z
+// CHECK-DAG: ??_VOverloadedNewDelete@@SAXPAX at Z
+// CHECK-DAG: ??HOverloadedNewDelete@@QAEHH at Z
+
+// X64-DAG:   ??2OverloadedNewDelete@@SAPEAX_K at Z
+// X64-DAG:   ??_UOverloadedNewDelete@@SAPEAX_K at Z
+// X64-DAG:   ??3OverloadedNewDelete@@SAXPEAX at Z
+// X64-DAG:   ??_VOverloadedNewDelete@@SAXPEAX at Z
+// X64-DAG:   ??HOverloadedNewDelete@@QEAAHH at Z
+
+// Indirecting the function type through a typedef will require a calling
+// convention adjustment before building the method decl.
+
+typedef void *__thiscall OperatorNewType(__SIZE_TYPE__);
+typedef void __thiscall OperatorDeleteType(void *);
+
+struct TypedefNewDelete {
+  OperatorNewType operator new;
+  OperatorNewType operator new[];
+  OperatorDeleteType operator delete;
+  OperatorDeleteType operator delete[];
+};
+
+void *TypedefNewDelete::operator new(__SIZE_TYPE__ s) { return 0; }
+void *TypedefNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; }
+void TypedefNewDelete::operator delete(void *) { }
+void TypedefNewDelete::operator delete[](void *) { }
+
+// CHECK-DAG: ??2TypedefNewDelete@@SAPAXI at Z
+// CHECK-DAG: ??_UTypedefNewDelete@@SAPAXI at Z
+// CHECK-DAG: ??3TypedefNewDelete@@SAXPAX at Z
+// CHECK-DAG: ??_VTypedefNewDelete@@SAXPAX at Z





More information about the cfe-commits mailing list