aaron.ballman created this revision.
aaron.ballman added a reviewer: rsmith.
Calling convention attributes notionally appertain to the function type -- they
modify the mangling of the function, change the behavior of assignment
operations, etc. However, they're not currently allowed to be written in the
type position within a function declaration. This patch allows the calling
convention attributes to be written in the type position as well as the
declaration position. This also adds a new diagnostic to diagnose this as being
incompatible with GCC despite the attribute being in the `gnu` namespace. I do
not think this incompatibility is sufficient to warrant adding a `clang`
namespace for the attributes, but that is another option available to us if
there is concern over the incompatibility.
Eventually, I would like to extend this to other attributes that really should
be type attributes, such as enable_if. The calling convention attributes just
happen to be the lowest hanging fruit.
https://reviews.llvm.org/D43750
Files:
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaType.cpp
test/SemaCXX/cxx11-gnu-attrs.cpp
test/SemaCXX/type-attrs.cpp
utils/TableGen/ClangAttrEmitter.cpp
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2068,7 +2068,8 @@
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;
@@ -3437,7 +3438,9 @@
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);
Index: test/SemaCXX/type-attrs.cpp
===================================================================
--- test/SemaCXX/type-attrs.cpp
+++ test/SemaCXX/type-attrs.cpp
@@ -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}}
Index: test/SemaCXX/cxx11-gnu-attrs.cpp
===================================================================
--- test/SemaCXX/cxx11-gnu-attrs.cpp
+++ test/SemaCXX/cxx11-gnu-attrs.cpp
@@ -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 @@
// 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}}
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -7142,14 +7142,19 @@
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
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3310,6 +3310,9 @@
"%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<
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -484,6 +484,11 @@
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> {
@@ -750,7 +755,7 @@
let Documentation = [CarriesDependencyDocs];
}
-def CDecl : InheritableAttr {
+def CDecl : DeclOrTypeAttr {
let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
@@ -1050,14 +1055,14 @@
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];
}
@@ -1189,7 +1194,7 @@
let Documentation = [Undocumented];
}
-def MSABI : InheritableAttr {
+def MSABI : DeclOrTypeAttr {
let Spellings = [GCC<"ms_abi">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [MSABIDocs];
@@ -1672,13 +1677,13 @@
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"],
@@ -1781,13 +1786,13 @@
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];
@@ -1814,38 +1819,38 @@
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];
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits