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 *
|
NestedNameSpecifier *
|
||||||
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
||||||
|
|
||||||
/// \brief Retrieves the default calling convention to use for
|
/// \brief Retrieves the default calling convention for the current target.
|
||||||
/// C++ instance methods.
|
CallingConv getDefaultCallingConvention(bool isVariadic,
|
||||||
CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
|
bool IsCXXMethod) const;
|
||||||
|
|
||||||
/// \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 "canonical" template name that refers to a
|
/// \brief Retrieves the "canonical" template name that refers to a
|
||||||
/// given template.
|
/// given template.
|
||||||
|
|
|
@ -1812,6 +1812,10 @@ template <> const TypedefType *Type::getAs() const;
|
||||||
/// non-sugared type.
|
/// non-sugared type.
|
||||||
template <> const TemplateSpecializationType *Type::getAs() const;
|
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
|
// We can do canonical leaf types faster, because we don't have to
|
||||||
// worry about preserving child type decoration.
|
// worry about preserving child type decoration.
|
||||||
#define TYPE(Class, Base)
|
#define TYPE(Class, Base)
|
||||||
|
@ -2683,7 +2687,11 @@ class FunctionType : public Type {
|
||||||
|
|
||||||
// Constructor with all defaults. Use when for example creating a
|
// Constructor with all defaults. Use when for example creating a
|
||||||
// function know to use defaults.
|
// 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 getNoReturn() const { return Bits & NoReturnMask; }
|
||||||
bool getProducesResult() const { return Bits & ProducesResultMask; }
|
bool getProducesResult() const { return Bits & ProducesResultMask; }
|
||||||
|
@ -2826,6 +2834,12 @@ public:
|
||||||
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
||||||
ConsumedArguments(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;
|
FunctionType::ExtInfo ExtInfo;
|
||||||
bool Variadic : 1;
|
bool Variadic : 1;
|
||||||
bool HasTrailingReturn : 1;
|
bool HasTrailingReturn : 1;
|
||||||
|
|
|
@ -200,7 +200,6 @@ namespace clang {
|
||||||
|
|
||||||
/// \brief CallingConv - Specifies the calling convention that a function uses.
|
/// \brief CallingConv - Specifies the calling convention that a function uses.
|
||||||
enum CallingConv {
|
enum CallingConv {
|
||||||
CC_Default,
|
|
||||||
CC_C, // __attribute__((cdecl))
|
CC_C, // __attribute__((cdecl))
|
||||||
CC_X86StdCall, // __attribute__((stdcall))
|
CC_X86StdCall, // __attribute__((stdcall))
|
||||||
CC_X86FastCall, // __attribute__((fastcall))
|
CC_X86FastCall, // __attribute__((fastcall))
|
||||||
|
|
|
@ -779,7 +779,6 @@ public:
|
||||||
default:
|
default:
|
||||||
return CCCR_Warning;
|
return CCCR_Warning;
|
||||||
case CC_C:
|
case CC_C:
|
||||||
case CC_Default:
|
|
||||||
return CCCR_OK;
|
return CCCR_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2539,6 +2539,15 @@ public:
|
||||||
bool CheckNoReturnAttr(const AttributeList &attr);
|
bool CheckNoReturnAttr(const AttributeList &attr);
|
||||||
void CheckAlignasUnderalignment(Decl *D);
|
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.
|
/// \brief Stmt attributes - this routine is the top level dispatcher.
|
||||||
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
|
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
|
||||||
SourceRange Range);
|
SourceRange Range);
|
||||||
|
|
|
@ -2732,9 +2732,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
|
||||||
QualType
|
QualType
|
||||||
ASTContext::getFunctionNoProtoType(QualType ResultTy,
|
ASTContext::getFunctionNoProtoType(QualType ResultTy,
|
||||||
const FunctionType::ExtInfo &Info) const {
|
const FunctionType::ExtInfo &Info) const {
|
||||||
const CallingConv DefaultCC = Info.getCC();
|
const CallingConv CallConv = Info.getCC();
|
||||||
const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
|
|
||||||
CC_X86StdCall : DefaultCC;
|
|
||||||
// Unique functions, to guarantee there is only one function of a particular
|
// Unique functions, to guarantee there is only one function of a particular
|
||||||
// structure.
|
// structure.
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
|
@ -2746,11 +2745,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
|
||||||
return QualType(FT, 0);
|
return QualType(FT, 0);
|
||||||
|
|
||||||
QualType Canonical;
|
QualType Canonical;
|
||||||
if (!ResultTy.isCanonical() ||
|
if (!ResultTy.isCanonical()) {
|
||||||
getCanonicalCallConv(CallConv) != CallConv) {
|
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
|
||||||
Canonical =
|
|
||||||
getFunctionNoProtoType(getCanonicalType(ResultTy),
|
|
||||||
Info.withCallingConv(getCanonicalCallConv(CallConv)));
|
|
||||||
|
|
||||||
// Get the new insert position for the node we care about.
|
// Get the new insert position for the node we care about.
|
||||||
FunctionNoProtoType *NewIP =
|
FunctionNoProtoType *NewIP =
|
||||||
|
@ -2799,14 +2795,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
|
||||||
if (!ArgArray[i].isCanonicalAsParam())
|
if (!ArgArray[i].isCanonicalAsParam())
|
||||||
isCanonical = false;
|
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.
|
// If this type isn't canonical, get the canonical version of it.
|
||||||
// The exception spec is not part of the canonical type.
|
// The exception spec is not part of the canonical type.
|
||||||
QualType Canonical;
|
QualType Canonical;
|
||||||
if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
|
if (!isCanonical) {
|
||||||
SmallVector<QualType, 16> CanonicalArgs;
|
SmallVector<QualType, 16> CanonicalArgs;
|
||||||
CanonicalArgs.reserve(NumArgs);
|
CanonicalArgs.reserve(NumArgs);
|
||||||
for (unsigned i = 0; i != NumArgs; ++i)
|
for (unsigned i = 0; i != NumArgs; ++i)
|
||||||
|
@ -2816,8 +2808,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
|
||||||
CanonicalEPI.HasTrailingReturn = false;
|
CanonicalEPI.HasTrailingReturn = false;
|
||||||
CanonicalEPI.ExceptionSpecType = EST_None;
|
CanonicalEPI.ExceptionSpecType = EST_None;
|
||||||
CanonicalEPI.NumExceptions = 0;
|
CanonicalEPI.NumExceptions = 0;
|
||||||
CanonicalEPI.ExtInfo
|
|
||||||
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
|
|
||||||
|
|
||||||
// Result types do not have ARC lifetime qualifiers.
|
// Result types do not have ARC lifetime qualifiers.
|
||||||
QualType CanResultTy = getCanonicalType(ResultTy);
|
QualType CanResultTy = getCanonicalType(ResultTy);
|
||||||
|
@ -2859,7 +2849,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
|
||||||
|
|
||||||
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
|
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
|
||||||
FunctionProtoType::ExtProtoInfo newEPI = EPI;
|
FunctionProtoType::ExtProtoInfo newEPI = EPI;
|
||||||
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
|
|
||||||
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
|
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
|
||||||
Types.push_back(FTP);
|
Types.push_back(FTP);
|
||||||
FunctionProtoTypes.InsertNode(FTP, InsertPos);
|
FunctionProtoTypes.InsertNode(FTP, InsertPos);
|
||||||
|
@ -6939,7 +6928,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
|
||||||
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
|
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
|
||||||
|
|
||||||
// Compatible functions must have compatible calling conventions
|
// Compatible functions must have compatible calling conventions
|
||||||
if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
|
if (lbaseInfo.getCC() != rbaseInfo.getCC())
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
// Regparm is part of the calling convention.
|
// Regparm is part of the calling convention.
|
||||||
|
@ -7784,7 +7773,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
|
||||||
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
|
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
|
||||||
"'.' should only occur at end of builtin type list!");
|
"'.' 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);
|
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
|
||||||
|
|
||||||
bool Variadic = (TypeStr[0] == '.');
|
bool Variadic = (TypeStr[0] == '.');
|
||||||
|
@ -7955,16 +7944,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
|
CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
|
||||||
|
bool IsCXXMethod) const {
|
||||||
// Pass through to the C++ ABI object
|
// Pass through to the C++ ABI object
|
||||||
return ABI->getDefaultMethodCallConv(isVariadic);
|
if (IsCXXMethod)
|
||||||
}
|
return ABI->getDefaultMethodCallConv(IsVariadic);
|
||||||
|
|
||||||
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
|
return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C;
|
||||||
if (CC == CC_C && !LangOpts.MRTD &&
|
|
||||||
getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
|
|
||||||
return CC_Default;
|
|
||||||
return CC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
|
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
|
||||||
|
|
|
@ -915,7 +915,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
|
||||||
|
|
||||||
void setCallingConv(CallingConv CC) {
|
void setCallingConv(CallingConv CC) {
|
||||||
switch (CC) {
|
switch (CC) {
|
||||||
case CC_Default: return;
|
|
||||||
case CC_C: return set("cc", "cdecl");
|
case CC_C: return set("cc", "cdecl");
|
||||||
case CC_X86FastCall: return set("cc", "x86_fastcall");
|
case CC_X86FastCall: return set("cc", "x86_fastcall");
|
||||||
case CC_X86StdCall: return set("cc", "x86_stdcall");
|
case CC_X86StdCall: return set("cc", "x86_stdcall");
|
||||||
|
|
|
@ -196,8 +196,10 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
|
||||||
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
|
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
|
||||||
PseudoDestructorTypeStorage DestroyedType)
|
PseudoDestructorTypeStorage DestroyedType)
|
||||||
: Expr(CXXPseudoDestructorExprClass,
|
: Expr(CXXPseudoDestructorExprClass,
|
||||||
Context.getPointerType(Context.getFunctionType(Context.VoidTy, None,
|
Context.getPointerType(Context.getFunctionType(
|
||||||
FunctionProtoType::ExtProtoInfo())),
|
Context.VoidTy, None,
|
||||||
|
FunctionProtoType::ExtProtoInfo(
|
||||||
|
Context.getDefaultCallingConvention(false, true)))),
|
||||||
VK_RValue, OK_Ordinary,
|
VK_RValue, OK_Ordinary,
|
||||||
/*isTypeDependent=*/(Base->isTypeDependent() ||
|
/*isTypeDependent=*/(Base->isTypeDependent() ||
|
||||||
(DestroyedType.getTypeSourceInfo() &&
|
(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
|
// that they could be in a DLL and somebody from another module could call
|
||||||
// them.)
|
// them.)
|
||||||
CallingConv CC = T->getCallConv();
|
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) {
|
switch (CC) {
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Unsupported CC for mangling");
|
llvm_unreachable("Unsupported CC for mangling");
|
||||||
case CC_Default:
|
|
||||||
case CC_C: Out << 'A'; break;
|
case CC_C: Out << 'A'; break;
|
||||||
case CC_X86Pascal: Out << 'C'; break;
|
case CC_X86Pascal: Out << 'C'; break;
|
||||||
case CC_X86ThisCall: Out << 'E'; break;
|
case CC_X86ThisCall: Out << 'E'; break;
|
||||||
|
|
|
@ -338,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const {
|
||||||
return getAsSugar<TemplateSpecializationType>(this);
|
return getAsSugar<TemplateSpecializationType>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> const AttributedType *Type::getAs() const {
|
||||||
|
return getAsSugar<AttributedType>(this);
|
||||||
|
}
|
||||||
|
|
||||||
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
|
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
|
||||||
/// sugar off the given type. This should produce an object of the
|
/// sugar off the given type. This should produce an object of the
|
||||||
/// same dynamic type as the canonical type.
|
/// same dynamic type as the canonical type.
|
||||||
|
@ -1559,9 +1563,6 @@ QualType QualType::getNonLValueExprType(const ASTContext &Context) const {
|
||||||
|
|
||||||
StringRef FunctionType::getNameForCallConv(CallingConv CC) {
|
StringRef FunctionType::getNameForCallConv(CallingConv CC) {
|
||||||
switch (CC) {
|
switch (CC) {
|
||||||
case CC_Default:
|
|
||||||
llvm_unreachable("no name for default cc");
|
|
||||||
|
|
||||||
case CC_C: return "cdecl";
|
case CC_C: return "cdecl";
|
||||||
case CC_X86StdCall: return "stdcall";
|
case CC_X86StdCall: return "stdcall";
|
||||||
case CC_X86FastCall: return "fastcall";
|
case CC_X86FastCall: return "fastcall";
|
||||||
|
|
|
@ -634,9 +634,14 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
|
||||||
|
|
||||||
if (!InsideCCAttribute) {
|
if (!InsideCCAttribute) {
|
||||||
switch (Info.getCC()) {
|
switch (Info.getCC()) {
|
||||||
case CC_Default: break;
|
|
||||||
case CC_C:
|
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;
|
break;
|
||||||
case CC_X86StdCall:
|
case CC_X86StdCall:
|
||||||
OS << " __attribute__((stdcall))";
|
OS << " __attribute__((stdcall))";
|
||||||
|
@ -1152,6 +1157,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||||
}
|
}
|
||||||
|
|
||||||
case AttributedType::attr_regparm: {
|
case AttributedType::attr_regparm: {
|
||||||
|
// FIXME: When Sema learns to form this AttributedType, avoid printing the
|
||||||
|
// attribute again in printFunctionProtoAfter.
|
||||||
OS << "regparm(";
|
OS << "regparm(";
|
||||||
QualType t = T->getEquivalentType();
|
QualType t = T->getEquivalentType();
|
||||||
while (!t->isFunctionType())
|
while (!t->isFunctionType())
|
||||||
|
@ -1191,13 +1198,17 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||||
OS << ')';
|
OS << ')';
|
||||||
break;
|
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_noreturn: OS << "noreturn"; break;
|
||||||
|
|
||||||
case AttributedType::attr_cdecl: OS << "cdecl"; break;
|
case AttributedType::attr_cdecl: OS << "cdecl"; break;
|
||||||
case AttributedType::attr_fastcall: OS << "fastcall"; break;
|
case AttributedType::attr_fastcall: OS << "fastcall"; break;
|
||||||
case AttributedType::attr_stdcall: OS << "stdcall"; break;
|
case AttributedType::attr_stdcall: OS << "stdcall"; break;
|
||||||
case AttributedType::attr_thiscall: OS << "thiscall"; break;
|
case AttributedType::attr_thiscall: OS << "thiscall"; break;
|
||||||
case AttributedType::attr_pascal: OS << "pascal"; break;
|
case AttributedType::attr_pascal: OS << "pascal"; break;
|
||||||
case AttributedType::attr_pcs: {
|
case AttributedType::attr_pcs:
|
||||||
|
case AttributedType::attr_pcs_vfp: {
|
||||||
OS << "pcs(";
|
OS << "pcs(";
|
||||||
QualType t = T->getEquivalentType();
|
QualType t = T->getEquivalentType();
|
||||||
while (!t->isFunctionType())
|
while (!t->isFunctionType())
|
||||||
|
|
|
@ -3094,9 +3094,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
|
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
|
||||||
return (CC == CC_Default ||
|
return (CC == CC_C || CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
|
||||||
CC == CC_C ||
|
|
||||||
CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
|
virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
|
||||||
|
|
|
@ -103,24 +103,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
|
||||||
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo());
|
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.
|
/// Arrange the argument and result information for a free function (i.e.
|
||||||
/// not a C++ or ObjC instance method) of the given type.
|
/// not a C++ or ObjC instance method) of the given type.
|
||||||
static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
|
static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
|
||||||
SmallVectorImpl<CanQualType> &prefix,
|
SmallVectorImpl<CanQualType> &prefix,
|
||||||
CanQual<FunctionProtoType> FTP) {
|
CanQual<FunctionProtoType> FTP) {
|
||||||
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
||||||
adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic());
|
|
||||||
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
|
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +211,6 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
|
||||||
argTypes.push_back(FTP->getArgType(i));
|
argTypes.push_back(FTP->getArgType(i));
|
||||||
|
|
||||||
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
||||||
adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic());
|
|
||||||
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
|
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +234,6 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
|
||||||
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
|
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
|
||||||
|
|
||||||
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
|
||||||
adjustCXXMethodInfo(*this, extInfo, false);
|
|
||||||
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
|
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
|
||||||
RequiredArgs::All);
|
RequiredArgs::All);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +392,6 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
|
||||||
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
|
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
|
||||||
|
|
||||||
FunctionType::ExtInfo info = FPT->getExtInfo();
|
FunctionType::ExtInfo info = FPT->getExtInfo();
|
||||||
adjustCXXMethodInfo(*this, info, FPT->isVariadic());
|
|
||||||
return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
|
return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
|
||||||
argTypes, info, required);
|
argTypes, info, required);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1262,7 +1262,7 @@ public:
|
||||||
// that when AVX types are involved: the ABI explicitly states it is
|
// 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
|
// undefined, and it doesn't work in practice because of how the ABI
|
||||||
// defines varargs anyway.
|
// defines varargs anyway.
|
||||||
if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) {
|
if (fnType->getCallConv() == CC_C) {
|
||||||
bool HasAVXType = false;
|
bool HasAVXType = false;
|
||||||
for (CallArgList::const_iterator
|
for (CallArgList::const_iterator
|
||||||
it = args.begin(), ie = args.end(); it != ie; ++it) {
|
it = args.begin(), ie = args.end(); it != ie; ++it) {
|
||||||
|
|
|
@ -2201,17 +2201,11 @@ static bool canRedefineFunction(const FunctionDecl *FD,
|
||||||
FD->getStorageClass() == SC_Extern);
|
FD->getStorageClass() == SC_Extern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the given calling convention the ABI default for the given
|
const AttributedType *Sema::getCallingConvAttributedType(QualType T) const {
|
||||||
/// declaration?
|
const AttributedType *AT = T->getAs<AttributedType>();
|
||||||
static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
|
while (AT && !AT->isCallingConv())
|
||||||
CallingConv ABIDefaultCC;
|
AT = AT->getModifiedType()->getAs<AttributedType>();
|
||||||
if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
|
return AT;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -2287,9 +2281,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
|
||||||
else
|
else
|
||||||
PrevDiag = diag::note_previous_declaration;
|
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
|
// Don't complain about this if we're in GNU89 mode and the old function
|
||||||
// is an extern inline function.
|
// is an extern inline function.
|
||||||
// Don't complain about specializations. They are not supposed to have
|
// Don't complain about specializations. They are not supposed to have
|
||||||
|
@ -2309,53 +2300,52 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a function is first declared with a calling convention, but is
|
|
||||||
// later declared or defined without one, the second decl assumes the
|
// If a function is first declared with a calling convention, but is later
|
||||||
// calling convention of the first.
|
// 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,
|
// It's OK if a function is first declared without a calling convention,
|
||||||
// but is later declared or defined with the default 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
|
// To test if either decl has an explicit calling convention, we look for
|
||||||
// difference between a function that really doesn't have a calling
|
// AttributedType sugar nodes on the type as written. If they are missing or
|
||||||
// convention and one that is declared cdecl. That's because in
|
// were canonicalized away, we assume the calling convention was implicit.
|
||||||
// canonicalization (see ASTContext.cpp), cdecl is canonicalized away
|
|
||||||
// because it is the default calling convention.
|
|
||||||
//
|
//
|
||||||
// Note also that we DO NOT return at this point, because we still have
|
// Note also that we DO NOT return at this point, because we still have
|
||||||
// other tests to run.
|
// other tests to run.
|
||||||
|
QualType OldQType = Context.getCanonicalType(Old->getType());
|
||||||
|
QualType NewQType = Context.getCanonicalType(New->getType());
|
||||||
const FunctionType *OldType = cast<FunctionType>(OldQType);
|
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 OldTypeInfo = OldType->getExtInfo();
|
||||||
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
|
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
|
||||||
bool RequiresAdjustment = false;
|
bool RequiresAdjustment = false;
|
||||||
if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) {
|
|
||||||
// Fast path: nothing to do.
|
|
||||||
|
|
||||||
// Inherit the CC from the previous declaration if it was specified
|
if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) {
|
||||||
// there but not here.
|
FunctionDecl *First = Old->getFirstDeclaration();
|
||||||
} else if (NewTypeInfo.getCC() == CC_Default) {
|
const FunctionType *FT =
|
||||||
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
|
First->getType().getCanonicalType()->castAs<FunctionType>();
|
||||||
RequiresAdjustment = true;
|
FunctionType::ExtInfo FI = FT->getExtInfo();
|
||||||
|
bool NewCCExplicit = getCallingConvAttributedType(New->getType());
|
||||||
|
if (!NewCCExplicit) {
|
||||||
|
// Inherit the CC from the previous declaration if it was specified
|
||||||
|
// there but not here.
|
||||||
|
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
|
||||||
|
RequiresAdjustment = true;
|
||||||
|
} else {
|
||||||
|
// Calling conventions aren't compatible, so complain.
|
||||||
|
bool FirstCCExplicit = getCallingConvAttributedType(First->getType());
|
||||||
|
Diag(New->getLocation(), diag::err_cconv_change)
|
||||||
|
<< FunctionType::getNameForCallConv(NewTypeInfo.getCC())
|
||||||
|
<< !FirstCCExplicit
|
||||||
|
<< (!FirstCCExplicit ? "" :
|
||||||
|
FunctionType::getNameForCallConv(FI.getCC()));
|
||||||
|
|
||||||
// Don't complain about mismatches when the default CC is
|
// Put the note on the first decl, since it is the one that matters.
|
||||||
// effectively the same as the explict one. Only Old decl contains correct
|
Diag(First->getLocation(), diag::note_previous_declaration);
|
||||||
// information about storage class of CXXMethod.
|
return true;
|
||||||
} else if (OldTypeInfo.getCC() == CC_Default &&
|
}
|
||||||
isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) {
|
|
||||||
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
|
|
||||||
RequiresAdjustment = true;
|
|
||||||
|
|
||||||
} else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
|
|
||||||
NewTypeInfo.getCC())) {
|
|
||||||
// Calling conventions really aren't compatible, so complain.
|
|
||||||
Diag(New->getLocation(), diag::err_cconv_change)
|
|
||||||
<< FunctionType::getNameForCallConv(NewTypeInfo.getCC())
|
|
||||||
<< (OldTypeInfo.getCC() == CC_Default)
|
|
||||||
<< (OldTypeInfo.getCC() == CC_Default ? "" :
|
|
||||||
FunctionType::getNameForCallConv(OldTypeInfo.getCC()));
|
|
||||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: diagnose the other way around?
|
// FIXME: diagnose the other way around?
|
||||||
|
@ -6463,6 +6453,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
diag::err_invalid_thread)
|
diag::err_invalid_thread)
|
||||||
<< DeclSpec::getSpecifierName(TSCS);
|
<< DeclSpec::getSpecifierName(TSCS);
|
||||||
|
|
||||||
|
if (DC->isRecord() &&
|
||||||
|
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
|
||||||
|
!D.getDeclSpec().isFriendSpecified())
|
||||||
|
adjustMemberFunctionCC(R);
|
||||||
|
|
||||||
bool isFriend = false;
|
bool isFriend = false;
|
||||||
FunctionTemplateDecl *FunctionTemplate = 0;
|
FunctionTemplateDecl *FunctionTemplate = 0;
|
||||||
bool isExplicitSpecialization = false;
|
bool isExplicitSpecialization = false;
|
||||||
|
@ -7144,7 +7139,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
|
|
||||||
// Turn this into a variadic function with no parameters.
|
// Turn this into a variadic function with no parameters.
|
||||||
const FunctionType *FT = NewFD->getType()->getAs<FunctionType>();
|
const FunctionType *FT = NewFD->getType()->getAs<FunctionType>();
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI(
|
||||||
|
Context.getDefaultCallingConvention(true, false));
|
||||||
EPI.Variadic = true;
|
EPI.Variadic = true;
|
||||||
EPI.ExtInfo = FT->getExtInfo();
|
EPI.ExtInfo = FT->getExtInfo();
|
||||||
|
|
||||||
|
|
|
@ -4435,6 +4435,21 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
|
||||||
FPT->getArgTypes(), EPI));
|
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) {
|
void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
|
||||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||||
if (FPT->getExceptionSpecType() != EST_Unevaluated)
|
if (FPT->getExceptionSpecType() != EST_Unevaluated)
|
||||||
|
@ -4631,7 +4646,9 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
||||||
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
|
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
|
||||||
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
|
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
|
||||||
// Compute the implicit exception specification.
|
// 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);
|
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
|
||||||
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
|
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
|
||||||
Context.getFunctionType(Context.VoidTy, None, EPI));
|
Context.getFunctionType(Context.VoidTy, None, EPI));
|
||||||
|
@ -7891,9 +7908,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
|
||||||
DefaultCon->setImplicit();
|
DefaultCon->setImplicit();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this constructor.
|
// Build an exception specification pointing back at this constructor.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon);
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
|
||||||
EPI.ExceptionSpecDecl = DefaultCon;
|
|
||||||
DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
|
DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
|
||||||
|
|
||||||
// We don't need to use SpecialMemberIsTrivial here; triviality for default
|
// We don't need to use SpecialMemberIsTrivial here; triviality for default
|
||||||
|
@ -8355,9 +8370,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
|
||||||
Destructor->setImplicit();
|
Destructor->setImplicit();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this destructor.
|
// Build an exception specification pointing back at this destructor.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
|
||||||
EPI.ExceptionSpecDecl = Destructor;
|
|
||||||
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
|
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
|
||||||
|
|
||||||
AddOverriddenMethods(ClassDecl, Destructor);
|
AddOverriddenMethods(ClassDecl, Destructor);
|
||||||
|
@ -8861,9 +8874,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
|
||||||
CopyAssignment->setImplicit();
|
CopyAssignment->setImplicit();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this member.
|
// Build an exception specification pointing back at this member.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI =
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
getImplicitMethodEPI(*this, CopyAssignment);
|
||||||
EPI.ExceptionSpecDecl = CopyAssignment;
|
|
||||||
CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
|
CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
|
||||||
|
|
||||||
// Add the parameter to the operator.
|
// Add the parameter to the operator.
|
||||||
|
@ -9375,9 +9387,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
|
||||||
MoveAssignment->setImplicit();
|
MoveAssignment->setImplicit();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this member.
|
// Build an exception specification pointing back at this member.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI =
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
getImplicitMethodEPI(*this, MoveAssignment);
|
||||||
EPI.ExceptionSpecDecl = MoveAssignment;
|
|
||||||
MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
|
MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
|
||||||
|
|
||||||
// Add the parameter to the operator.
|
// Add the parameter to the operator.
|
||||||
|
@ -9732,9 +9743,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
||||||
CopyConstructor->setDefaulted();
|
CopyConstructor->setDefaulted();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this member.
|
// Build an exception specification pointing back at this member.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI =
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
getImplicitMethodEPI(*this, CopyConstructor);
|
||||||
EPI.ExceptionSpecDecl = CopyConstructor;
|
|
||||||
CopyConstructor->setType(
|
CopyConstructor->setType(
|
||||||
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
|
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
|
||||||
|
|
||||||
|
@ -9922,9 +9932,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
|
||||||
MoveConstructor->setDefaulted();
|
MoveConstructor->setDefaulted();
|
||||||
|
|
||||||
// Build an exception specification pointing back at this member.
|
// Build an exception specification pointing back at this member.
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI =
|
||||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
getImplicitMethodEPI(*this, MoveConstructor);
|
||||||
EPI.ExceptionSpecDecl = MoveConstructor;
|
|
||||||
MoveConstructor->setType(
|
MoveConstructor->setType(
|
||||||
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
|
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
|
||||||
|
|
||||||
|
@ -11646,27 +11655,11 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
|
||||||
if (NewCC == OldCC)
|
if (NewCC == OldCC)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If either of the calling conventions are set to "default", we need to pick
|
Diag(New->getLocation(),
|
||||||
// something more sensible based on the target. This supports code where the
|
diag::err_conflicting_overriding_cc_attributes)
|
||||||
// one method explicitly sets thiscall, and another has no explicit calling
|
<< New->getDeclName() << New->getType() << Old->getType();
|
||||||
// convention.
|
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
|
||||||
CallingConv Default =
|
return true;
|
||||||
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,
|
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
|
||||||
|
|
|
@ -539,7 +539,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
// C++11 [expr.prim.lambda]p4:
|
// C++11 [expr.prim.lambda]p4:
|
||||||
// If a lambda-expression does not include a lambda-declarator, it is as
|
// If a lambda-expression does not include a lambda-declarator, it is as
|
||||||
// if the lambda-declarator were ().
|
// if the lambda-declarator were ().
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
|
||||||
|
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
|
||||||
EPI.HasTrailingReturn = true;
|
EPI.HasTrailingReturn = true;
|
||||||
EPI.TypeQuals |= DeclSpec::TQ_const;
|
EPI.TypeQuals |= DeclSpec::TQ_const;
|
||||||
QualType MethodTy = Context.getFunctionType(Context.DependentTy, None,
|
QualType MethodTy = Context.getFunctionType(Context.DependentTy, None,
|
||||||
|
@ -819,17 +820,20 @@ static void addFunctionPointerConversion(Sema &S,
|
||||||
QualType FunctionTy;
|
QualType FunctionTy;
|
||||||
{
|
{
|
||||||
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
|
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
|
||||||
|
CallingConv CC = S.Context.getDefaultCallingConvention(
|
||||||
|
Proto->isVariadic(), /*IsCXXMethod=*/false);
|
||||||
|
ExtInfo.ExtInfo = ExtInfo.ExtInfo.withCallingConv(CC);
|
||||||
ExtInfo.TypeQuals = 0;
|
ExtInfo.TypeQuals = 0;
|
||||||
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
|
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
|
||||||
Proto->getArgTypes(), ExtInfo);
|
Proto->getArgTypes(), ExtInfo);
|
||||||
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
|
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionProtoType::ExtProtoInfo ExtInfo;
|
FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
|
||||||
|
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
|
||||||
ExtInfo.TypeQuals = Qualifiers::Const;
|
ExtInfo.TypeQuals = Qualifiers::Const;
|
||||||
QualType ConvTy =
|
QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
|
||||||
S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
|
|
||||||
|
|
||||||
SourceLocation Loc = IntroducerRange.getBegin();
|
SourceLocation Loc = IntroducerRange.getBegin();
|
||||||
DeclarationName Name
|
DeclarationName Name
|
||||||
= S.Context.DeclarationNames.getCXXConversionFunctionName(
|
= S.Context.DeclarationNames.getCXXConversionFunctionName(
|
||||||
|
@ -893,8 +897,9 @@ static void addBlockPointerConversion(Sema &S,
|
||||||
Proto->getResultType(), Proto->getArgTypes(), ExtInfo);
|
Proto->getResultType(), Proto->getArgTypes(), ExtInfo);
|
||||||
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
|
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionProtoType::ExtProtoInfo ExtInfo;
|
FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
|
||||||
|
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
|
||||||
ExtInfo.TypeQuals = Qualifiers::Const;
|
ExtInfo.TypeQuals = Qualifiers::Const;
|
||||||
QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo);
|
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.
|
// function to have, if it were to match the name given.
|
||||||
// FIXME: Calling convention!
|
// FIXME: Calling convention!
|
||||||
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
|
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
|
||||||
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default);
|
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
|
||||||
EPI.ExceptionSpecType = EST_None;
|
EPI.ExceptionSpecType = EST_None;
|
||||||
EPI.NumExceptions = 0;
|
EPI.NumExceptions = 0;
|
||||||
QualType ExpectedType
|
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());
|
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,
|
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
QualType declSpecType,
|
QualType declSpecType,
|
||||||
TypeSourceInfo *TInfo) {
|
TypeSourceInfo *TInfo) {
|
||||||
|
@ -2793,9 +2842,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
if (FTI.isAmbiguous)
|
if (FTI.isAmbiguous)
|
||||||
warnAboutAmbiguousFunction(S, D, DeclType, T);
|
warnAboutAmbiguousFunction(S, D, DeclType, T);
|
||||||
|
|
||||||
|
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
|
||||||
|
|
||||||
if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
|
if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
|
||||||
// Simple void foo(), where the incoming T is the result type.
|
// Simple void foo(), where the incoming T is the result type.
|
||||||
T = Context.getFunctionNoProtoType(T);
|
T = Context.getFunctionNoProtoType(T, EI);
|
||||||
} else {
|
} else {
|
||||||
// We allow a zero-parameter variadic function in C if the
|
// We allow a zero-parameter variadic function in C if the
|
||||||
// function is marked with the "overloadable" attribute. Scan
|
// 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);
|
S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
|
||||||
D.setInvalidType(true);
|
D.setInvalidType(true);
|
||||||
// Recover by creating a K&R-style function type.
|
// Recover by creating a K&R-style function type.
|
||||||
T = Context.getFunctionNoProtoType(T);
|
T = Context.getFunctionNoProtoType(T, EI);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
FunctionProtoType::ExtProtoInfo EPI;
|
||||||
|
EPI.ExtInfo = EI;
|
||||||
EPI.Variadic = FTI.isVariadic;
|
EPI.Variadic = FTI.isVariadic;
|
||||||
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
|
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
|
||||||
EPI.TypeQuals = FTI.TypeQuals;
|
EPI.TypeQuals = FTI.TypeQuals;
|
||||||
|
@ -4414,20 +4466,19 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
|
||||||
|
|
||||||
const FunctionType *fn = unwrapped.get();
|
const FunctionType *fn = unwrapped.get();
|
||||||
CallingConv CCOld = fn->getCallConv();
|
CallingConv CCOld = fn->getCallConv();
|
||||||
if (S.Context.getCanonicalCallConv(CC) ==
|
AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
|
||||||
S.Context.getCanonicalCallConv(CCOld)) {
|
|
||||||
FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC);
|
|
||||||
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) {
|
if (CC != CCOld) {
|
||||||
// Should we diagnose reapplications of the same convention?
|
// Error out on when there's already an attribute on the type
|
||||||
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
|
// and the CCs don't match.
|
||||||
<< FunctionType::getNameForCallConv(CC)
|
const AttributedType *AT = S.getCallingConvAttributedType(type);
|
||||||
<< FunctionType::getNameForCallConv(CCOld);
|
if (AT && AT->getAttrKind() != CCAttrKind) {
|
||||||
attr.setInvalid();
|
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||||
return true;
|
<< FunctionType::getNameForCallConv(CC)
|
||||||
|
<< FunctionType::getNameForCallConv(CCOld);
|
||||||
|
attr.setInvalid();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnose the use of X86 fastcall on varargs or unprototyped functions.
|
// Diagnose the use of X86 fastcall on varargs or unprototyped functions.
|
||||||
|
@ -4463,10 +4514,38 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
|
||||||
FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
|
FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
|
||||||
QualType Equivalent =
|
QualType Equivalent =
|
||||||
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
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;
|
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
|
/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
|
||||||
static void HandleOpenCLImageAccessAttribute(QualType& CurType,
|
static void HandleOpenCLImageAccessAttribute(QualType& CurType,
|
||||||
const AttributeList &Attr,
|
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);
|
void baz(int arg);
|
||||||
|
|
||||||
|
@ -14,4 +14,13 @@ void foo(int arg) {
|
||||||
|
|
||||||
// CHECK: declare x86_stdcallcc void @baz(i32)
|
// 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{{.*}} }
|
// 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__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
|
||||||
|
|
||||||
void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {}
|
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
|
// 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
|
// Pointers to free functions
|
||||||
void free_func_default();
|
void free_func_default(); // expected-note 2 {{previous declaration is here}}
|
||||||
void __cdecl free_func_cdecl();
|
void __cdecl free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
|
||||||
void __stdcall free_func_stdcall(); // expected-note {{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 __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 __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 __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 __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 __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 __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 __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'}}
|
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_thiscall1();
|
||||||
void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
|
void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
|
||||||
|
|
||||||
// Unless attributed, typedefs carry no calling convention and use the default
|
// Typedefs carrying the __cdecl convention are adjusted to __thiscall.
|
||||||
// based on context.
|
void_fun_t member_typedef_default; // expected-note {{previous declaration is here}}
|
||||||
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 member_typedef_cdecl; // expected-note {{previous declaration is here}}
|
cdecl_fun_t __cdecl member_typedef_cdecl2;
|
||||||
__stdcall void_fun_t member_typedef_stdcall;
|
void_fun_t __stdcall member_typedef_stdcall;
|
||||||
|
|
||||||
// Static member functions can't be __thiscall
|
// Static member functions can't be __thiscall
|
||||||
static void static_member_default1();
|
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_cdecl1();
|
||||||
static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}}
|
static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}}
|
||||||
static void __stdcall static_member_stdcall1();
|
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 __cdecl S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
|
||||||
void __thiscall S::member_default2() {}
|
void __thiscall S::member_default2() {}
|
||||||
|
|
||||||
void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
|
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 __stdcall S::member_typedef_stdcall() {}
|
||||||
|
|
||||||
void S::member_cdecl1() {}
|
void S::member_cdecl1() {}
|
||||||
|
@ -76,25 +81,18 @@ void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thi
|
||||||
void S::member_thiscall1() {}
|
void S::member_thiscall1() {}
|
||||||
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
|
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
|
||||||
|
|
||||||
void __cdecl S::static_member_default1() {}
|
void S::static_member_default1() {}
|
||||||
void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
|
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 S::static_member_cdecl1() {}
|
||||||
void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
|
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 __cdecl S::member_variadic_default(int x, ...) { (void)x; }
|
||||||
(void)x;
|
void S::member_variadic_cdecl(int x, ...) { (void)x; }
|
||||||
}
|
|
||||||
void S::member_variadic_cdecl(int x, ...) {
|
|
||||||
(void)x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cdecl S::static_member_variadic_default(int x, ...) {
|
void __cdecl S::static_member_variadic_default(int x, ...) { (void)x; }
|
||||||
(void)x;
|
void S::static_member_variadic_cdecl(int x, ...) { (void)x; }
|
||||||
}
|
|
||||||
void S::static_member_variadic_cdecl(int x, ...) {
|
|
||||||
(void)x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare a template using a calling convention.
|
// Declare a template using a calling convention.
|
||||||
template <class CharT> inline int __cdecl mystrlen(const CharT *str) {
|
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(str);
|
||||||
mystrlen(ints);
|
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 {
|
namespace PR14339 {
|
||||||
class A {
|
class A {
|
||||||
|
@ -28,6 +28,6 @@ namespace PR14339 {
|
||||||
|
|
||||||
class F : public E {
|
class F : public E {
|
||||||
public:
|
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>()) {
|
if (const FunctionType *FD = T->getAs<FunctionType>()) {
|
||||||
#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
|
#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
|
||||||
switch (FD->getCallConv()) {
|
switch (FD->getCallConv()) {
|
||||||
TCALLINGCONV(Default);
|
|
||||||
TCALLINGCONV(C);
|
TCALLINGCONV(C);
|
||||||
TCALLINGCONV(X86StdCall);
|
TCALLINGCONV(X86StdCall);
|
||||||
TCALLINGCONV(X86FastCall);
|
TCALLINGCONV(X86FastCall);
|
||||||
|
|
Loading…
Reference in New Issue