forked from OSchip/llvm-project
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
This commit is contained in:
parent
8f4524a728
commit
78af0708b7
|
@ -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.
|
||||
|
|
|
@ -1812,6 +1812,10 @@ template <> const TypedefType *Type::getAs() const;
|
|||
/// non-sugared type.
|
||||
template <> const TemplateSpecializationType *Type::getAs() const;
|
||||
|
||||
/// \brief This will check for an AttributedType by removing any existing sugar
|
||||
/// until it reaches an AttributedType or a non-sugared type.
|
||||
template <> const AttributedType *Type::getAs() const;
|
||||
|
||||
// We can do canonical leaf types faster, because we don't have to
|
||||
// worry about preserving child type decoration.
|
||||
#define TYPE(Class, Base)
|
||||
|
@ -2683,7 +2687,11 @@ class FunctionType : public Type {
|
|||
|
||||
// Constructor with all defaults. Use when for example creating a
|
||||
// function know to use defaults.
|
||||
ExtInfo() : Bits(0) {}
|
||||
ExtInfo() : Bits(CC_C) { }
|
||||
|
||||
// Constructor with just the calling convention, which is an important part
|
||||
// of the canonical type.
|
||||
ExtInfo(CallingConv CC) : Bits(CC) { }
|
||||
|
||||
bool getNoReturn() const { return Bits & NoReturnMask; }
|
||||
bool getProducesResult() const { return Bits & ProducesResultMask; }
|
||||
|
@ -2826,6 +2834,12 @@ public:
|
|||
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
||||
ConsumedArguments(0) {}
|
||||
|
||||
ExtProtoInfo(CallingConv CC)
|
||||
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
|
||||
Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
|
||||
ExceptionSpecTemplate(0), ConsumedArguments(0) {}
|
||||
|
||||
FunctionType::ExtInfo ExtInfo;
|
||||
bool Variadic : 1;
|
||||
bool HasTrailingReturn : 1;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -779,7 +779,6 @@ public:
|
|||
default:
|
||||
return CCCR_Warning;
|
||||
case CC_C:
|
||||
case CC_Default:
|
||||
return CCCR_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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() &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,54 +2300,53 @@ 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.
|
||||
|
||||
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.
|
||||
} 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.
|
||||
} else {
|
||||
// Calling conventions aren't compatible, so complain.
|
||||
bool FirstCCExplicit = getCallingConvAttributedType(First->getType());
|
||||
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);
|
||||
<< !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?
|
||||
if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) {
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
|
||||
|
|
|
@ -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,16 +820,19 @@ 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
|
||||
|
@ -894,7 +898,8 @@ static void addBlockPointerConversion(Sema &S,
|
|||
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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,21 +4466,20 @@ 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?
|
||||
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.
|
||||
if (CC == CC_X86FastCall) {
|
||||
|
@ -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,
|
||||
|
|
|
@ -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{{.*}} }
|
||||
|
|
|
@ -56,3 +56,7 @@ PROC __attribute__((cdecl)) ctest4(const char *x) {}
|
|||
void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
|
||||
|
||||
void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {}
|
||||
|
||||
typedef void typedef_fun_t(int);
|
||||
typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}}
|
||||
void __attribute__((stdcall)) typedef_fun(int x) { } // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// RUN: %clang_cc1 -DMRTD -mrtd -triple i386-unknown-unknown -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -verify %s
|
||||
|
||||
#ifndef MRTD
|
||||
// expected-note@+5 {{previous declaration is here}}
|
||||
// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
// expected-note@+5 {{previous declaration is here}}
|
||||
// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
#endif
|
||||
void nonvariadic1(int a, int b, int c);
|
||||
void __attribute__((stdcall)) nonvariadic1(int a, int b, int c);
|
||||
void nonvariadic2(int a, int b, int c);
|
||||
void __attribute__((stdcall)) nonvariadic2(int a, int b, int c) { }
|
||||
|
||||
// expected-note@+2 {{previous declaration is here}}
|
||||
// expected-error@+2 {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
void variadic(int a, ...);
|
||||
void __attribute__((stdcall)) variadic(int a, ...);
|
||||
|
||||
#ifdef MRTD
|
||||
// expected-note@+3 {{previous definition is here}}
|
||||
// expected-error@+3 {{redefinition of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}}
|
||||
#endif
|
||||
extern void (*a)(int, int);
|
||||
__attribute__((cdecl)) extern void (*a)(int, int);
|
||||
|
||||
extern void (*b)(int, ...);
|
||||
__attribute__((cdecl)) extern void (*b)(int, ...);
|
||||
|
||||
#ifndef MRTD
|
||||
// expected-note@+3 {{previous definition is here}}
|
||||
// expected-error@+3 {{redefinition of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}}
|
||||
#endif
|
||||
extern void (*c)(int, int);
|
||||
__attribute__((stdcall)) extern void (*c)(int, int);
|
||||
|
||||
// expected-note@+2 {{previous definition is here}}
|
||||
// expected-error@+2 {{redefinition of 'd' with a different type: 'void ((*))(int, ...) __attribute__((stdcall))' vs 'void (*)(int, ...)'}}
|
||||
extern void (*d)(int, ...);
|
||||
__attribute__((stdcall)) extern void (*d)(int, ...);
|
|
@ -0,0 +1,387 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fms-extensions -cxx-abi microsoft -verify -triple i686-pc-win32 %s
|
||||
|
||||
// Pointers to free functions
|
||||
void free_func_default();
|
||||
void __cdecl free_func_cdecl();
|
||||
void __stdcall free_func_stdcall();
|
||||
void __fastcall free_func_fastcall();
|
||||
|
||||
typedef void ( *fptr_default)();
|
||||
typedef void (__cdecl *fptr_cdecl)();
|
||||
typedef void (__stdcall *fptr_stdcall)();
|
||||
typedef void (__fastcall *fptr_fastcall)();
|
||||
|
||||
// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
|
||||
void cb_fptr_default(fptr_default ptr);
|
||||
// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
|
||||
void cb_fptr_cdecl(fptr_cdecl ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
|
||||
void cb_fptr_stdcall(fptr_stdcall ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
|
||||
void cb_fptr_fastcall(fptr_fastcall ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
|
||||
void cb_fptr_const_default(const fptr_default ptr);
|
||||
|
||||
void call_free_func() {
|
||||
cb_fptr_default(free_func_default);
|
||||
cb_fptr_default(free_func_cdecl);
|
||||
cb_fptr_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
|
||||
cb_fptr_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
|
||||
cb_fptr_default(&free_func_default);
|
||||
cb_fptr_default(&free_func_cdecl);
|
||||
cb_fptr_default(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
|
||||
cb_fptr_default(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
|
||||
|
||||
cb_fptr_cdecl(free_func_default);
|
||||
cb_fptr_cdecl(free_func_cdecl);
|
||||
cb_fptr_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
|
||||
cb_fptr_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
|
||||
cb_fptr_cdecl(&free_func_default);
|
||||
cb_fptr_cdecl(&free_func_cdecl);
|
||||
cb_fptr_cdecl(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
|
||||
cb_fptr_cdecl(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
|
||||
|
||||
cb_fptr_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
|
||||
cb_fptr_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
|
||||
cb_fptr_stdcall(free_func_stdcall);
|
||||
cb_fptr_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
|
||||
|
||||
cb_fptr_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
|
||||
cb_fptr_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
|
||||
cb_fptr_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
|
||||
cb_fptr_fastcall(free_func_fastcall);
|
||||
|
||||
cb_fptr_const_default(free_func_default);
|
||||
cb_fptr_const_default(free_func_cdecl);
|
||||
cb_fptr_const_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
|
||||
cb_fptr_const_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
|
||||
|
||||
}
|
||||
|
||||
// Pointers to variadic functions
|
||||
// variadic function can't declared stdcall or fastcall
|
||||
void free_func_variadic_default(int, ...);
|
||||
void __cdecl free_func_variadic_cdecl(int, ...);
|
||||
|
||||
typedef void ( *fptr_variadic_default)(int, ...);
|
||||
typedef void (__cdecl *fptr_variadic_cdecl)(int, ...);
|
||||
|
||||
void cb_fptr_variadic_default(fptr_variadic_default ptr);
|
||||
void cb_fptr_variadic_cdecl(fptr_variadic_cdecl ptr);
|
||||
|
||||
void call_free_variadic_func() {
|
||||
cb_fptr_variadic_default(free_func_variadic_default);
|
||||
cb_fptr_variadic_default(free_func_variadic_cdecl);
|
||||
cb_fptr_variadic_default(&free_func_variadic_default);
|
||||
cb_fptr_variadic_default(&free_func_variadic_cdecl);
|
||||
|
||||
cb_fptr_variadic_cdecl(free_func_variadic_default);
|
||||
cb_fptr_variadic_cdecl(free_func_variadic_cdecl);
|
||||
cb_fptr_variadic_cdecl(&free_func_variadic_default);
|
||||
cb_fptr_variadic_cdecl(&free_func_variadic_cdecl);
|
||||
}
|
||||
|
||||
// References to functions
|
||||
typedef void ( &fref_default)();
|
||||
typedef void (__cdecl &fref_cdecl)();
|
||||
typedef void (__stdcall &fref_stdcall)();
|
||||
typedef void (__fastcall &fref_fastcall)();
|
||||
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
|
||||
void cb_fref_default(fref_default ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
|
||||
void cb_fref_cdecl(fref_cdecl ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
|
||||
void cb_fref_stdcall(fref_stdcall ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
|
||||
void cb_fref_fastcall(fref_fastcall ptr);
|
||||
|
||||
void call_free_func_ref() {
|
||||
cb_fref_default(free_func_default);
|
||||
cb_fref_default(free_func_cdecl);
|
||||
cb_fref_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
|
||||
cb_fref_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
|
||||
|
||||
cb_fref_cdecl(free_func_default);
|
||||
cb_fref_cdecl(free_func_cdecl);
|
||||
cb_fref_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
|
||||
cb_fref_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
|
||||
|
||||
cb_fref_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
|
||||
cb_fref_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
|
||||
cb_fref_stdcall(free_func_stdcall);
|
||||
cb_fref_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
|
||||
|
||||
cb_fref_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
|
||||
cb_fref_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
|
||||
cb_fref_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
|
||||
cb_fref_fastcall(free_func_fastcall);
|
||||
}
|
||||
|
||||
// References to variadic functions
|
||||
// variadic function can't declared stdcall or fastcall
|
||||
typedef void ( &fref_variadic_default)(int, ...);
|
||||
typedef void (__cdecl &fref_variadic_cdecl)(int, ...);
|
||||
|
||||
void cb_fref_variadic_default(fptr_variadic_default ptr);
|
||||
void cb_fref_variadic_cdecl(fptr_variadic_cdecl ptr);
|
||||
|
||||
void call_free_variadic_func_ref() {
|
||||
cb_fref_variadic_default(free_func_variadic_default);
|
||||
cb_fref_variadic_default(free_func_variadic_cdecl);
|
||||
|
||||
cb_fref_variadic_cdecl(free_func_variadic_default);
|
||||
cb_fref_variadic_cdecl(free_func_variadic_cdecl);
|
||||
}
|
||||
|
||||
// Pointers to members
|
||||
namespace NonVariadic {
|
||||
|
||||
struct A {
|
||||
void member_default();
|
||||
void __cdecl member_cdecl();
|
||||
void __thiscall member_thiscall();
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
};
|
||||
|
||||
struct C {
|
||||
void member_default();
|
||||
void __cdecl member_cdecl();
|
||||
void __thiscall member_thiscall();
|
||||
};
|
||||
|
||||
typedef void ( A::*memb_a_default)();
|
||||
typedef void (__cdecl A::*memb_a_cdecl)();
|
||||
typedef void (__thiscall A::*memb_a_thiscall)();
|
||||
typedef void ( B::*memb_b_default)();
|
||||
typedef void (__cdecl B::*memb_b_cdecl)();
|
||||
typedef void (__thiscall B::*memb_b_thiscall)();
|
||||
typedef void ( C::*memb_c_default)();
|
||||
typedef void (__cdecl C::*memb_c_cdecl)();
|
||||
typedef void (__thiscall C::*memb_c_thiscall)();
|
||||
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_a_default(memb_a_default ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
void cb_memb_a_cdecl(memb_a_cdecl ptr);
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_a_thiscall(memb_a_thiscall ptr);
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_b_default(memb_b_default ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
void cb_memb_b_cdecl(memb_b_cdecl ptr);
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_b_thiscall(memb_b_thiscall ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_c_default(memb_c_default ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
|
||||
void cb_memb_c_cdecl(memb_c_cdecl ptr);
|
||||
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
|
||||
void cb_memb_c_thiscall(memb_c_thiscall ptr);
|
||||
|
||||
void call_member() {
|
||||
cb_memb_a_default(&A::member_default);
|
||||
cb_memb_a_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_default'}}
|
||||
cb_memb_a_default(&A::member_thiscall);
|
||||
|
||||
cb_memb_a_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
|
||||
cb_memb_a_cdecl(&A::member_cdecl);
|
||||
cb_memb_a_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
|
||||
|
||||
cb_memb_a_thiscall(&A::member_default);
|
||||
cb_memb_a_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_thiscall'}}
|
||||
cb_memb_a_thiscall(&A::member_thiscall);
|
||||
}
|
||||
|
||||
void call_member_inheritance() {
|
||||
cb_memb_b_default(&A::member_default);
|
||||
cb_memb_b_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_default'}}
|
||||
cb_memb_b_default(&A::member_thiscall);
|
||||
cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
|
||||
cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
|
||||
cb_memb_c_default(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
|
||||
|
||||
cb_memb_b_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
|
||||
cb_memb_b_cdecl(&A::member_cdecl);
|
||||
cb_memb_b_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
|
||||
cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
|
||||
cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
|
||||
cb_memb_c_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
|
||||
|
||||
cb_memb_b_thiscall(&A::member_default);
|
||||
cb_memb_b_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_thiscall'}}
|
||||
cb_memb_b_thiscall(&A::member_thiscall);
|
||||
cb_memb_c_thiscall(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
|
||||
cb_memb_c_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
|
||||
cb_memb_c_thiscall(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
|
||||
}
|
||||
} // end namespace NonVariadic
|
||||
|
||||
namespace Variadic {
|
||||
struct A {
|
||||
void member_default(int, ...);
|
||||
void __cdecl member_cdecl(int, ...);
|
||||
void __thiscall member_thiscall(int, ...);
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
};
|
||||
|
||||
struct C {
|
||||
void member_default(int, ...);
|
||||
void __cdecl member_cdecl(int, ...);
|
||||
};
|
||||
|
||||
typedef void ( A::*memb_a_default)(int, ...);
|
||||
typedef void (__cdecl A::*memb_a_cdecl)(int, ...);
|
||||
typedef void ( B::*memb_b_default)(int, ...);
|
||||
typedef void (__cdecl B::*memb_b_cdecl)(int, ...);
|
||||
typedef void ( C::*memb_c_default)(int, ...);
|
||||
typedef void (__cdecl C::*memb_c_cdecl)(int, ...);
|
||||
|
||||
void cb_memb_a_default(memb_a_default ptr);
|
||||
void cb_memb_a_cdecl(memb_a_cdecl ptr);
|
||||
void cb_memb_b_default(memb_b_default ptr);
|
||||
void cb_memb_b_cdecl(memb_b_cdecl ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
|
||||
void cb_memb_c_default(memb_c_default ptr);
|
||||
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
|
||||
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
|
||||
void cb_memb_c_cdecl(memb_c_cdecl ptr);
|
||||
|
||||
void call_member() {
|
||||
cb_memb_a_default(&A::member_default);
|
||||
cb_memb_a_default(&A::member_cdecl);
|
||||
|
||||
cb_memb_a_cdecl(&A::member_default);
|
||||
cb_memb_a_cdecl(&A::member_cdecl);
|
||||
}
|
||||
|
||||
void call_member_inheritance() {
|
||||
cb_memb_b_default(&A::member_default);
|
||||
cb_memb_b_default(&A::member_cdecl);
|
||||
cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
|
||||
cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
|
||||
|
||||
cb_memb_b_cdecl(&A::member_default);
|
||||
cb_memb_b_cdecl(&A::member_cdecl);
|
||||
cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
|
||||
cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
|
||||
}
|
||||
} // end namespace Variadic
|
||||
|
||||
namespace MultiChunkDecls {
|
||||
|
||||
// Try to test declarators that have multiple DeclaratorChunks.
|
||||
struct A {
|
||||
void __thiscall member_thiscall(int);
|
||||
};
|
||||
|
||||
void (A::*return_mptr(short))(int) {
|
||||
return &A::member_thiscall;
|
||||
}
|
||||
|
||||
void (A::*(*return_fptr_mptr(char))(short))(int) {
|
||||
return return_mptr;
|
||||
}
|
||||
|
||||
typedef void (A::*mptr_t)(int);
|
||||
mptr_t __stdcall return_mptr_std(short) {
|
||||
return &A::member_thiscall;
|
||||
}
|
||||
|
||||
void (A::*(*return_fptr_std_mptr(char))(short))(int) {
|
||||
return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'mptr_t (short) __attribute__((stdcall))'}}
|
||||
}
|
||||
|
||||
void call_return() {
|
||||
A o;
|
||||
void (A::*(*fptr)(short))(int) = return_fptr_mptr('a');
|
||||
void (A::*mptr)(int) = fptr(1);
|
||||
(o.*mptr)(2);
|
||||
}
|
||||
|
||||
} // end namespace MultiChunkDecls
|
||||
|
||||
namespace MemberPointers {
|
||||
|
||||
struct A {
|
||||
void __thiscall method_thiscall();
|
||||
void __cdecl method_cdecl();
|
||||
void __stdcall method_stdcall();
|
||||
void __fastcall method_fastcall();
|
||||
};
|
||||
|
||||
void ( A::*mp1)() = &A::method_thiscall;
|
||||
void (__cdecl A::*mp2)() = &A::method_cdecl;
|
||||
void (__stdcall A::*mp3)() = &A::method_stdcall;
|
||||
void (__fastcall A::*mp4)() = &A::method_fastcall;
|
||||
|
||||
// Use a typedef to form the member pointer and verify that cdecl is adjusted.
|
||||
typedef void ( fun_default)();
|
||||
typedef void (__cdecl fun_cdecl)();
|
||||
typedef void (__stdcall fun_stdcall)();
|
||||
typedef void (__fastcall fun_fastcall)();
|
||||
|
||||
// FIXME: Adjust cdecl to thiscall when forming a member pointer.
|
||||
//fun_default A::*td1 = &A::method_thiscall;
|
||||
fun_cdecl A::*td2 = &A::method_cdecl;
|
||||
fun_stdcall A::*td3 = &A::method_stdcall;
|
||||
fun_fastcall A::*td4 = &A::method_fastcall;
|
||||
|
||||
// Round trip the function type through a template, and verify that only cdecl
|
||||
// gets adjusted.
|
||||
template<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}}
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
// 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_cdecl; // expected-note {{previous declaration is here}}
|
||||
__stdcall void_fun_t member_typedef_stdcall;
|
||||
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();
|
||||
|
@ -67,7 +71,8 @@ void __cdecl S::member_default1() {} // expected-error {{function declared 'c
|
|||
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_cdecl1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
|
||||
void __cdecl S::member_typedef_cdecl2() {}
|
||||
void __stdcall S::member_typedef_stdcall() {}
|
||||
|
||||
void S::member_cdecl1() {}
|
||||
|
@ -76,25 +81,18 @@ void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thi
|
|||
void S::member_thiscall1() {}
|
||||
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
|
||||
|
||||
void __cdecl S::static_member_default1() {}
|
||||
void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
void S::static_member_default1() {}
|
||||
void __cdecl S::static_member_default2() {}
|
||||
void __stdcall S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
|
||||
void S::static_member_cdecl1() {}
|
||||
void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
|
||||
|
||||
void __cdecl S::member_variadic_default(int x, ...) {
|
||||
(void)x;
|
||||
}
|
||||
void S::member_variadic_cdecl(int x, ...) {
|
||||
(void)x;
|
||||
}
|
||||
void __cdecl S::member_variadic_default(int x, ...) { (void)x; }
|
||||
void S::member_variadic_cdecl(int x, ...) { (void)x; }
|
||||
|
||||
void __cdecl S::static_member_variadic_default(int x, ...) {
|
||||
(void)x;
|
||||
}
|
||||
void S::static_member_variadic_cdecl(int x, ...) {
|
||||
(void)x;
|
||||
}
|
||||
void __cdecl S::static_member_variadic_default(int x, ...) { (void)x; }
|
||||
void S::static_member_variadic_cdecl(int x, ...) { (void)x; }
|
||||
|
||||
// Declare a template using a calling convention.
|
||||
template <class CharT> inline int __cdecl mystrlen(const CharT *str) {
|
||||
|
@ -110,3 +108,39 @@ void use_tmpl(const char *str, const int *ints) {
|
|||
mystrlen(str);
|
||||
mystrlen(ints);
|
||||
}
|
||||
|
||||
struct MixedCCStaticOverload {
|
||||
static void overloaded(int a);
|
||||
static void __stdcall overloaded(short a);
|
||||
};
|
||||
|
||||
void MixedCCStaticOverload::overloaded(int a) {}
|
||||
void MixedCCStaticOverload::overloaded(short a) {}
|
||||
|
||||
// Friend function decls are cdecl by default, not thiscall. Friend method
|
||||
// decls should always be redeclarations, because the class cannot be
|
||||
// incomplete.
|
||||
struct FriendClass {
|
||||
void friend_method() {}
|
||||
};
|
||||
void __stdcall friend_stdcall1() {}
|
||||
class MakeFriendDecls {
|
||||
int x;
|
||||
friend void FriendClass::friend_method();
|
||||
friend void friend_default();
|
||||
friend void friend_stdcall1();
|
||||
friend void __stdcall friend_stdcall2();
|
||||
friend void friend_stdcall3(); // expected-note {{previous declaration is here}}
|
||||
};
|
||||
void friend_default() {}
|
||||
void __stdcall friend_stdcall3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
|
||||
void __stdcall friend_stdcall2() {}
|
||||
|
||||
// Test functions with multiple attributes.
|
||||
void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attribute(int x);
|
||||
void multi_attribute(int x) { __builtin_unreachable(); }
|
||||
|
||||
|
||||
// expected-error@+2 {{stdcall and cdecl attributes are not compatible}}
|
||||
// expected-error@+1 {{fastcall and cdecl attributes are not compatible}}
|
||||
void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x);
|
||||
|
|
|
@ -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))'}}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -504,7 +504,6 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue