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 { @@ -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]; } 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; // Clang-Specific Attributes def warn_attribute_iboutlet : Warning< 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: 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: 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: 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);