From 78af0708b7d3b1d7a3189c39541c91cf9cb6d3f7 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 27 Aug 2013 23:08:25 +0000 Subject: [PATCH] Delete CC_Default and use the target default CC everywhere Summary: Makes functions with implicit calling convention compatible with function types with a matching explicit calling convention. This fixes things like calls to qsort(), which has an explicit __cdecl attribute on the comparator in Windows headers. Clang will now infer the calling convention from the declarator. There are two cases when the CC must be adjusted during redeclaration: 1. When defining a non-inline static method. 2. When redeclaring a function with an implicit or mismatched convention. Fixes PR13457, and allows clang to compile CommandLine.cpp for the Microsoft C++ ABI. Excellent test cases provided by Alexander Zinenko! Reviewers: rsmith Differential Revision: http://llvm-reviews.chandlerc.com/D1231 llvm-svn: 189412 --- clang/include/clang/AST/ASTContext.h | 16 +- clang/include/clang/AST/Type.h | 16 +- clang/include/clang/Basic/Specifiers.h | 1 - clang/include/clang/Basic/TargetInfo.h | 1 - clang/include/clang/Sema/Sema.h | 9 + clang/lib/AST/ASTContext.cpp | 38 +- clang/lib/AST/DumpXML.cpp | 1 - clang/lib/AST/ExprCXX.cpp | 6 +- clang/lib/AST/MicrosoftMangle.cpp | 11 - clang/lib/AST/Type.cpp | 7 +- clang/lib/AST/TypePrinter.cpp | 17 +- clang/lib/Basic/Targets.cpp | 4 +- clang/lib/CodeGen/CGCall.cpp | 15 - clang/lib/CodeGen/TargetInfo.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 94 ++--- clang/lib/Sema/SemaDeclCXX.cpp | 73 ++-- clang/lib/Sema/SemaLambda.cpp | 21 +- clang/lib/Sema/SemaLookup.cpp | 2 +- clang/lib/Sema/SemaType.cpp | 111 ++++- clang/test/CodeGen/mrtd.c | 11 +- clang/test/Sema/callingconv.c | 4 + clang/test/Sema/mrtd.c | 40 ++ clang/test/SemaCXX/calling-conv-compat.cpp | 387 ++++++++++++++++++ .../test/SemaCXX/decl-microsoft-call-conv.cpp | 90 ++-- clang/test/SemaCXX/virtual-override-x86.cpp | 4 +- clang/tools/libclang/CXType.cpp | 1 - 26 files changed, 755 insertions(+), 227 deletions(-) create mode 100644 clang/test/Sema/mrtd.c create mode 100644 clang/test/SemaCXX/calling-conv-compat.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0e0a62be9720..06264efa0682 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1769,19 +1769,9 @@ public: NestedNameSpecifier * getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; - /// \brief Retrieves the default calling convention to use for - /// C++ instance methods. - CallingConv getDefaultCXXMethodCallConv(bool isVariadic); - - /// \brief Retrieves the canonical representation of the given - /// calling convention. - CallingConv getCanonicalCallConv(CallingConv CC) const; - - /// \brief Determines whether two calling conventions name the same - /// calling convention. - bool isSameCallConv(CallingConv lcc, CallingConv rcc) { - return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc)); - } + /// \brief Retrieves the default calling convention for the current target. + CallingConv getDefaultCallingConvention(bool isVariadic, + bool IsCXXMethod) const; /// \brief Retrieves the "canonical" template name that refers to a /// given template. diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 6e2246ba3703..436fceeb80c2 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1812,6 +1812,10 @@ template <> const TypedefType *Type::getAs() const; /// non-sugared type. template <> const TemplateSpecializationType *Type::getAs() const; +/// \brief This will check for an AttributedType by removing any existing sugar +/// until it reaches an AttributedType or a non-sugared type. +template <> const AttributedType *Type::getAs() const; + // We can do canonical leaf types faster, because we don't have to // worry about preserving child type decoration. #define TYPE(Class, Base) @@ -2683,7 +2687,11 @@ class FunctionType : public Type { // Constructor with all defaults. Use when for example creating a // function know to use defaults. - ExtInfo() : Bits(0) {} + ExtInfo() : Bits(CC_C) { } + + // Constructor with just the calling convention, which is an important part + // of the canonical type. + ExtInfo(CallingConv CC) : Bits(CC) { } bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } @@ -2826,6 +2834,12 @@ public: ExceptionSpecDecl(0), ExceptionSpecTemplate(0), ConsumedArguments(0) {} + ExtProtoInfo(CallingConv CC) + : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0), + ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0), + Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0), + ExceptionSpecTemplate(0), ConsumedArguments(0) {} + FunctionType::ExtInfo ExtInfo; bool Variadic : 1; bool HasTrailingReturn : 1; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 7fe242ece874..d9d5799e0409 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -200,7 +200,6 @@ namespace clang { /// \brief CallingConv - Specifies the calling convention that a function uses. enum CallingConv { - CC_Default, CC_C, // __attribute__((cdecl)) CC_X86StdCall, // __attribute__((stdcall)) CC_X86FastCall, // __attribute__((fastcall)) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ec7cdec7ad43..1073711ce4a4 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -779,7 +779,6 @@ public: default: return CCCR_Warning; case CC_C: - case CC_Default: return CCCR_OK; } } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 749c64d95880..6722e535f083 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2539,6 +2539,15 @@ public: bool CheckNoReturnAttr(const AttributeList &attr); void CheckAlignasUnderalignment(Decl *D); + /// 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); + + /// Get the outermost AttributedType node that sets a calling convention. + /// Valid types should not have multiple attributes with different CCs. + const AttributedType *getCallingConvAttributedType(QualType T) const; + /// \brief Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, SourceRange Range); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 29ddb37525dc..94d9e918e75d 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2732,9 +2732,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { - const CallingConv DefaultCC = Info.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; + const CallingConv CallConv = Info.getCC(); + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -2746,11 +2745,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical() || - getCanonicalCallConv(CallConv) != CallConv) { - Canonical = - getFunctionNoProtoType(getCanonicalType(ResultTy), - Info.withCallingConv(getCanonicalCallConv(CallConv))); + if (!ResultTy.isCanonical()) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -2799,14 +2795,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; - const CallingConv DefaultCC = EPI.ExtInfo.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; - // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { + if (!isCanonical) { SmallVector CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2816,8 +2808,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, CanonicalEPI.HasTrailingReturn = false; CanonicalEPI.ExceptionSpecType = EST_None; CanonicalEPI.NumExceptions = 0; - CanonicalEPI.ExtInfo - = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); // Result types do not have ARC lifetime qualifiers. QualType CanResultTy = getCanonicalType(ResultTy); @@ -2859,7 +2849,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; - newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); @@ -6939,7 +6928,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); // Compatible functions must have compatible calling conventions - if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC())) + if (lbaseInfo.getCC() != rbaseInfo.getCC()) return QualType(); // Regparm is part of the calling convention. @@ -7784,7 +7773,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - FunctionType::ExtInfo EI; + FunctionType::ExtInfo EI(CC_C); if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); bool Variadic = (TypeStr[0] == '.'); @@ -7955,16 +7944,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; } -CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) { +CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, + bool IsCXXMethod) const { // Pass through to the C++ ABI object - return ABI->getDefaultMethodCallConv(isVariadic); -} + if (IsCXXMethod) + return ABI->getDefaultMethodCallConv(IsVariadic); -CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const { - if (CC == CC_C && !LangOpts.MRTD && - getTargetInfo().getCXXABI().isMemberFunctionCCDefault()) - return CC_Default; - return CC; + return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C; } bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { diff --git a/clang/lib/AST/DumpXML.cpp b/clang/lib/AST/DumpXML.cpp index be22ae450b62..9516a4be99a5 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/lib/AST/DumpXML.cpp @@ -915,7 +915,6 @@ struct XMLDumper : public XMLDeclVisitor, void setCallingConv(CallingConv CC) { switch (CC) { - case CC_Default: return; case CC_C: return set("cc", "cdecl"); case CC_X86FastCall: return set("cc", "x86_fastcall"); case CC_X86StdCall: return set("cc", "x86_stdcall"); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index b76bc2f28497..36aa2892f2af 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -196,8 +196,10 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, None, - FunctionProtoType::ExtProtoInfo())), + Context.getPointerType(Context.getFunctionType( + Context.VoidTy, None, + FunctionProtoType::ExtProtoInfo( + Context.getDefaultCallingConvention(false, true)))), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || (DestroyedType.getTypeSourceInfo() && diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 87527c9294aa..97edce105cd4 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1391,20 +1391,9 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, // that they could be in a DLL and somebody from another module could call // them.) CallingConv CC = T->getCallConv(); - if (CC == CC_Default) { - if (IsInstMethod) { - const FunctionProtoType *FPT = - T->getCanonicalTypeUnqualified().castAs(); - bool isVariadic = FPT->isVariadic(); - CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); - } else { - CC = CC_C; - } - } switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); - case CC_Default: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; case CC_X86ThisCall: Out << 'E'; break; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index ef423eba879e..1bd2d3b98da9 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -338,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const { return getAsSugar(this); } +template <> const AttributedType *Type::getAs() const { + return getAsSugar(this); +} + /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. @@ -1559,9 +1563,6 @@ QualType QualType::getNonLValueExprType(const ASTContext &Context) const { StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { - case CC_Default: - llvm_unreachable("no name for default cc"); - case CC_C: return "cdecl"; case CC_X86StdCall: return "stdcall"; case CC_X86FastCall: return "fastcall"; diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index f6fd886e8a46..2a4cf52027d4 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -634,9 +634,14 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (!InsideCCAttribute) { switch (Info.getCC()) { - case CC_Default: break; case CC_C: - OS << " __attribute__((cdecl))"; + // The C calling convention is the default on the vast majority of platforms + // we support. If the user wrote it explicitly, it will usually be printed + // while traversing the AttributedType. If the type has been desugared, let + // the canonical spelling be the implicit calling convention. + // FIXME: It would be better to be explicit in certain contexts, such as a + // cdecl function typedef used to declare a member function with the + // Microsoft C++ ABI. break; case CC_X86StdCall: OS << " __attribute__((stdcall))"; @@ -1152,6 +1157,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, } case AttributedType::attr_regparm: { + // FIXME: When Sema learns to form this AttributedType, avoid printing the + // attribute again in printFunctionProtoAfter. OS << "regparm("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) @@ -1191,13 +1198,17 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; + // FIXME: When Sema learns to form this AttributedType, avoid printing the + // attribute again in printFunctionProtoAfter. case AttributedType::attr_noreturn: OS << "noreturn"; break; + case AttributedType::attr_cdecl: OS << "cdecl"; break; case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; case AttributedType::attr_thiscall: OS << "thiscall"; break; case AttributedType::attr_pascal: OS << "pascal"; break; - case AttributedType::attr_pcs: { + case AttributedType::attr_pcs: + case AttributedType::attr_pcs_vfp: { OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 84f8a347bda9..f4c4226482d5 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -3094,9 +3094,7 @@ public: } virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { - return (CC == CC_Default || - CC == CC_C || - CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning; + return (CC == CC_C || CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning; } virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const { diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 971a2ade1262..ed02c74cdfca 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -103,24 +103,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT, return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo()); } -/// Given the formal ext-info of a C++ instance method, adjust it -/// according to the C++ ABI in effect. -static void adjustCXXMethodInfo(CodeGenTypes &CGT, - FunctionType::ExtInfo &extInfo, - bool isVariadic) { - if (extInfo.getCC() == CC_Default) { - CallingConv CC = CGT.getContext().getDefaultCXXMethodCallConv(isVariadic); - extInfo = extInfo.withCallingConv(CC); - } -} - /// Arrange the argument and result information for a free function (i.e. /// not a C++ or ObjC instance method) of the given type. static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT, SmallVectorImpl &prefix, CanQual FTP) { FunctionType::ExtInfo extInfo = FTP->getExtInfo(); - adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic()); return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo); } @@ -223,7 +211,6 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D, argTypes.push_back(FTP->getArgType(i)); FunctionType::ExtInfo extInfo = FTP->getExtInfo(); - adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic()); return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required); } @@ -247,7 +234,6 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D, assert(FTP->isVariadic() == 0 && "dtor with formal parameters"); FunctionType::ExtInfo extInfo = FTP->getExtInfo(); - adjustCXXMethodInfo(*this, extInfo, false); return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, RequiredArgs::All); } @@ -406,7 +392,6 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args, argTypes.push_back(Context.getCanonicalParamType(i->Ty)); FunctionType::ExtInfo info = FPT->getExtInfo(); - adjustCXXMethodInfo(*this, info, FPT->isVariadic()); return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()), argTypes, info, required); } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 70fc8fed5d47..b56684ba5c8a 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -1262,7 +1262,7 @@ public: // that when AVX types are involved: the ABI explicitly states it is // undefined, and it doesn't work in practice because of how the ABI // defines varargs anyway. - if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) { + if (fnType->getCallConv() == CC_C) { bool HasAVXType = false; for (CallArgList::const_iterator it = args.begin(), ie = args.end(); it != ie; ++it) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d831c706190c..748814d93448 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2201,17 +2201,11 @@ static bool canRedefineFunction(const FunctionDecl *FD, FD->getStorageClass() == SC_Extern); } -/// Is the given calling convention the ABI default for the given -/// declaration? -static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) { - CallingConv ABIDefaultCC; - if (isa(D) && cast(D)->isInstance()) { - ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic()); - } else { - // Free C function or a static method. - ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C); - } - return ABIDefaultCC == CC; +const AttributedType *Sema::getCallingConvAttributedType(QualType T) const { + const AttributedType *AT = T->getAs(); + while (AT && !AT->isCallingConv()) + AT = AT->getModifiedType()->getAs(); + return AT; } template @@ -2287,9 +2281,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S, else PrevDiag = diag::note_previous_declaration; - QualType OldQType = Context.getCanonicalType(Old->getType()); - QualType NewQType = Context.getCanonicalType(New->getType()); - // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. // Don't complain about specializations. They are not supposed to have @@ -2309,53 +2300,52 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S, } } - // If a function is first declared with a calling convention, but is - // later declared or defined without one, the second decl assumes the - // calling convention of the first. + + // If a function is first declared with a calling convention, but is later + // declared or defined without one, all following decls assume the calling + // convention of the first. // // It's OK if a function is first declared without a calling convention, // but is later declared or defined with the default calling convention. // - // For the new decl, we have to look at the NON-canonical type to tell the - // difference between a function that really doesn't have a calling - // convention and one that is declared cdecl. That's because in - // canonicalization (see ASTContext.cpp), cdecl is canonicalized away - // because it is the default calling convention. + // To test if either decl has an explicit calling convention, we look for + // AttributedType sugar nodes on the type as written. If they are missing or + // were canonicalized away, we assume the calling convention was implicit. // // Note also that we DO NOT return at this point, because we still have // other tests to run. + QualType OldQType = Context.getCanonicalType(Old->getType()); + QualType NewQType = Context.getCanonicalType(New->getType()); const FunctionType *OldType = cast(OldQType); - const FunctionType *NewType = New->getType()->getAs(); + const FunctionType *NewType = cast(NewQType); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; - if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) { - // Fast path: nothing to do. - // Inherit the CC from the previous declaration if it was specified - // there but not here. - } else if (NewTypeInfo.getCC() == CC_Default) { - NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); - RequiresAdjustment = true; + if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) { + FunctionDecl *First = Old->getFirstDeclaration(); + const FunctionType *FT = + First->getType().getCanonicalType()->castAs(); + FunctionType::ExtInfo FI = FT->getExtInfo(); + bool NewCCExplicit = getCallingConvAttributedType(New->getType()); + if (!NewCCExplicit) { + // Inherit the CC from the previous declaration if it was specified + // there but not here. + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; + } else { + // Calling conventions aren't compatible, so complain. + bool FirstCCExplicit = getCallingConvAttributedType(First->getType()); + Diag(New->getLocation(), diag::err_cconv_change) + << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) + << !FirstCCExplicit + << (!FirstCCExplicit ? "" : + FunctionType::getNameForCallConv(FI.getCC())); - // Don't complain about mismatches when the default CC is - // effectively the same as the explict one. Only Old decl contains correct - // information about storage class of CXXMethod. - } else if (OldTypeInfo.getCC() == CC_Default && - isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) { - NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); - RequiresAdjustment = true; - - } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), - NewTypeInfo.getCC())) { - // Calling conventions really aren't compatible, so complain. - Diag(New->getLocation(), diag::err_cconv_change) - << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) - << (OldTypeInfo.getCC() == CC_Default) - << (OldTypeInfo.getCC() == CC_Default ? "" : - FunctionType::getNameForCallConv(OldTypeInfo.getCC())); - Diag(Old->getLocation(), diag::note_previous_declaration); - return true; + // Put the note on the first decl, since it is the one that matters. + Diag(First->getLocation(), diag::note_previous_declaration); + return true; + } } // FIXME: diagnose the other way around? @@ -6463,6 +6453,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); + if (DC->isRecord() && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && + !D.getDeclSpec().isFriendSpecified()) + adjustMemberFunctionCC(R); + bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; @@ -7144,7 +7139,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Turn this into a variadic function with no parameters. const FunctionType *FT = NewFD->getType()->getAs(); - FunctionProtoType::ExtProtoInfo EPI; + FunctionProtoType::ExtProtoInfo EPI( + Context.getDefaultCallingConvention(true, false)); EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f12f92321ae6..bfb96c7ff5e7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4435,6 +4435,21 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT, FPT->getArgTypes(), EPI)); } +static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, + CXXMethodDecl *MD) { + FunctionProtoType::ExtProtoInfo EPI; + + // Build an exception specification pointing back at this member. + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = MD; + + // Set the calling convention to the default for C++ instance methods. + EPI.ExtInfo = EPI.ExtInfo.withCallingConv( + S.Context.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCXXMethod=*/true)); + return EPI; +} + void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->castAs(); if (FPT->getExceptionSpecType() != EST_Unevaluated) @@ -4631,7 +4646,9 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) { // Compute the implicit exception specification. - FunctionProtoType::ExtProtoInfo EPI; + CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCXXMethod=*/true); + FunctionProtoType::ExtProtoInfo EPI(CC); computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); const FunctionProtoType *ImplicitType = cast( Context.getFunctionType(Context.VoidTy, None, EPI)); @@ -7891,9 +7908,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setImplicit(); // Build an exception specification pointing back at this constructor. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = DefaultCon; + FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon); DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // We don't need to use SpecialMemberIsTrivial here; triviality for default @@ -8355,9 +8370,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setImplicit(); // Build an exception specification pointing back at this destructor. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = Destructor; + FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor); Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); AddOverriddenMethods(ClassDecl, Destructor); @@ -8861,9 +8874,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setImplicit(); // Build an exception specification pointing back at this member. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = CopyAssignment; + FunctionProtoType::ExtProtoInfo EPI = + getImplicitMethodEPI(*this, CopyAssignment); CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI)); // Add the parameter to the operator. @@ -9375,9 +9387,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setImplicit(); // Build an exception specification pointing back at this member. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = MoveAssignment; + FunctionProtoType::ExtProtoInfo EPI = + getImplicitMethodEPI(*this, MoveAssignment); MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI)); // Add the parameter to the operator. @@ -9732,9 +9743,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setDefaulted(); // Build an exception specification pointing back at this member. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = CopyConstructor; + FunctionProtoType::ExtProtoInfo EPI = + getImplicitMethodEPI(*this, CopyConstructor); CopyConstructor->setType( Context.getFunctionType(Context.VoidTy, ArgType, EPI)); @@ -9922,9 +9932,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setDefaulted(); // Build an exception specification pointing back at this member. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = MoveConstructor; + FunctionProtoType::ExtProtoInfo EPI = + getImplicitMethodEPI(*this, MoveConstructor); MoveConstructor->setType( Context.getFunctionType(Context.VoidTy, ArgType, EPI)); @@ -11646,27 +11655,11 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, if (NewCC == OldCC) return false; - // If either of the calling conventions are set to "default", we need to pick - // something more sensible based on the target. This supports code where the - // one method explicitly sets thiscall, and another has no explicit calling - // convention. - CallingConv Default = - Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member); - if (NewCC == CC_Default) - NewCC = Default; - if (OldCC == CC_Default) - OldCC = Default; - - // If the calling conventions still don't match, then report the error - if (NewCC != OldCC) { - Diag(New->getLocation(), - diag::err_conflicting_overriding_cc_attributes) - << New->getDeclName() << New->getType() << Old->getType(); - Diag(Old->getLocation(), diag::note_overridden_virtual_function); - return true; - } - - return false; + Diag(New->getLocation(), + diag::err_conflicting_overriding_cc_attributes) + << New->getDeclName() << New->getType() << Old->getType(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; } bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index ae3a938333f8..242105f789cf 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -539,7 +539,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as // if the lambda-declarator were (). - FunctionProtoType::ExtProtoInfo EPI; + FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true)); EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; QualType MethodTy = Context.getFunctionType(Context.DependentTy, None, @@ -819,17 +820,20 @@ static void addFunctionPointerConversion(Sema &S, QualType FunctionTy; { FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo(); + CallingConv CC = S.Context.getDefaultCallingConvention( + Proto->isVariadic(), /*IsCXXMethod=*/false); + ExtInfo.ExtInfo = ExtInfo.ExtInfo.withCallingConv(CC); ExtInfo.TypeQuals = 0; FunctionTy = S.Context.getFunctionType(Proto->getResultType(), Proto->getArgTypes(), ExtInfo); FunctionPtrTy = S.Context.getPointerType(FunctionTy); } - - FunctionProtoType::ExtProtoInfo ExtInfo; + + FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true)); ExtInfo.TypeQuals = Qualifiers::Const; - QualType ConvTy = - S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo); - + QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo); + SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name = S.Context.DeclarationNames.getCXXConversionFunctionName( @@ -893,8 +897,9 @@ static void addBlockPointerConversion(Sema &S, Proto->getResultType(), Proto->getArgTypes(), ExtInfo); BlockPtrTy = S.Context.getBlockPointerType(FunctionTy); } - - FunctionProtoType::ExtProtoInfo ExtInfo; + + FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true)); ExtInfo.TypeQuals = Qualifiers::Const; QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a17a903a5f4e..c00ae69cbe87 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -728,7 +728,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // function to have, if it were to match the name given. // FIXME: Calling convention! FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); - EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default); + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); EPI.ExceptionSpecType = EST_None; EPI.NumExceptions = 0; QualType ExpectedType diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9664937954b9..52b099e197d7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1784,6 +1784,8 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, } } + // FIXME: Adjust member function pointer calling conventions. + return Context.getMemberPointerType(T, Class.getTypePtr()); } @@ -2420,6 +2422,53 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D, } } +/// Helper for figuring out the default CC for a function declarator type. If +/// this is the outermost chunk, then we can determine the CC from the +/// declarator context. If not, then this could be either a member function +/// type or normal function type. +static CallingConv +getCCForDeclaratorChunk(Sema &S, Declarator &D, + const DeclaratorChunk::FunctionTypeInfo &FTI, + unsigned ChunkIndex) { + assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function); + + bool IsCXXInstanceMethod = false; + + if (S.getLangOpts().CPlusPlus) { + // Look inwards through parentheses to see if this chunk will form a + // member pointer type or if we're the declarator. Any type attributes + // between here and there will override the CC we choose here. + unsigned I = ChunkIndex; + bool FoundNonParen = false; + while (I && !FoundNonParen) { + --I; + if (D.getTypeObject(I).Kind != DeclaratorChunk::Paren) + FoundNonParen = true; + } + + if (FoundNonParen) { + // If we're not the declarator, we're a regular function type unless we're + // in a member pointer. + IsCXXInstanceMethod = + D.getTypeObject(I).Kind == DeclaratorChunk::MemberPointer; + } else { + // We're the innermost decl chunk, so must be a function declarator. + assert(D.isFunctionDeclarator()); + + // If we're inside a record, we're declaring a method, but it could be + // static. + IsCXXInstanceMethod = + (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && + !D.getDeclSpec().isFriendSpecified()); + } + } + + return S.Context.getDefaultCallingConvention(FTI.isVariadic, + IsCXXInstanceMethod); +} + static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -2793,9 +2842,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.isAmbiguous) warnAboutAmbiguousFunction(S, D, DeclType, T); + FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex)); + if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) { // Simple void foo(), where the incoming T is the result type. - T = Context.getFunctionNoProtoType(T); + T = Context.getFunctionNoProtoType(T, EI); } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan @@ -2820,11 +2871,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); D.setInvalidType(true); // Recover by creating a K&R-style function type. - T = Context.getFunctionNoProtoType(T); + T = Context.getFunctionNoProtoType(T, EI); break; } FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = EI; EPI.Variadic = FTI.isVariadic; EPI.HasTrailingReturn = FTI.hasTrailingReturnType(); EPI.TypeQuals = FTI.TypeQuals; @@ -4414,20 +4466,19 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, const FunctionType *fn = unwrapped.get(); CallingConv CCOld = fn->getCallConv(); - if (S.Context.getCanonicalCallConv(CC) == - S.Context.getCanonicalCallConv(CCOld)) { - FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC); - type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); - return true; - } + AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr); - if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) { - // Should we diagnose reapplications of the same convention? - S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << FunctionType::getNameForCallConv(CCOld); - attr.setInvalid(); - return true; + if (CC != CCOld) { + // Error out on when there's already an attribute on the type + // and the CCs don't match. + const AttributedType *AT = S.getCallingConvAttributedType(type); + if (AT && AT->getAttrKind() != CCAttrKind) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld); + attr.setInvalid(); + return true; + } } // Diagnose the use of X86 fastcall on varargs or unprototyped functions. @@ -4463,10 +4514,38 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); QualType Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); - type = S.Context.getAttributedType(getCCTypeAttrKind(attr), type, Equivalent); + type = S.Context.getAttributedType(CCAttrKind, type, Equivalent); return true; } +void Sema::adjustMemberFunctionCC(QualType &T) { + const FunctionType *FT = T->castAs(); + bool IsVariadic = (isa(FT) && + cast(FT)->isVariadic()); + CallingConv CC = FT->getCallConv(); + CallingConv DefaultCC = + Context.getDefaultCallingConvention(IsVariadic, /*IsCXXMethod=*/false); + if (CC != DefaultCC) + return; + + // Check if there was an explicit attribute, but only look through parens. + // The intent is to look for an attribute on the current declarator, but not + // one that came from a typedef. + QualType R = T.IgnoreParens(); + while (const AttributedType *AT = dyn_cast(R)) { + if (AT->isCallingConv()) + return; + R = AT->getModifiedType().IgnoreParens(); + } + + // FIXME: This loses sugar. This should probably be fixed with an implicit + // AttributedType node that adjusts the convention. + CC = Context.getDefaultCallingConvention(IsVariadic, /*IsCXXMethod=*/true); + FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC)); + FunctionTypeUnwrapper Unwrapped(*this, T); + T = Unwrapped.wrap(*this, FT); +} + /// Handle OpenCL image access qualifiers: read_only, write_only, read_write static void HandleOpenCLImageAccessAttribute(QualType& CurType, const AttributeList &Attr, diff --git a/clang/test/CodeGen/mrtd.c b/clang/test/CodeGen/mrtd.c index a40a59ac0fcc..8fa7cf02cead 100644 --- a/clang/test/CodeGen/mrtd.c +++ b/clang/test/CodeGen/mrtd.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -mrtd -triple i386-unknown-freebsd9.0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s | FileCheck %s void baz(int arg); @@ -14,4 +14,13 @@ void foo(int arg) { // CHECK: declare x86_stdcallcc void @baz(i32) +void qux(int arg, ...) { } +// CHECK: define void @qux(i32 %arg, ...) + +void quux(int a1, int a2, int a3) { + qux(a1, a2, a3); +} +// CHECK-LABEL: define x86_stdcallcc void @quux +// CHECK: call void (i32, ...)* @qux + // CHECK: attributes [[NUW]] = { nounwind{{.*}} } diff --git a/clang/test/Sema/callingconv.c b/clang/test/Sema/callingconv.c index ea91675c1983..b9adf791b594 100644 --- a/clang/test/Sema/callingconv.c +++ b/clang/test/Sema/callingconv.c @@ -56,3 +56,7 @@ PROC __attribute__((cdecl)) ctest4(const char *x) {} void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}} void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {} + +typedef void typedef_fun_t(int); +typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}} +void __attribute__((stdcall)) typedef_fun(int x) { } // expected-error {{function declared 'stdcall' here was previously declared without calling convention}} diff --git a/clang/test/Sema/mrtd.c b/clang/test/Sema/mrtd.c new file mode 100644 index 000000000000..653413b01277 --- /dev/null +++ b/clang/test/Sema/mrtd.c @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -DMRTD -mrtd -triple i386-unknown-unknown -verify %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -verify %s + +#ifndef MRTD +// expected-note@+5 {{previous declaration is here}} +// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}} +// expected-note@+5 {{previous declaration is here}} +// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}} +#endif +void nonvariadic1(int a, int b, int c); +void __attribute__((stdcall)) nonvariadic1(int a, int b, int c); +void nonvariadic2(int a, int b, int c); +void __attribute__((stdcall)) nonvariadic2(int a, int b, int c) { } + +// expected-note@+2 {{previous declaration is here}} +// expected-error@+2 {{function declared 'stdcall' here was previously declared without calling convention}} +void variadic(int a, ...); +void __attribute__((stdcall)) variadic(int a, ...); + +#ifdef MRTD +// expected-note@+3 {{previous definition is here}} +// expected-error@+3 {{redefinition of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}} +#endif +extern void (*a)(int, int); +__attribute__((cdecl)) extern void (*a)(int, int); + +extern void (*b)(int, ...); +__attribute__((cdecl)) extern void (*b)(int, ...); + +#ifndef MRTD +// expected-note@+3 {{previous definition is here}} +// expected-error@+3 {{redefinition of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}} +#endif +extern void (*c)(int, int); +__attribute__((stdcall)) extern void (*c)(int, int); + +// expected-note@+2 {{previous definition is here}} +// expected-error@+2 {{redefinition of 'd' with a different type: 'void ((*))(int, ...) __attribute__((stdcall))' vs 'void (*)(int, ...)'}} +extern void (*d)(int, ...); +__attribute__((stdcall)) extern void (*d)(int, ...); diff --git a/clang/test/SemaCXX/calling-conv-compat.cpp b/clang/test/SemaCXX/calling-conv-compat.cpp new file mode 100644 index 000000000000..b6cc42973c80 --- /dev/null +++ b/clang/test/SemaCXX/calling-conv-compat.cpp @@ -0,0 +1,387 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fms-extensions -cxx-abi microsoft -verify -triple i686-pc-win32 %s + +// Pointers to free functions +void free_func_default(); +void __cdecl free_func_cdecl(); +void __stdcall free_func_stdcall(); +void __fastcall free_func_fastcall(); + +typedef void ( *fptr_default)(); +typedef void (__cdecl *fptr_cdecl)(); +typedef void (__stdcall *fptr_stdcall)(); +typedef void (__fastcall *fptr_fastcall)(); + +// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}} +// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}} +void cb_fptr_default(fptr_default ptr); +// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}} +// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}} +void cb_fptr_cdecl(fptr_cdecl ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}} +void cb_fptr_stdcall(fptr_stdcall ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}} +void cb_fptr_fastcall(fptr_fastcall ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}} +void cb_fptr_const_default(const fptr_default ptr); + +void call_free_func() { + cb_fptr_default(free_func_default); + cb_fptr_default(free_func_cdecl); + cb_fptr_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}} + cb_fptr_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}} + cb_fptr_default(&free_func_default); + cb_fptr_default(&free_func_cdecl); + cb_fptr_default(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}} + cb_fptr_default(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}} + + cb_fptr_cdecl(free_func_default); + cb_fptr_cdecl(free_func_cdecl); + cb_fptr_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}} + cb_fptr_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}} + cb_fptr_cdecl(&free_func_default); + cb_fptr_cdecl(&free_func_cdecl); + cb_fptr_cdecl(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}} + cb_fptr_cdecl(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}} + + cb_fptr_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}} + cb_fptr_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}} + cb_fptr_stdcall(free_func_stdcall); + cb_fptr_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}} + + cb_fptr_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}} + cb_fptr_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}} + cb_fptr_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}} + cb_fptr_fastcall(free_func_fastcall); + + cb_fptr_const_default(free_func_default); + cb_fptr_const_default(free_func_cdecl); + cb_fptr_const_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}} + cb_fptr_const_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}} + +} + +// Pointers to variadic functions +// variadic function can't declared stdcall or fastcall +void free_func_variadic_default(int, ...); +void __cdecl free_func_variadic_cdecl(int, ...); + +typedef void ( *fptr_variadic_default)(int, ...); +typedef void (__cdecl *fptr_variadic_cdecl)(int, ...); + +void cb_fptr_variadic_default(fptr_variadic_default ptr); +void cb_fptr_variadic_cdecl(fptr_variadic_cdecl ptr); + +void call_free_variadic_func() { + cb_fptr_variadic_default(free_func_variadic_default); + cb_fptr_variadic_default(free_func_variadic_cdecl); + cb_fptr_variadic_default(&free_func_variadic_default); + cb_fptr_variadic_default(&free_func_variadic_cdecl); + + cb_fptr_variadic_cdecl(free_func_variadic_default); + cb_fptr_variadic_cdecl(free_func_variadic_cdecl); + cb_fptr_variadic_cdecl(&free_func_variadic_default); + cb_fptr_variadic_cdecl(&free_func_variadic_cdecl); +} + +// References to functions +typedef void ( &fref_default)(); +typedef void (__cdecl &fref_cdecl)(); +typedef void (__stdcall &fref_stdcall)(); +typedef void (__fastcall &fref_fastcall)(); + +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}} +void cb_fref_default(fref_default ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}} +void cb_fref_cdecl(fref_cdecl ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}} +void cb_fref_stdcall(fref_stdcall ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}} +void cb_fref_fastcall(fref_fastcall ptr); + +void call_free_func_ref() { + cb_fref_default(free_func_default); + cb_fref_default(free_func_cdecl); + cb_fref_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_default'}} + cb_fref_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_default'}} + + cb_fref_cdecl(free_func_default); + cb_fref_cdecl(free_func_cdecl); + cb_fref_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}} + cb_fref_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}} + + cb_fref_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_stdcall'}} + cb_fref_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_stdcall'}} + cb_fref_stdcall(free_func_stdcall); + cb_fref_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_stdcall'}} + + cb_fref_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_fastcall'}} + cb_fref_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_fastcall'}} + cb_fref_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_fastcall'}} + cb_fref_fastcall(free_func_fastcall); +} + +// References to variadic functions +// variadic function can't declared stdcall or fastcall +typedef void ( &fref_variadic_default)(int, ...); +typedef void (__cdecl &fref_variadic_cdecl)(int, ...); + +void cb_fref_variadic_default(fptr_variadic_default ptr); +void cb_fref_variadic_cdecl(fptr_variadic_cdecl ptr); + +void call_free_variadic_func_ref() { + cb_fref_variadic_default(free_func_variadic_default); + cb_fref_variadic_default(free_func_variadic_cdecl); + + cb_fref_variadic_cdecl(free_func_variadic_default); + cb_fref_variadic_cdecl(free_func_variadic_cdecl); +} + +// Pointers to members +namespace NonVariadic { + +struct A { + void member_default(); + void __cdecl member_cdecl(); + void __thiscall member_thiscall(); +}; + +struct B : public A { +}; + +struct C { + void member_default(); + void __cdecl member_cdecl(); + void __thiscall member_thiscall(); +}; + +typedef void ( A::*memb_a_default)(); +typedef void (__cdecl A::*memb_a_cdecl)(); +typedef void (__thiscall A::*memb_a_thiscall)(); +typedef void ( B::*memb_b_default)(); +typedef void (__cdecl B::*memb_b_cdecl)(); +typedef void (__thiscall B::*memb_b_thiscall)(); +typedef void ( C::*memb_c_default)(); +typedef void (__cdecl C::*memb_c_cdecl)(); +typedef void (__thiscall C::*memb_c_thiscall)(); + +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_a_default(memb_a_default ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}} +void cb_memb_a_cdecl(memb_a_cdecl ptr); +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_a_thiscall(memb_a_thiscall ptr); +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_b_default(memb_b_default ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}} +void cb_memb_b_cdecl(memb_b_cdecl ptr); +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_b_thiscall(memb_b_thiscall ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_c_default(memb_c_default ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}} +void cb_memb_c_cdecl(memb_c_cdecl ptr); +// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}} +void cb_memb_c_thiscall(memb_c_thiscall ptr); + +void call_member() { + cb_memb_a_default(&A::member_default); + cb_memb_a_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_default'}} + cb_memb_a_default(&A::member_thiscall); + + cb_memb_a_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}} + cb_memb_a_cdecl(&A::member_cdecl); + cb_memb_a_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}} + + cb_memb_a_thiscall(&A::member_default); + cb_memb_a_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_thiscall'}} + cb_memb_a_thiscall(&A::member_thiscall); +} + +void call_member_inheritance() { + cb_memb_b_default(&A::member_default); + cb_memb_b_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_default'}} + cb_memb_b_default(&A::member_thiscall); + cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}} + cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}} + cb_memb_c_default(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_default'}} + + cb_memb_b_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}} + cb_memb_b_cdecl(&A::member_cdecl); + cb_memb_b_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}} + cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}} + cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}} + cb_memb_c_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}} + + cb_memb_b_thiscall(&A::member_default); + cb_memb_b_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_thiscall'}} + cb_memb_b_thiscall(&A::member_thiscall); + cb_memb_c_thiscall(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}} + cb_memb_c_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}} + cb_memb_c_thiscall(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}} +} +} // end namespace NonVariadic + +namespace Variadic { +struct A { + void member_default(int, ...); + void __cdecl member_cdecl(int, ...); + void __thiscall member_thiscall(int, ...); +}; + +struct B : public A { +}; + +struct C { + void member_default(int, ...); + void __cdecl member_cdecl(int, ...); +}; + +typedef void ( A::*memb_a_default)(int, ...); +typedef void (__cdecl A::*memb_a_cdecl)(int, ...); +typedef void ( B::*memb_b_default)(int, ...); +typedef void (__cdecl B::*memb_b_cdecl)(int, ...); +typedef void ( C::*memb_c_default)(int, ...); +typedef void (__cdecl C::*memb_c_cdecl)(int, ...); + +void cb_memb_a_default(memb_a_default ptr); +void cb_memb_a_cdecl(memb_a_cdecl ptr); +void cb_memb_b_default(memb_b_default ptr); +void cb_memb_b_cdecl(memb_b_cdecl ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}} +void cb_memb_c_default(memb_c_default ptr); +// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}} +// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}} +void cb_memb_c_cdecl(memb_c_cdecl ptr); + +void call_member() { + cb_memb_a_default(&A::member_default); + cb_memb_a_default(&A::member_cdecl); + + cb_memb_a_cdecl(&A::member_default); + cb_memb_a_cdecl(&A::member_cdecl); +} + +void call_member_inheritance() { + cb_memb_b_default(&A::member_default); + cb_memb_b_default(&A::member_cdecl); + cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}} + cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}} + + cb_memb_b_cdecl(&A::member_default); + cb_memb_b_cdecl(&A::member_cdecl); + cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}} + cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}} +} +} // end namespace Variadic + +namespace MultiChunkDecls { + +// Try to test declarators that have multiple DeclaratorChunks. +struct A { + void __thiscall member_thiscall(int); +}; + +void (A::*return_mptr(short))(int) { + return &A::member_thiscall; +} + +void (A::*(*return_fptr_mptr(char))(short))(int) { + return return_mptr; +} + +typedef void (A::*mptr_t)(int); +mptr_t __stdcall return_mptr_std(short) { + return &A::member_thiscall; +} + +void (A::*(*return_fptr_std_mptr(char))(short))(int) { + return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'mptr_t (short) __attribute__((stdcall))'}} +} + +void call_return() { + A o; + void (A::*(*fptr)(short))(int) = return_fptr_mptr('a'); + void (A::*mptr)(int) = fptr(1); + (o.*mptr)(2); +} + +} // end namespace MultiChunkDecls + +namespace MemberPointers { + +struct A { + void __thiscall method_thiscall(); + void __cdecl method_cdecl(); + void __stdcall method_stdcall(); + void __fastcall method_fastcall(); +}; + +void ( A::*mp1)() = &A::method_thiscall; +void (__cdecl A::*mp2)() = &A::method_cdecl; +void (__stdcall A::*mp3)() = &A::method_stdcall; +void (__fastcall A::*mp4)() = &A::method_fastcall; + +// Use a typedef to form the member pointer and verify that cdecl is adjusted. +typedef void ( fun_default)(); +typedef void (__cdecl fun_cdecl)(); +typedef void (__stdcall fun_stdcall)(); +typedef void (__fastcall fun_fastcall)(); + +// FIXME: Adjust cdecl to thiscall when forming a member pointer. +//fun_default A::*td1 = &A::method_thiscall; +fun_cdecl A::*td2 = &A::method_cdecl; +fun_stdcall A::*td3 = &A::method_stdcall; +fun_fastcall A::*td4 = &A::method_fastcall; + +// Round trip the function type through a template, and verify that only cdecl +// gets adjusted. +template struct X { + typedef Fn A::*p; +}; + +// FIXME: Adjust cdecl to thiscall when forming a member pointer. +//X::p tmpl1 = &A::method_thiscall; +//X::p tmpl2 = &A::method_thiscall; +X::p tmpl3 = &A::method_stdcall; +X::p tmpl4 = &A::method_fastcall; + +} // end namespace MemberPointers + +// Test that lambdas that capture nothing convert to cdecl function pointers. +namespace Lambdas { + +void pass_fptr_cdecl (void (__cdecl *fp)()); +void pass_fptr_stdcall (void (__stdcall *fp)()); // expected-note {{candidate function not viable}} +void pass_fptr_fastcall(void (__fastcall *fp)()); // expected-note {{candidate function not viable}} + +void conversion_to_fptr() { + pass_fptr_cdecl ([]() { } ); + pass_fptr_stdcall ([]() { } ); // expected-error {{no matching function for call}} + pass_fptr_fastcall([]() { } ); // expected-error {{no matching function for call}} +} + +} diff --git a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp index 9e85e62cf88e..7fcf515d6797 100644 --- a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp +++ b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -1,21 +1,24 @@ // RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -fms-extensions -verify %s +typedef void void_fun_t(); +typedef void __cdecl cdecl_fun_t(); + // Pointers to free functions -void free_func_default(); -void __cdecl free_func_cdecl(); -void __stdcall free_func_stdcall(); // expected-note {{previous declaration is here}} +void free_func_default(); // expected-note 2 {{previous declaration is here}} +void __cdecl free_func_cdecl(); // expected-note 2 {{previous declaration is here}} +void __stdcall free_func_stdcall(); // expected-note 2 {{previous declaration is here}} void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}} -void __cdecl free_func_default(); // expected-note 2 {{previous declaration is here}} +void __cdecl free_func_default(); void __stdcall free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}} void __fastcall free_func_default(); // expected-error {{function declared 'fastcall' here was previously declared without calling convention}} -void free_func_cdecl(); // expected-note 2 {{previous declaration is here}} +void free_func_cdecl(); void __stdcall free_func_cdecl(); // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}} void __fastcall free_func_cdecl(); // expected-error {{function declared 'fastcall' here was previously declared 'cdecl'}} +void free_func_stdcall(); void __cdecl free_func_stdcall(); // expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}} -void free_func_stdcall(); // expected-note {{previous declaration is here}} void __fastcall free_func_stdcall(); // expected-error {{function declared 'fastcall' here was previously declared 'stdcall'}} void __cdecl free_func_fastcall(); // expected-error {{function declared 'cdecl' here was previously declared 'fastcall'}} @@ -41,15 +44,16 @@ struct S { void __thiscall member_thiscall1(); void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}} - // Unless attributed, typedefs carry no calling convention and use the default - // based on context. - void_fun_t member_typedef_default; // expected-note {{previous declaration is here}} - cdecl_fun_t member_typedef_cdecl; // expected-note {{previous declaration is here}} - __stdcall void_fun_t member_typedef_stdcall; + // Typedefs carrying the __cdecl convention are adjusted to __thiscall. + void_fun_t member_typedef_default; // expected-note {{previous declaration is here}} + cdecl_fun_t member_typedef_cdecl1; // expected-note {{previous declaration is here}} + cdecl_fun_t __cdecl member_typedef_cdecl2; + void_fun_t __stdcall member_typedef_stdcall; // Static member functions can't be __thiscall static void static_member_default1(); - static void static_member_default2(); // expected-note {{previous declaration is here}} + static void static_member_default2(); + static void static_member_default3(); // expected-note {{previous declaration is here}} static void __cdecl static_member_cdecl1(); static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}} static void __stdcall static_member_stdcall1(); @@ -66,8 +70,9 @@ struct S { void __cdecl S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}} void __thiscall S::member_default2() {} -void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}} -void __thiscall S::member_typedef_cdecl() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}} +void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}} +void __cdecl S::member_typedef_cdecl1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}} +void __cdecl S::member_typedef_cdecl2() {} void __stdcall S::member_typedef_stdcall() {} void S::member_cdecl1() {} @@ -76,25 +81,18 @@ void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thi void S::member_thiscall1() {} void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}} -void __cdecl S::static_member_default1() {} -void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}} +void S::static_member_default1() {} +void __cdecl S::static_member_default2() {} +void __stdcall S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}} void S::static_member_cdecl1() {} void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}} -void __cdecl S::member_variadic_default(int x, ...) { - (void)x; -} -void S::member_variadic_cdecl(int x, ...) { - (void)x; -} +void __cdecl S::member_variadic_default(int x, ...) { (void)x; } +void S::member_variadic_cdecl(int x, ...) { (void)x; } -void __cdecl S::static_member_variadic_default(int x, ...) { - (void)x; -} -void S::static_member_variadic_cdecl(int x, ...) { - (void)x; -} +void __cdecl S::static_member_variadic_default(int x, ...) { (void)x; } +void S::static_member_variadic_cdecl(int x, ...) { (void)x; } // Declare a template using a calling convention. template inline int __cdecl mystrlen(const CharT *str) { @@ -110,3 +108,39 @@ void use_tmpl(const char *str, const int *ints) { mystrlen(str); mystrlen(ints); } + +struct MixedCCStaticOverload { + static void overloaded(int a); + static void __stdcall overloaded(short a); +}; + +void MixedCCStaticOverload::overloaded(int a) {} +void MixedCCStaticOverload::overloaded(short a) {} + +// Friend function decls are cdecl by default, not thiscall. Friend method +// decls should always be redeclarations, because the class cannot be +// incomplete. +struct FriendClass { + void friend_method() {} +}; +void __stdcall friend_stdcall1() {} +class MakeFriendDecls { + int x; + friend void FriendClass::friend_method(); + friend void friend_default(); + friend void friend_stdcall1(); + friend void __stdcall friend_stdcall2(); + friend void friend_stdcall3(); // expected-note {{previous declaration is here}} +}; +void friend_default() {} +void __stdcall friend_stdcall3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}} +void __stdcall friend_stdcall2() {} + +// Test functions with multiple attributes. +void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attribute(int x); +void multi_attribute(int x) { __builtin_unreachable(); } + + +// expected-error@+2 {{stdcall and cdecl attributes are not compatible}} +// expected-error@+1 {{fastcall and cdecl attributes are not compatible}} +void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x); diff --git a/clang/test/SemaCXX/virtual-override-x86.cpp b/clang/test/SemaCXX/virtual-override-x86.cpp index ad70d3f22437..75d8af3b3ea3 100644 --- a/clang/test/SemaCXX/virtual-override-x86.cpp +++ b/clang/test/SemaCXX/virtual-override-x86.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11 +// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11 -cxx-abi microsoft namespace PR14339 { class A { @@ -28,6 +28,6 @@ namespace PR14339 { class F : public E { public: - void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void ()') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}} + void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void () __attribute__((thiscall))') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}} }; } diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index 3ed388f4a708..6c937c6e52d8 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -504,7 +504,6 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { if (const FunctionType *FD = T->getAs()) { #define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X switch (FD->getCallConv()) { - TCALLINGCONV(Default); TCALLINGCONV(C); TCALLINGCONV(X86StdCall); TCALLINGCONV(X86FastCall);