r221991 - Complete support for the SD-6 standing document (based off N4200) with support for __has_cpp_attribute.
Aaron Ballman
aaron at aaronballman.com
Fri Nov 14 05:44:03 PST 2014
Author: aaronballman
Date: Fri Nov 14 07:44:02 2014
New Revision: 221991
URL: http://llvm.org/viewvc/llvm-project?rev=221991&view=rev
Log:
Complete support for the SD-6 standing document (based off N4200) with support for __has_cpp_attribute.
Added:
cfe/trunk/test/Preprocessor/has_attribute.cpp
Modified:
cfe/trunk/docs/LanguageExtensions.rst
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/Attributes.h
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Basic/Attributes.cpp
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Fri Nov 14 07:44:02 2014
@@ -109,6 +109,36 @@ following ``__`` (double underscore) to
the same name. For instance, ``__cxx_rvalue_references__`` can be used instead
of ``cxx_rvalue_references``.
+``__has_cpp_attribute``
+-------------------
+
+This function-like macro takes a single argument that is the name of a
+C++11-style attribute. The argument can either be a single identifier, or a
+scoped identifier. If the attribute is supported, a nonzero value is returned.
+If the attribute is a standards-based attribute, this macro returns a nonzero
+value based on the year and month in which the attribute was voted into the
+working draft. If the attribute is not supported by the current compliation
+target, this macro evaluates to 0. It can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_cpp_attribute // Optional of course.
+ #define __has_cpp_attribute(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_cpp_attribute(clang::fallthrough)
+ #define FALLTHROUGH [[clang::fallthrough]]
+ #else
+ #define FALLTHROUGH
+ #endif
+ ...
+
+The attribute identifier (but not scope) can also be specified with a preceding
+and following ``__`` (double underscore) to avoid interference from a macro with
+the same name. For instance, ``gnu::__const__`` can be used instead of
+``gnu::const``.
+
``__has_attribute``
-------------------
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Nov 14 07:44:02 2014
@@ -186,10 +186,11 @@ class Spelling<string name, string varie
class GNU<string name> : Spelling<name, "GNU">;
class Declspec<string name> : Spelling<name, "Declspec">;
-class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
+class CXX11<string namespace, string name, int version = 1>
+ : Spelling<name, "CXX11"> {
string Namespace = namespace;
-}
-class Keyword<string name> : Spelling<name, "Keyword">;
+ int Version = version;
+} class Keyword<string name> : Spelling<name, "Keyword">;
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
string Namespace = namespace;
}
@@ -452,7 +453,8 @@ def Bounded : IgnoredAttr {
}
def CarriesDependency : InheritableParamAttr {
- let Spellings = [GNU<"carries_dependency">, CXX11<"","carries_dependency">];
+ let Spellings = [GNU<"carries_dependency">,
+ CXX11<"","carries_dependency", 200809>];
let Subjects = SubjectList<[ParmVar, ObjCMethod, Function], ErrorDiag>;
let Documentation = [CarriesDependencyDocs];
}
@@ -593,7 +595,7 @@ def C11NoReturn : InheritableAttr {
}
def CXX11NoReturn : InheritableAttr {
- let Spellings = [CXX11<"","noreturn">];
+ let Spellings = [CXX11<"","noreturn", 200809>];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [CXX11NoReturnDocs];
}
@@ -642,7 +644,7 @@ def OpenCLConstantAddressSpace : TypeAtt
def Deprecated : InheritableAttr {
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
- CXX11<"","deprecated">];
+ CXX11<"","deprecated", 201309>];
let Args = [StringArgument<"Message", 1>];
let Documentation = [Undocumented];
}
Modified: cfe/trunk/include/clang/Basic/Attributes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attributes.h?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attributes.h (original)
+++ cfe/trunk/include/clang/Basic/Attributes.h Fri Nov 14 07:44:02 2014
@@ -30,11 +30,11 @@ enum class AttrSyntax {
Pragma
};
-/// \brief Return true if we recognize and implement the attribute specified by
-/// the given information.
-bool hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
- const IdentifierInfo *Attr, const llvm::Triple &T,
- const LangOptions &LangOpts);
+/// \brief Return the version number associated with the attribute if we
+/// recognize and implement the attribute specified by the given information.
+int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
+ const IdentifierInfo *Attr, const llvm::Triple &T,
+ const LangOptions &LangOpts);
} // end namespace clang
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Nov 14 07:44:02 2014
@@ -135,6 +135,7 @@ class Preprocessor : public RefCountedBa
IdentifierInfo *Ident__is_identifier; // __is_identifier
IdentifierInfo *Ident__building_module; // __building_module
IdentifierInfo *Ident__MODULE__; // __MODULE__
+ IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute
SourceLocation DATELoc, TIMELoc;
unsigned CounterValue; // Next __COUNTER__ value.
Modified: cfe/trunk/lib/Basic/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Attributes.cpp?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Attributes.cpp (original)
+++ cfe/trunk/lib/Basic/Attributes.cpp Fri Nov 14 07:44:02 2014
@@ -3,7 +3,7 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
-bool clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
+int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
const IdentifierInfo *Attr, const llvm::Triple &T,
const LangOptions &LangOpts) {
StringRef Name = Attr->getName();
@@ -13,5 +13,5 @@ bool clang::hasAttribute(AttrSyntax Synt
#include "clang/Basic/AttrHasAttributeImpl.inc"
- return false;
+ return 0;
}
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Fri Nov 14 07:44:02 2014
@@ -96,6 +96,9 @@ void Preprocessor::RegisterBuiltinMacros
Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma");
+ // C++ Standing Document Extensions.
+ Ident__has_cpp_attribute = RegisterBuiltinMacro(*this, "__has_cpp_attribute");
+
// GCC Extensions.
Ident__BASE_FILE__ = RegisterBuiltinMacro(*this, "__BASE_FILE__");
Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
@@ -1374,12 +1377,14 @@ void Preprocessor::ExpandBuiltinMacro(To
II == Ident__has_extension ||
II == Ident__has_builtin ||
II == Ident__is_identifier ||
- II == Ident__has_attribute) {
+ II == Ident__has_attribute ||
+ II == Ident__has_cpp_attribute) {
// The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
bool IsValid = false;
IdentifierInfo *FeatureII = nullptr;
+ IdentifierInfo *ScopeII = nullptr;
// Read the '('.
LexUnexpandedToken(Tok);
@@ -1387,14 +1392,26 @@ void Preprocessor::ExpandBuiltinMacro(To
// Read the identifier
LexUnexpandedToken(Tok);
if ((FeatureII = Tok.getIdentifierInfo())) {
- // Read the ')'.
+ // If we're checking __has_cpp_attribute, it is possible to receive a
+ // scope token. Read the "::", if it's available.
LexUnexpandedToken(Tok);
- if (Tok.is(tok::r_paren))
+ bool IsScopeValid = true;
+ if (II == Ident__has_cpp_attribute && Tok.is(tok::coloncolon)) {
+ LexUnexpandedToken(Tok);
+ // The first thing we read was not the feature, it was the scope.
+ ScopeII = FeatureII;
+ if (FeatureII = Tok.getIdentifierInfo())
+ LexUnexpandedToken(Tok);
+ else
+ IsScopeValid = false;
+ }
+ // Read the closing paren.
+ if (IsScopeValid && Tok.is(tok::r_paren))
IsValid = true;
}
}
- bool Value = false;
+ int Value = 0;
if (!IsValid)
Diag(StartLoc, diag::err_feature_check_malformed);
else if (II == Ident__is_identifier)
@@ -1405,6 +1422,9 @@ void Preprocessor::ExpandBuiltinMacro(To
} else if (II == Ident__has_attribute)
Value = hasAttribute(AttrSyntax::Generic, nullptr, FeatureII,
getTargetInfo().getTriple(), getLangOpts());
+ else if (II == Ident__has_cpp_attribute)
+ Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
+ getTargetInfo().getTriple(), getLangOpts());
else if (II == Ident__has_extension)
Value = HasExtension(*this, FeatureII);
else {
@@ -1412,7 +1432,7 @@ void Preprocessor::ExpandBuiltinMacro(To
Value = HasFeature(*this, FeatureII);
}
- OS << (int)Value;
+ OS << Value;
if (IsValid)
Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_include ||
Added: cfe/trunk/test/Preprocessor/has_attribute.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/has_attribute.cpp?rev=221991&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/has_attribute.cpp (added)
+++ cfe/trunk/test/Preprocessor/has_attribute.cpp Fri Nov 14 07:44:02 2014
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -E %s -o - | FileCheck %s
+
+// CHECK: has_cxx11_carries_dep
+#if __has_cpp_attribute(carries_dependency)
+ int has_cxx11_carries_dep();
+#endif
+
+// CHECK: has_clang_fallthrough
+#if __has_cpp_attribute(clang::fallthrough)
+ int has_clang_fallthrough();
+#endif
+
+// CHECK: does_not_have_selectany
+#if !__has_cpp_attribute(selectany)
+ int does_not_have_selectany();
+#endif
+
+// The attribute name can be bracketed with double underscores.
+// CHECK: has_clang_fallthrough_2
+#if __has_cpp_attribute(clang::__fallthrough__)
+ int has_clang_fallthrough_2();
+#endif
+
+// The scope cannot be bracketed with double underscores.
+// CHECK: does_not_have___clang___fallthrough
+#if !__has_cpp_attribute(__clang__::fallthrough)
+ int does_not_have___clang___fallthrough();
+#endif
+
+// Test that C++11, target-specific attributes behave properly.
+
+// CHECK: does_not_have_mips16
+#if !__has_cpp_attribute(gnu::mips16)
+ int does_not_have_mips16();
+#endif
+
+// Test that the version numbers of attributes listed in SD-6 are supported
+// correctly.
+
+// CHECK: has_cxx11_carries_dep_vers
+#if __has_cpp_attribute(carries_dependency) == 200809
+ int has_cxx11_carries_dep_vers();
+#endif
+
+// CHECK: has_cxx11_noreturn_vers
+#if __has_cpp_attribute(noreturn) == 200809
+ int has_cxx11_noreturn_vers();
+#endif
+
+// CHECK: has_cxx14_deprecated_vers
+#if __has_cpp_attribute(deprecated) == 201309
+ int has_cxx14_deprecated_vers();
+#endif
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Nov 14 07:44:02 2014
@@ -1820,6 +1820,27 @@ static void GenerateHasAttrSpellingStrin
const std::vector<Record *> &Attrs, raw_ostream &OS,
const std::string &Variety = "", const std::string &Scope = "") {
for (const auto *Attr : Attrs) {
+ // C++11-style attributes have specific version information associated with
+ // them. If the attribute has no scope, the version information must not
+ // have the default value (1), as that's incorrect. Instead, the unscoped
+ // attribute version information should be taken from the SD-6 standing
+ // document, which can be found at:
+ // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
+ int Version = 1;
+
+ if (Variety == "CXX11") {
+ std::vector<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings");
+ for (const auto &Spelling : Spellings) {
+ if (Spelling->getValueAsString("Variety") == "CXX11") {
+ Version = static_cast<int>(Spelling->getValueAsInt("Version"));
+ if (Scope.empty() && Version == 1)
+ PrintError(Spelling->getLoc(), "C++ standard attributes must "
+ "have valid version information.");
+ break;
+ }
+ }
+ }
+
// It is assumed that there will be an llvm::Triple object named T within
// scope that can be used to determine whether the attribute exists in
// a given target.
@@ -1858,16 +1879,16 @@ static void GenerateHasAttrSpellingStrin
// C++11 mode should be checked against LangOpts, which is presumed to be
// present in the caller.
Test = "LangOpts.CPlusPlus11";
- else
- Test = "true";
+ std::string TestStr =
+ !Test.empty() ? Test + " ? " + std::to_string(Version) + " : 0" : "1";
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
for (const auto &S : Spellings)
if (Variety.empty() || (Variety == S.variety() &&
(Scope.empty() || Scope == S.nameSpace())))
- OS << " .Case(\"" << S.name() << "\", " << Test << ")\n";
+ OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n";
}
- OS << " .Default(false);\n";
+ OS << " .Default(0);\n";
}
// Emits the list of spellings for attributes.
@@ -1899,16 +1920,16 @@ void EmitClangAttrHasAttrImpl(RecordKeep
OS << "switch (Syntax) {\n";
OS << "case AttrSyntax::Generic:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Attrs, OS);
OS << "case AttrSyntax::GNU:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU");
OS << "case AttrSyntax::Declspec:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
OS << "case AttrSyntax::Pragma:\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
OS << "case AttrSyntax::CXX: {\n";
// C++11-style attributes are further split out based on the Scope.
@@ -1921,7 +1942,7 @@ void EmitClangAttrHasAttrImpl(RecordKeep
OS << "if (!Scope || Scope->getName() == \"\") {\n";
else
OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
- OS << " return llvm::StringSwitch<bool>(Name)\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
OS << "}";
}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=221991&r1=221990&r2=221991&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri Nov 14 07:44:02 2014
@@ -590,8 +590,8 @@ Clang version they became available:</p>
</td>
</tr>
<tr>
- <td class="partial" align="center">
- SVN (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4200">N4200</a>): Partial <a href="#n4200">(1)</a>
+ <td class="full" align="center">
+ SVN (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4200">N4200</a>)</a>
</td>
</tr>
<tr>
@@ -611,10 +611,6 @@ Clang version they became available:</p>
</tr>
</table>
-<p>
-<span id="n4200">(1): <code>__has_cpp_attribute</code> is not yet supported.</span>
-</p>
-
</div>
</body>
</html>
More information about the cfe-commits
mailing list