Allow writing calling convention attributes on function types.

Calling convention attributes notionally appertain to the function type -- they modify the mangling of the function, change the behavior of assignment operations, etc. This commit allows the calling convention attributes to be written in the type position as well as the declaration position.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@331459 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Aaron Ballman 2018-05-03 15:33:50 +00:00
parent 25c97e35c2
commit db7467d886
6 changed files with 43 additions and 23 deletions

View File

@ -493,6 +493,11 @@ class InheritableAttr : Attr {
bit InheritEvenIfAlreadyPresent = 0;
}
/// Some attributes, like calling conventions, can appear in either the
/// declaration or the type position. These attributes are morally type
/// attributes, but have historically been written on declarations.
class DeclOrTypeAttr : InheritableAttr;
/// A target-specific attribute. This class is meant to be used as a mixin
/// with InheritableAttr or Attr depending on the attribute's needs.
class TargetSpecificAttr<TargetSpec target> {
@ -765,7 +770,7 @@ def CarriesDependency : InheritableParamAttr {
let Documentation = [CarriesDependencyDocs];
}
def CDecl : InheritableAttr {
def CDecl : DeclOrTypeAttr {
let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
@ -1066,14 +1071,14 @@ def FallThrough : StmtAttr {
let Documentation = [FallthroughDocs];
}
def FastCall : InheritableAttr {
def FastCall : DeclOrTypeAttr {
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
Keyword<"_fastcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [FastCallDocs];
}
def RegCall : InheritableAttr {
def RegCall : DeclOrTypeAttr {
let Spellings = [GCC<"regcall">, Keyword<"__regcall">];
let Documentation = [RegCallDocs];
}
@ -1205,7 +1210,7 @@ def MayAlias : InheritableAttr {
let Documentation = [Undocumented];
}
def MSABI : InheritableAttr {
def MSABI : DeclOrTypeAttr {
let Spellings = [GCC<"ms_abi">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [MSABIDocs];
@ -1689,13 +1694,13 @@ def Packed : InheritableAttr {
let Documentation = [Undocumented];
}
def IntelOclBicc : InheritableAttr {
def IntelOclBicc : DeclOrTypeAttr {
let Spellings = [Clang<"intel_ocl_bicc", 0>];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
}
def Pcs : InheritableAttr {
def Pcs : DeclOrTypeAttr {
let Spellings = [GCC<"pcs">];
let Args = [EnumArgument<"PCS", "PCSType",
["aapcs", "aapcs-vfp"],
@ -1798,13 +1803,13 @@ def Sentinel : InheritableAttr {
let Documentation = [Undocumented];
}
def StdCall : InheritableAttr {
def StdCall : DeclOrTypeAttr {
let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [StdCallDocs];
}
def SwiftCall : InheritableAttr {
def SwiftCall : DeclOrTypeAttr {
let Spellings = [Clang<"swiftcall">];
// let Subjects = SubjectList<[Function]>;
let Documentation = [SwiftCallDocs];
@ -1831,38 +1836,38 @@ def Suppress : StmtAttr {
let Documentation = [SuppressDocs];
}
def SysVABI : InheritableAttr {
def SysVABI : DeclOrTypeAttr {
let Spellings = [GCC<"sysv_abi">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
}
def ThisCall : InheritableAttr {
def ThisCall : DeclOrTypeAttr {
let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">,
Keyword<"_thiscall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [ThisCallDocs];
}
def VectorCall : InheritableAttr {
def VectorCall : DeclOrTypeAttr {
let Spellings = [Clang<"vectorcall">, Keyword<"__vectorcall">,
Keyword<"_vectorcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [VectorCallDocs];
}
def Pascal : InheritableAttr {
def Pascal : DeclOrTypeAttr {
let Spellings = [Clang<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
}
def PreserveMost : InheritableAttr {
def PreserveMost : DeclOrTypeAttr {
let Spellings = [Clang<"preserve_most">];
let Documentation = [PreserveMostDocs];
}
def PreserveAll : InheritableAttr {
def PreserveAll : DeclOrTypeAttr {
let Spellings = [Clang<"preserve_all">];
let Documentation = [PreserveAllDocs];
}

View File

@ -3336,6 +3336,9 @@ def err_attribute_not_supported_in_lang : Error<
"%0 attribute is not supported in %select{C|C++|Objective-C}1">;
def err_attribute_not_supported_on_arch
: Error<"%0 attribute is not supported on '%1'">;
def warn_gcc_ignores_type_attr : Warning<
"GCC does not allow the %0 attribute to be written on a type">,
InGroup<GccCompat>;
// Clang-Specific Attributes
def warn_attribute_iboutlet : Warning<

View File

@ -7185,14 +7185,19 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isCXX11Attribute()) {
// [[gnu::...]] attributes are treated as declaration attributes, so may
// not appertain to a DeclaratorChunk, even if we handle them as type
// attributes.
// not appertain to a DeclaratorChunk. If we handle them as type
// attributes, accept them in that position and diagnose the GCC
// incompatibility.
if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) {
bool IsTypeAttr = attr.isTypeAttr();
if (TAL == TAL_DeclChunk) {
state.getSema().Diag(attr.getLoc(),
diag::warn_cxx11_gnu_attribute_on_type)
IsTypeAttr
? diag::warn_gcc_ignores_type_attr
: diag::warn_cxx11_gnu_attribute_on_type)
<< attr.getName();
continue;
if (!IsTypeAttr)
continue;
}
} else if (TAL != TAL_DeclChunk) {
// Otherwise, only consider type processing for a C++11 attribute if

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -Wno-gcc-compat -verify %s
// Error cases.
@ -18,8 +18,7 @@ int *[[gnu::unused]] attr_on_ptr;
// expected-warning@-2 {{calling convention '__stdcall' ignored for this target}}
[[gnu::fastcall]] void pr17424_4() [[gnu::stdcall]];
// expected-warning@-1 {{calling convention 'fastcall' ignored for this target}}
// expected-warning@-2 {{attribute 'stdcall' ignored, because it cannot be applied to a type}}
// expected-warning@-3 {{calling convention 'stdcall' ignored for this target}}
// expected-warning@-2 {{calling convention 'stdcall' ignored for this target}}
void pr17424_5 [[gnu::fastcall]]();
// expected-warning@-1 {{calling convention 'fastcall' ignored for this target}}

View File

@ -0,0 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-pc-win32 -Wgcc-compat -std=c++11 -verify %s
void f() [[gnu::cdecl]] {} // expected-warning {{GCC does not allow the 'cdecl' attribute to be written on a type}}
void g() [[gnu::stdcall]] {} // expected-warning {{GCC does not allow the 'stdcall' attribute to be written on a type}}
void i() [[gnu::fastcall]] {} // expected-warning {{GCC does not allow the 'fastcall' attribute to be written on a type}}

View File

@ -2159,7 +2159,8 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
bool Inheritable = false;
for (const auto &Super : llvm::reverse(Supers)) {
const Record *R = Super.first;
if (R->getName() != "TargetSpecificAttr" && SuperName.empty())
if (R->getName() != "TargetSpecificAttr" &&
R->getName() != "DeclOrTypeAttr" && SuperName.empty())
SuperName = R->getName();
if (R->getName() == "InheritableAttr")
Inheritable = true;
@ -3528,7 +3529,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitArgInfo(*I->second, SS);
SS << ", " << I->second->getValueAsBit("HasCustomParsing");
SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", "
<< (I->second->isSubClassOf("TypeAttr") ||
I->second->isSubClassOf("DeclOrTypeAttr"));
SS << ", " << I->second->isSubClassOf("StmtAttr");
SS << ", " << IsKnownToGCC(*I->second);
SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second);