r189412 - Delete CC_Default and use the target default CC everywhere
Reid Kleckner
reid at kleckner.net
Tue Aug 27 16:08:26 PDT 2013
Author: rnk
Date: Tue Aug 27 18:08:25 2013
New Revision: 189412
URL: http://llvm.org/viewvc/llvm-project?rev=189412&view=rev
Log:
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
Added:
cfe/trunk/test/Sema/mrtd.c
cfe/trunk/test/SemaCXX/calling-conv-compat.cpp
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/Specifiers.h
cfe/trunk/include/clang/Basic/TargetInfo.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/DumpXML.cpp
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/MicrosoftMangle.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/AST/TypePrinter.cpp
cfe/trunk/lib/Basic/Targets.cpp
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/CodeGen/mrtd.c
cfe/trunk/test/Sema/callingconv.c
cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp
cfe/trunk/test/SemaCXX/virtual-override-x86.cpp
cfe/trunk/tools/libclang/CXType.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Aug 27 18:08:25 2013
@@ -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.
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Tue Aug 27 18:08:25 2013
@@ -1812,6 +1812,10 @@ template <> const TypedefType *Type::get
/// 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;
Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Tue Aug 27 18:08:25 2013
@@ -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))
Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Tue Aug 27 18:08:25 2013
@@ -779,7 +779,6 @@ public:
default:
return CCCR_Warning;
case CC_C:
- case CC_Default:
return CCCR_OK;
}
}
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Aug 27 18:08:25 2013
@@ -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);
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Aug 27 18:08:25 2013
@@ -2732,9 +2732,8 @@ ASTContext::getDependentSizedExtVectorTy
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(QualT
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 Res
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 Res
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 Res
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(
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(unsi
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
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 {
Modified: cfe/trunk/lib/AST/DumpXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DumpXML.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DumpXML.cpp (original)
+++ cfe/trunk/lib/AST/DumpXML.cpp Tue Aug 27 18:08:25 2013
@@ -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");
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Aug 27 18:08:25 2013
@@ -196,8 +196,10 @@ CXXPseudoDestructorExpr::CXXPseudoDestru
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() &&
Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Aug 27 18:08:25 2013
@@ -1391,20 +1391,9 @@ void MicrosoftCXXNameMangler::mangleCall
// 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;
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Aug 27 18:08:25 2013
@@ -338,6 +338,10 @@ template <> const TemplateSpecialization
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(
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";
Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Tue Aug 27 18:08:25 2013
@@ -634,9 +634,14 @@ void TypePrinter::printFunctionProtoAfte
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(c
}
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(c
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())
Modified: cfe/trunk/lib/Basic/Targets.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Targets.cpp (original)
+++ cfe/trunk/lib/Basic/Targets.cpp Tue Aug 27 18:08:25 2013
@@ -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 {
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Tue Aug 27 18:08:25 2013
@@ -103,24 +103,12 @@ static const CGFunctionInfo &arrangeFree
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::arrangeCXXConstructorDecla
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
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
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);
}
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Aug 27 18:08:25 2013
@@ -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) {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 27 18:08:25 2013
@@ -2201,17 +2201,11 @@ static bool canRedefineFunction(const Fu
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(FunctionDec
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(FunctionDec
}
}
- // 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;
+ 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()));
- } 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,
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,
// 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();
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 27 18:08:25 2013
@@ -4435,6 +4435,21 @@ updateExceptionSpec(Sema &S, FunctionDec
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::CheckExplicitlyDefaultedSpeci
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::DeclareImplici
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::DeclareImplicit
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::DeclareImplicitCopy
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::DeclareImplicitMove
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::DeclareImplici
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::DeclareImplici
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::CheckOverridingFunctionAttrib
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,
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Tue Aug 27 18:08:25 2013
@@ -539,7 +539,8 @@ void Sema::ActOnStartOfLambdaDefinition(
// 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
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(Se
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);
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Aug 27 18:08:25 2013
@@ -728,7 +728,7 @@ static bool LookupDirect(Sema &S, Lookup
// 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
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Aug 27 18:08:25 2013
@@ -1784,6 +1784,8 @@ QualType Sema::BuildMemberPointerType(Qu
}
}
+ // FIXME: Adjust member function pointer calling conventions.
+
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@@ -2420,6 +2422,53 @@ static void warnAboutAmbiguousFunction(S
}
}
+/// 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 *GetFullTypeForDec
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 *GetFullTypeForDec
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(TypeP
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(TypeP
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,
Modified: cfe/trunk/test/CodeGen/mrtd.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mrtd.c?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/mrtd.c (original)
+++ cfe/trunk/test/CodeGen/mrtd.c Tue Aug 27 18:08:25 2013
@@ -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{{.*}} }
Modified: cfe/trunk/test/Sema/callingconv.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/callingconv.c?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/test/Sema/callingconv.c (original)
+++ cfe/trunk/test/Sema/callingconv.c Tue Aug 27 18:08:25 2013
@@ -56,3 +56,7 @@ PROC __attribute__((cdecl)) ctest4(const
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}}
Added: cfe/trunk/test/Sema/mrtd.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/mrtd.c?rev=189412&view=auto
==============================================================================
--- cfe/trunk/test/Sema/mrtd.c (added)
+++ cfe/trunk/test/Sema/mrtd.c Tue Aug 27 18:08:25 2013
@@ -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 at +5 {{previous declaration is here}}
+// expected-error at +5 {{function declared 'stdcall' here was previously declared without calling convention}}
+// expected-note at +5 {{previous declaration is here}}
+// expected-error at +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 at +2 {{previous declaration is here}}
+// expected-error at +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 at +3 {{previous definition is here}}
+// expected-error at +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 at +3 {{previous definition is here}}
+// expected-error at +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 at +2 {{previous definition is here}}
+// expected-error at +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, ...);
Added: cfe/trunk/test/SemaCXX/calling-conv-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/calling-conv-compat.cpp?rev=189412&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/calling-conv-compat.cpp (added)
+++ cfe/trunk/test/SemaCXX/calling-conv-compat.cpp Tue Aug 27 18:08:25 2013
@@ -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 at +4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note at +3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
+// expected-note at +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 at +4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note at +3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
+// expected-note at +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 at +3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
+// expected-note at +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 at +3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
+// expected-note at +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 at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
+// expected-note at +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 at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
+// expected-note at +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 at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
+// expected-note at +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 at +3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
+// expected-note at +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 at +3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
+// expected-note at +2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
+// expected-note at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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<typename Fn> struct X {
+ typedef Fn A::*p;
+};
+
+// FIXME: Adjust cdecl to thiscall when forming a member pointer.
+//X<void ()>::p tmpl1 = &A::method_thiscall;
+//X<void __cdecl ()>::p tmpl2 = &A::method_thiscall;
+X<void __stdcall ()>::p tmpl3 = &A::method_stdcall;
+X<void __fastcall ()>::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}}
+}
+
+}
Modified: cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp Tue Aug 27 18:08:25 2013
@@ -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() {} //
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 <class CharT> inline int __cdecl mystrlen(const CharT *str) {
@@ -110,3 +108,39 @@ void use_tmpl(const char *str, const int
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 at +2 {{stdcall and cdecl attributes are not compatible}}
+// expected-error at +1 {{fastcall and cdecl attributes are not compatible}}
+void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x);
Modified: cfe/trunk/test/SemaCXX/virtual-override-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtual-override-x86.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/virtual-override-x86.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtual-override-x86.cpp Tue Aug 27 18:08:25 2013
@@ -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))'}}
};
}
Modified: cfe/trunk/tools/libclang/CXType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=189412&r1=189411&r2=189412&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXType.cpp (original)
+++ cfe/trunk/tools/libclang/CXType.cpp Tue Aug 27 18:08:25 2013
@@ -504,7 +504,6 @@ CXCallingConv clang_getFunctionTypeCalli
if (const FunctionType *FD = T->getAs<FunctionType>()) {
#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
switch (FD->getCallConv()) {
- TCALLINGCONV(Default);
TCALLINGCONV(C);
TCALLINGCONV(X86StdCall);
TCALLINGCONV(X86FastCall);
More information about the cfe-commits
mailing list