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@Z +// CHECK-DAG: ??_UOverloadedNewDelete@@SAPAXI@Z +// CHECK-DAG: ??3OverloadedNewDelete@@SAXPAX@Z +// CHECK-DAG: ??_VOverloadedNewDelete@@SAXPAX@Z +// CHECK-DAG: ??HOverloadedNewDelete@@QAEHH@Z + +// X64-DAG: ??2OverloadedNewDelete@@SAPEAX_K@Z +// X64-DAG: ??_UOverloadedNewDelete@@SAPEAX_K@Z +// X64-DAG: ??3OverloadedNewDelete@@SAXPEAX@Z +// X64-DAG: ??_VOverloadedNewDelete@@SAXPEAX@Z +// X64-DAG: ??HOverloadedNewDelete@@QEAAHH@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@Z +// CHECK-DAG: ??_UTypedefNewDelete@@SAPAXI@Z +// CHECK-DAG: ??3TypedefNewDelete@@SAXPAX@Z +// CHECK-DAG: ??_VTypedefNewDelete@@SAXPAX@Z _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
