diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-08-27 23:08:25 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-08-27 23:08:25 +0000 |
commit | 78af0708b7d3b1d7a3189c39541c91cf9cb6d3f7 (patch) | |
tree | 390ae44b40f830581cf98ffae4be55c7480f9d0b /clang/lib | |
parent | 8f4524a7282aefe99ba42b92f9708c3d94232215 (diff) | |
download | bcm5719-llvm-78af0708b7d3b1d7a3189c39541c91cf9cb6d3f7.tar.gz bcm5719-llvm-78af0708b7d3b1d7a3189c39541c91cf9cb6d3f7.zip |
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
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 38 | ||||
-rw-r--r-- | clang/lib/AST/DumpXML.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 7 | ||||
-rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 15 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 96 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 73 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 111 |
14 files changed, 224 insertions, 180 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 29ddb37525d..94d9e918e75 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<QualType> 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<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2816,8 +2808,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> 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<QualType> 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 be22ae450b6..9516a4be99a 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/lib/AST/DumpXML.cpp @@ -915,7 +915,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, 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 b76bc2f2849..36aa2892f2a 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 87527c9294a..97edce105cd 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<FunctionProtoType>(); - 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 ef423eba879..1bd2d3b98da 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<TemplateSpecializationType>(this); } +template <> const AttributedType *Type::getAs() const { + return getAsSugar<AttributedType>(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 f6fd886e8a4..2a4cf52027d 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 84f8a347bda..f4c4226482d 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 971a2ade126..ed02c74cdfc 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<CanQualType> &prefix, CanQual<FunctionProtoType> 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 70fc8fed5d4..b56684ba5c8 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 d831c706190..748814d9344 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<CXXMethodDecl>(D) && cast<CXXMethodDecl>(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<AttributedType>(); + while (AT && !AT->isCallingConv()) + AT = AT->getModifiedType()->getAs<AttributedType>(); + return AT; } template <typename T> @@ -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<FunctionType>(OldQType); - const FunctionType *NewType = New->getType()->getAs<FunctionType>(); + const FunctionType *NewType = cast<FunctionType>(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; - - // 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; + if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) { + FunctionDecl *First = Old->getFirstDeclaration(); + const FunctionType *FT = + First->getType().getCanonicalType()->castAs<FunctionType>(); + 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())); + + // 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<FunctionType>(); - 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 f12f92321ae..bfb96c7ff5e 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<FunctionProtoType>(); 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<FunctionProtoType>( 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 ae3a938333f..242105f789c 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 a17a903a5f4..c00ae69cbe8 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 9664937954b..52b099e197d 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<FunctionType>(); + bool IsVariadic = (isa<FunctionProtoType>(FT) && + cast<FunctionProtoType>(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<AttributedType>(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, |