r300556 - Add #pragma clang attribute
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 18 07:33:40 PDT 2017
Author: arphaman
Date: Tue Apr 18 09:33:39 2017
New Revision: 300556
URL: http://llvm.org/viewvc/llvm-project?rev=300556&view=rev
Log:
Add #pragma clang attribute
This is a recommit of r300539 that was reverted in r300543 due to test failures.
The original commit message is displayed below:
The new '#pragma clang attribute' directive can be used to apply attributes to
multiple declarations. An attribute must satisfy the following conditions to
be supported by the pragma:
- It must have a subject list that's defined in the TableGen file.
- It must be documented.
- It must not be late parsed.
- It must have a GNU/C++11 spelling.
Differential Revision: https://reviews.llvm.org/D30009
Added:
cfe/trunk/include/clang/Basic/AttrSubjectMatchRules.h
cfe/trunk/test/FixIt/fixit-pragma-attribute.c
cfe/trunk/test/FixIt/fixit-pragma-attribute.cpp
cfe/trunk/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
cfe/trunk/test/Misc/pragma-attribute-cxx.cpp
cfe/trunk/test/Misc/pragma-attribute-objc-subject-match-rules.m
cfe/trunk/test/Misc/pragma-attribute-objc.m
cfe/trunk/test/Misc/pragma-attribute-strict-subjects.c
cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
cfe/trunk/test/Parser/pragma-attribute-declspec.cpp
cfe/trunk/test/Parser/pragma-attribute.cpp
cfe/trunk/test/Sema/pragma-attribute-strict-subjects.c
cfe/trunk/test/Sema/pragma-attribute.c
Modified:
cfe/trunk/docs/LanguageExtensions.rst
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/CMakeLists.txt
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Parse/CMakeLists.txt
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/AttributeList.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Basic/Attributes.cpp
cfe/trunk/lib/Parse/ParsePragma.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/AttributeList.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/SemaAttr.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/test/lit.cfg
cfe/trunk/test/lit.site.cfg.in
cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
cfe/trunk/utils/TableGen/TableGen.cpp
cfe/trunk/utils/TableGen/TableGenBackends.h
Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Tue Apr 18 09:33:39 2017
@@ -2346,3 +2346,178 @@ statements in C)
The pragma can also be used with ``off`` which turns FP contraction off for a
section of the code. This can be useful when fast contraction is otherwise
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
+
+Specifying an attribute for multiple declarations (#pragma clang attribute)
+===========================================================================
+
+The ``#pragma clang attribute`` directive can be used to apply an attribute to
+multiple declarations. The ``#pragma clang attribute push`` variation of the
+directive pushes a new attribute to the attribute stack. The declarations that
+follow the pragma receive the attributes that are on the attribute stack, until
+the stack is cleared using a ``#pragma clang attribute pop`` directive. Multiple
+push directives can be nested inside each other.
+
+The attributes that are used in the ``#pragma clang attribute`` directives
+can be written using the GNU-style syntax:
+
+.. code-block:: c++
+
+ #pragma clang attribute push(__attribute__((annotate("custom"))), apply_to = function)
+
+ void function(); // The function now has the annotate("custom") attribute
+
+ #pragma clang attribute pop
+
+The attributes can also be written using the C++11 style syntax:
+
+.. code-block:: c++
+
+ #pragma clang attribute push([[noreturn]], apply_to = function)
+
+ void function(); // The function now has the [[noreturn]] attribute
+
+ #pragma clang attribute pop
+
+The ``__declspec`` style syntax is also supported:
+
+.. code-block:: c++
+
+ #pragma clang attribute push(__declspec(dllexport), apply_to = function)
+
+ void function(); // The function now has the __declspec(dllexport) attribute
+
+ #pragma clang attribute pop
+
+A single push directive accepts only one attribute regardless of the syntax
+used.
+
+Subject Match Rules
+-------------------
+
+The set of declarations that receive a single attribute from the attribute stack
+depends on the subject match rules that were specified in the pragma. Subject
+match rules are specified after the attribute. The compiler expects an
+identifier that corresponds to the subject set specifier. The ``apply_to``
+specifier is currently the only supported subject set specifier. It allows you
+to specify match rules that form a subset of the attribute's allowed subject
+set, i.e. the compiler doesn't require all of the attribute's subjects. For
+example, an attribute like ``[[nodiscard]]`` whose subject set includes
+``enum``, ``record`` and ``hasType(functionType)``, requires the presence of at
+least one of these rules after ``apply_to``:
+
+.. code-block:: c++
+
+ #pragma clang attribute push([[nodiscard]], apply_to = enum)
+
+ enum Enum1 { A1, B1 }; // The enum will receive [[nodiscard]]
+
+ struct Record1 { }; // The struct will *not* receive [[nodiscard]]
+
+ #pragma clang attribute pop
+
+ #pragma clang attribute push([[nodiscard]], apply_to = any(record, enum))
+
+ enum Enum2 { A2, B2 }; // The enum will receive [[nodiscard]]
+
+ struct Record2 { }; // The struct *will* receive [[nodiscard]]
+
+ #pragma clang attribute pop
+
+ // This is an error, since [[nodiscard]] can't be applied to namespaces:
+ #pragma clang attribute push([[nodiscard]], apply_to = any(record, namespace))
+
+ #pragma clang attribute pop
+
+Multiple match rules can be specified using the ``any`` match rule, as shown
+in the example above. The ``any`` rule applies attributes to all declarations
+that are matched by at least one of the rules in the ``any``. It doesn't nest
+and can't be used inside the other match rules. Redundant match rules or rules
+that conflict with one another should not be used inside of ``any``.
+
+Clang supports the following match rules:
+
+- ``function``: Can be used to apply attributes to functions. This includes C++
+ member functions, static functions, operators, and constructors/destructors.
+
+- ``function(is_member)``: Can be used to apply attributes to C++ member
+ functions. This includes members like static functions, operators, and
+ constructors/destructors.
+
+- ``hasType(functionType)``: Can be used to apply attributes to functions, C++
+ member functions, and variables/fields whose type is a function pointer. It
+ does not apply attributes to Objective-C methods or blocks.
+
+- ``type_alias``: Can be used to apply attributes to ``typedef`` declarations
+ and C++11 type aliases.
+
+- ``record``: Can be used to apply attributes to ``struct``, ``class``, and
+ ``union`` declarations.
+
+- ``record(unless(is_union))``: Can be used to apply attributes only to
+ ``struct`` and ``class`` declarations.
+
+- ``enum``: Can be be used to apply attributes to enumeration declarations.
+
+- ``enum_constant``: Can be used to apply attributes to enumerators.
+
+- ``variable``: Can be used to apply attributes to variables, including
+ local variables, parameters, global variables, and static member variables.
+ It does not apply attributes to instance member variables or Objective-C
+ ivars.
+
+- ``variable(is_thread_local)``: Can be used to apply attributes to thread-local
+ variables only.
+
+- ``variable(is_global)``: Can be used to apply attributes to global variables
+ only.
+
+- ``variable(is_parameter)``: Can be used to apply attributes to parameters
+ only.
+
+- ``variable(unless(is_parameter))``: Can be used to apply attributes to all
+ the variables that are not parameters.
+
+- ``field``: Can be used to apply attributes to non-static member variables
+ in a record. This includes Objective-C ivars.
+
+- ``namespace``: Can be used to apply attributes to ``namespace`` declarations.
+
+- ``objc_interface``: Can be used to apply attributes to ``@interface``
+ declarations.
+
+- ``objc_protocol``: Can be used to apply attributes to ``@protocol``
+ declarations.
+
+- ``objc_category``: Can be used to apply attributes to category declarations,
+ including class extensions.
+
+- ``objc_method``: Can be used to apply attributes to Objective-C methods,
+ including instance and class methods. Implicit methods like implicit property
+ getters and setters do not receive the attribute.
+
+- ``objc_method(is_instance)``: Can be used to apply attributes to Objective-C
+ instance methods.
+
+- ``objc_property``: Can be used to apply attributes to ``@property``
+ declarations.
+
+- ``block``: Can be used to apply attributes to block declarations. This does
+ not include variables/fields of block pointer type.
+
+The use of ``unless`` in match rules is currently restricted to a strict set of
+sub-rules that are used by the supported attributes. That means that even though
+``variable(unless(is_parameter))`` is a valid match rule,
+``variable(unless(is_thread_local))`` is not.
+
+Supported Attributes
+--------------------
+
+Not all attributes can be used with the ``#pragma clang attribute`` directive.
+Notably, statement attributes like ``[[fallthrough]]`` or type attributes
+like ``address_space`` aren't supported by this directive. You can determine
+whether or not an attribute is supported by the pragma by referring to the
+:doc:`individual documentation for that attribute <AttributeReference>`.
+
+The attributes are applied to all matching declarations individually, even when
+the attribute is semantically incorrect. The attributes that aren't applied to
+any declaration are not verified semantically.
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Apr 18 09:33:39 2017
@@ -248,6 +248,8 @@ def COnly : LangOpt<"CPlusPlus", 1>;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
def RenderScript : LangOpt<"RenderScript">;
+def ObjC : LangOpt<"ObjC1">;
+def BlocksSupported : LangOpt<"Blocks">;
// Defines targets for target-specific attributes. The list of strings should
// specify architectures for which the target applies, based off the ArchType
@@ -270,6 +272,102 @@ def TargetMicrosoftCXXABI : TargetArch<[
let CXXABIs = ["Microsoft"];
}
+// Attribute subject match rules that are used for #pragma clang attribute.
+//
+// A instance of AttrSubjectMatcherRule represents an individual match rule.
+// An individual match rule can correspond to a number of different attribute
+// subjects, e.g. "record" matching rule corresponds to the Record and
+// CXXRecord attribute subjects.
+//
+// Match rules are used in the subject list of the #pragma clang attribute.
+// Match rules can have sub-match rules that are instances of
+// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number
+// of different attribute subjects, and it can have a negated spelling as well.
+// For example, "variable(unless(is_parameter))" matching rule corresponds to
+// the NonParmVar attribute subject.
+class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects,
+ bit negated = 0> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ bit Negated = negated;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, the language options are taken
+ // from the parent matcher rule.
+ list<LangOpt> LangOpts = [];
+}
+class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects,
+ list<AttrSubjectMatcherSubRule> subrules = []> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ list<AttrSubjectMatcherSubRule> Constraints = subrules;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, no language options are required.
+ list<LangOpt> LangOpts = [];
+}
+
+// function(is_member)
+def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [
+ SubRuleForCXXMethod
+]>;
+// hasType is abstract, it should be used with one of the sub-rules.
+def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [
+ AttrSubjectMatcherSubRule<"functionType", [FunctionLike]>
+
+ // FIXME: There's a matcher ambiguity with objc methods and blocks since
+ // functionType excludes them but functionProtoType includes them.
+ // AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]>
+]>;
+def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias",
+ [TypedefName]>;
+def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record,
+ CXXRecord], [
+ // unless(is_union)
+ AttrSubjectMatcherSubRule<"is_union", [Struct], 1>
+]>;
+def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>;
+def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant",
+ [EnumConstant]>;
+def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [
+ AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>,
+ AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>,
+ AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>,
+ // unless(is_parameter)
+ AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1>
+]>;
+def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>;
+def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace",
+ [Namespace]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface",
+ [ObjCInterface]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol",
+ [ObjCProtocol]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
+ [ObjCCategory]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
+ [ObjCMethod], [
+ AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
+]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property",
+ [ObjCProperty]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
+ let LangOpts = [BlocksSupported];
+}
+
class Attr {
// The various ways in which an attribute can be spelled in source
list<Spelling> Spellings;
@@ -305,6 +403,14 @@ class Attr {
// Set to true if this attribute meaningful when applied to or inherited
// in a class template definition.
bit MeaningfulToClassTemplateDefinition = 0;
+ // Set to true if this attribute can be used with '#pragma clang attribute'.
+ // By default, when this value is false, an attribute is supported by the
+ // '#pragma clang attribute' only when:
+ // - It has documentation.
+ // - It has a subject list whose subjects can be represented using subject
+ // match rules.
+ // - It has GNU/CXX11 spelling and doesn't require delayed parsing.
+ bit ForcePragmaAttributeSupport = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
@@ -478,6 +584,9 @@ def AnalyzerNoReturn : InheritableAttr {
def Annotate : InheritableParamAttr {
let Spellings = [GNU<"annotate">];
let Args = [StringArgument<"Annotation">];
+ // Ensure that the annotate attribute can be used with
+ // '#pragma clang attribute' even though it has no subject list.
+ let ForcePragmaAttributeSupport = 1;
let Documentation = [Undocumented];
}
Added: cfe/trunk/include/clang/Basic/AttrSubjectMatchRules.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrSubjectMatchRules.h?rev=300556&view=auto
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrSubjectMatchRules.h (added)
+++ cfe/trunk/include/clang/Basic/AttrSubjectMatchRules.h Tue Apr 18 09:33:39 2017
@@ -0,0 +1,46 @@
+//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace attr {
+
+/// \brief A list of all the recognized kinds of attributes.
+enum SubjectMatchRule {
+#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X,
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+};
+
+const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule);
+
+using ParsedSubjectMatchRuleSet = llvm::DenseMap<SubjectMatchRule, SourceRange>;
+
+} // end namespace attr
+} // end namespace clang
+
+namespace llvm {
+
+template <>
+struct DenseMapInfo<clang::attr::SubjectMatchRule> : DenseMapInfo<int> {
+ static inline clang::attr::SubjectMatchRule getEmptyKey() {
+ return (clang::attr::SubjectMatchRule)DenseMapInfo<int>::getEmptyKey();
+ }
+ static inline clang::attr::SubjectMatchRule getTombstoneKey() {
+ return (clang::attr::SubjectMatchRule)DenseMapInfo<int>::getTombstoneKey();
+ }
+};
+
+} // end namespace llvm
+
+#endif
Modified: cfe/trunk/include/clang/Basic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/CMakeLists.txt?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/Basic/CMakeLists.txt Tue Apr 18 09:33:39 2017
@@ -28,6 +28,11 @@ clang_tablegen(AttrList.inc -gen-clang-a
SOURCE Attr.td
TARGET ClangAttrList)
+clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE Attr.td
+ TARGET ClangAttrSubjectMatchRuleList)
+
clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Apr 18 09:33:39 2017
@@ -461,7 +461,9 @@ def Uninitialized : DiagGroup<"uninitia
def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
-def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>;
+def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
+def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
+ PragmaClangAttribute]>;
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Apr 18 09:33:39 2017
@@ -979,6 +979,43 @@ def err_pragma_optimize_invalid_argument
"expected 'on' or 'off'">;
def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
+// - #pragma clang attribute
+def err_pragma_attribute_expected_push_pop : Error<
+ "expected 'push' or 'pop' after '#pragma clang attribute'">;
+def err_pragma_attribute_invalid_argument : Error<
+ "unexpected argument '%0' to '#pragma clang attribute'; "
+ "expected 'push' or 'pop'">;
+def err_pragma_attribute_expected_attribute : Error<
+ "expected an attribute after '('">;
+def err_pragma_attribute_expected_attribute_name : Error<
+ "expected identifier that represents an attribute name">;
+def err_pragma_attribute_extra_tokens_after_attribute : Error<
+ "extra tokens after attribute in a '#pragma clang attribute push'">;
+def err_pragma_attribute_unsupported_attribute : Error<
+ "attribute %0 is not supported by '#pragma clang attribute'">;
+def err_pragma_attribute_multiple_attributes : Error<
+ "more than one attribute specified in '#pragma clang attribute push'">;
+def err_pragma_attribute_expected_attribute_syntax : Error<
+ "expected an attribute that is specified using the GNU, C++11 or '__declspec'"
+ " syntax">;
+def note_pragma_attribute_use_attribute_kw : Note<"use the GNU '__attribute__' "
+ "syntax">;
+def err_pragma_attribute_invalid_subject_set_specifier : Error<
+ "expected attribute subject set specifier 'apply_to'">;
+def err_pragma_attribute_expected_subject_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject rule">;
+def err_pragma_attribute_unknown_subject_rule : Error<
+ "unknown attribute subject rule '%0'">;
+def err_pragma_attribute_expected_subject_sub_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject matcher "
+ "sub-rule; '%0' matcher %select{does not support sub-rules|supports the "
+ "following sub-rules: %2|}1">;
+def err_pragma_attribute_unknown_subject_sub_rule : Error<
+ "%select{invalid use of|unknown}2 attribute subject matcher sub-rule '%0'; "
+ "'%1' matcher %select{does not support sub-rules|supports the following "
+ "sub-rules: %3}2">;
+def err_pragma_attribute_duplicate_subject : Error<
+ "duplicate attribute subject matcher '%0'">;
def err_opencl_unroll_hint_on_non_loop : Error<
"OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 18 09:33:39 2017
@@ -750,6 +750,25 @@ def err_pragma_loop_compatibility : Erro
def err_pragma_loop_precedes_nonloop : Error<
"expected a for, while, or do-while loop to follow '%0'">;
+def err_pragma_attribute_matcher_subrule_contradicts_rule : Error<
+ "redundant attribute subject matcher sub-rule '%0'; '%1' already matches "
+ "those declarations">;
+def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error<
+ "negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">;
+def err_pragma_attribute_invalid_matchers : Error<
+ "attribute %0 can't be applied to %1">;
+def err_pragma_attribute_stack_mismatch : Error<
+ "'#pragma clang attribute pop' with no matching '#pragma clang attribute push'">;
+def warn_pragma_attribute_unused : Warning<
+ "unused attribute %0 in '#pragma clang attribute push' region">,
+ InGroup<PragmaClangAttribute>;
+def note_pragma_attribute_region_ends_here : Note<
+ "'#pragma clang attribute push' regions ends here">;
+def err_pragma_attribute_no_pop_eof : Error<"unterminated "
+ "'#pragma clang attribute push' at end of file">;
+def note_pragma_attribute_applied_decl_here : Note<
+ "when applied to this declaration">;
+
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<
"duplicate interface definition for class %0">;
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Tue Apr 18 09:33:39 2017
@@ -790,6 +790,9 @@ ANNOTATION(pragma_loop_hint)
ANNOTATION(pragma_fp)
+// Annotation for the attribute pragma directives - #pragma clang attribute ...
+ANNOTATION(pragma_attribute)
+
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)
Modified: cfe/trunk/include/clang/Parse/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/CMakeLists.txt?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/Parse/CMakeLists.txt Tue Apr 18 09:33:39 2017
@@ -2,3 +2,9 @@ clang_tablegen(AttrParserStringSwitches.
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrParserStringSwitches)
+
+clang_tablegen(AttrSubMatchRulesParserStringSwitches.inc
+ -gen-clang-attr-subject-match-rules-parser-string-switches
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrSubMatchRulesParserStringSwitches)
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Apr 18 09:33:39 2017
@@ -184,6 +184,7 @@ class Parser : public CodeCompletionHand
std::unique_ptr<PragmaHandler> UnrollHintHandler;
std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
std::unique_ptr<PragmaHandler> FPHandler;
+ std::unique_ptr<PragmaHandler> AttributePragmaHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -565,6 +566,12 @@ private:
/// #pragma clang loop and #pragma unroll.
bool HandlePragmaLoopHint(LoopHint &Hint);
+ bool ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules,
+ SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc);
+
+ void HandlePragmaAttribute();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Tue Apr 18 09:33:39 2017
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/VersionTuple.h"
@@ -509,9 +510,14 @@ public:
unsigned getMaxArgs() const;
bool hasVariadicArg() const;
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
+ bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const;
+ void getMatchRules(const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>>
+ &MatchRules) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(const TargetInfo &Target) const;
bool isKnownToGCC() const;
+ bool isSupportedByPragmaAttribute() const;
/// \brief If the parsed attribute has a semantic equivalent, and it would
/// have a semantic Spelling enumeration (due to having semantically-distinct
@@ -774,6 +780,8 @@ public:
void clear() { list = nullptr; pool.clear(); }
AttributeList *getList() const { return list; }
+ void clearListOnly() { list = nullptr; }
+
/// Returns a reference to the attribute list. Try not to introduce
/// dependencies on this method, it may not be long-lived.
AttributeList *&getListRef() { return list; }
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Apr 18 09:33:39 2017
@@ -437,6 +437,20 @@ public:
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
+ /// \brief This represents the stack of attributes that were pushed by
+ /// \#pragma clang attribute.
+ struct PragmaAttributeEntry {
+ SourceLocation Loc;
+ AttributeList *Attribute;
+ SmallVector<attr::SubjectMatchRule, 4> MatchRules;
+ bool IsUsed;
+ };
+ SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack;
+
+ /// \brief The declaration that is currently receiving an attribute from the
+ /// #pragma attribute stack.
+ const Decl *PragmaAttributeCurrentTargetDecl;
+
/// \brief This represents the last location of a "#pragma clang optimize off"
/// directive if such a directive has not been closed by an "on" yet. If
/// optimizations are currently "on", this is set to an invalid location.
@@ -7206,9 +7220,13 @@ public:
PrintInstantiationStack();
LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
}
+ if (PragmaAttributeCurrentTargetDecl)
+ PrintPragmaAttributeInstantiationPoint();
}
void PrintInstantiationStack();
+ void PrintPragmaAttributeInstantiationPoint();
+
/// \brief Determines whether we are currently in a context where
/// template argument substitution failures are not considered
/// errors.
@@ -8152,6 +8170,20 @@ public:
/// the appropriate attribute.
void AddCFAuditedAttribute(Decl *D);
+ /// \brief Called on well-formed '\#pragma clang attribute push'.
+ void ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules);
+
+ /// \brief Called on well-formed '\#pragma clang attribute pop'.
+ void ActOnPragmaAttributePop(SourceLocation PragmaLoc);
+
+ /// \brief Adds the attributes that have been specified using the
+ /// '\#pragma clang attribute push' directives to the given declaration.
+ void AddPragmaAttributes(Scope *S, Decl *D);
+
+ void DiagnoseUnterminatedPragmaAttribute();
+
/// \brief Called on well formed \#pragma clang optimize.
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
Modified: cfe/trunk/lib/Basic/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Attributes.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Attributes.cpp (original)
+++ cfe/trunk/lib/Basic/Attributes.cpp Tue Apr 18 09:33:39 2017
@@ -1,4 +1,5 @@
#include "clang/Basic/Attributes.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -15,3 +16,13 @@ int clang::hasAttribute(AttrSyntax Synta
return 0;
}
+
+const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
+ switch (Rule) {
+#define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \
+ case attr::NAME: \
+ return SPELLING;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid subject match rule");
+}
Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
+++ cfe/trunk/lib/Parse/ParsePragma.cpp Tue Apr 18 09:33:39 2017
@@ -183,6 +183,17 @@ private:
Sema &Actions;
};
+/// PragmaAttributeHandler - "\#pragma clang attribute ...".
+struct PragmaAttributeHandler : public PragmaHandler {
+ PragmaAttributeHandler(AttributeFactory &AttrFactory)
+ : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+
+ /// A pool of attributes that were parsed in \#pragma clang attribute.
+ ParsedAttributes AttributesForPragmaAttribute;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -275,6 +286,9 @@ void Parser::initializePragmaHandlers()
FPHandler.reset(new PragmaFPHandler());
PP.AddPragmaHandler("clang", FPHandler.get());
+
+ AttributePragmaHandler.reset(new PragmaAttributeHandler(AttrFactory));
+ PP.AddPragmaHandler("clang", AttributePragmaHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -356,6 +370,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", FPHandler.get());
FPHandler.reset();
+
+ PP.RemovePragmaHandler("clang", AttributePragmaHandler.get());
+ AttributePragmaHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -966,6 +983,422 @@ bool Parser::HandlePragmaLoopHint(LoopHi
return true;
}
+namespace {
+struct PragmaAttributeInfo {
+ enum ActionType { Push, Pop };
+ ParsedAttributes &Attributes;
+ ActionType Action;
+ ArrayRef<Token> Tokens;
+
+ PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {}
+};
+
+#include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc"
+
+} // end anonymous namespace
+
+static StringRef getIdentifier(const Token &Tok) {
+ if (Tok.is(tok::identifier))
+ return Tok.getIdentifierInfo()->getName();
+ const char *S = tok::getKeywordSpelling(Tok.getKind());
+ if (!S)
+ return "";
+ return S;
+}
+
+static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \
+ case Value: \
+ return IsAbstract;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid attribute subject match rule");
+ return false;
+}
+
+static void diagnoseExpectedAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ SourceLocation SubRuleLoc) {
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc,
+ diag::err_pragma_attribute_expected_subject_sub_identifier)
+ << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+static void diagnoseUnknownAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ StringRef SubRuleName, SourceLocation SubRuleLoc) {
+
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule)
+ << SubRuleName << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc,
+ SourceLocation &LastMatchRuleEndLoc) {
+ bool IsAny = false;
+ BalancedDelimiterTracker AnyParens(*this, tok::l_paren);
+ if (getIdentifier(Tok) == "any") {
+ AnyLoc = ConsumeToken();
+ IsAny = true;
+ if (AnyParens.expectAndConsume())
+ return true;
+ }
+
+ do {
+ // Parse the subject matcher rule.
+ StringRef Name = getIdentifier(Tok);
+ if (Name.empty()) {
+ Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier);
+ return true;
+ }
+ std::pair<Optional<attr::SubjectMatchRule>,
+ Optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
+ Rule = isAttributeSubjectMatchRule(Name);
+ if (!Rule.first) {
+ Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name;
+ return true;
+ }
+ attr::SubjectMatchRule PrimaryRule = *Rule.first;
+ SourceLocation RuleLoc = ConsumeToken();
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (isAbstractAttrMatcherRule(PrimaryRule)) {
+ if (Parens.expectAndConsume())
+ return true;
+ } else if (Parens.consumeOpen()) {
+ if (!SubjectMatchRules
+ .insert(
+ std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc)))
+ .second)
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << Name
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc));
+ LastMatchRuleEndLoc = RuleLoc;
+ continue;
+ }
+
+ // Parse the sub-rules.
+ StringRef SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ Tok.getLocation());
+ return true;
+ }
+ attr::SubjectMatchRule SubRule;
+ if (SubRuleName == "unless") {
+ SourceLocation SubRuleLoc = ConsumeToken();
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (Parens.expectAndConsume())
+ return true;
+ SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleLoc);
+ return true;
+ }
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true);
+ if (!SubRuleOrNone) {
+ std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")";
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleUnlessName, SubRuleLoc);
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ if (Parens.consumeClose())
+ return true;
+ } else {
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false);
+ if (!SubRuleOrNone) {
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleName, Tok.getLocation());
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ }
+ SourceLocation RuleEndLoc = Tok.getLocation();
+ LastMatchRuleEndLoc = RuleEndLoc;
+ if (Parens.consumeClose())
+ return true;
+ if (!SubjectMatchRules
+ .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc)))
+ .second) {
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << attr::getSubjectMatchRuleSpelling(SubRule)
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc));
+ continue;
+ }
+ } while (IsAny && TryConsumeToken(tok::comma));
+
+ if (IsAny)
+ if (AnyParens.consumeClose())
+ return true;
+
+ return false;
+}
+
+namespace {
+
+/// Describes the stage at which attribute subject rule parsing was interruped.
+enum class MissingAttributeSubjectRulesRecoveryPoint {
+ Comma,
+ ApplyTo,
+ Equals,
+ Any,
+ None,
+};
+
+MissingAttributeSubjectRulesRecoveryPoint
+getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
+ if (const auto *II = Tok.getIdentifierInfo()) {
+ if (II->isStr("apply_to"))
+ return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
+ if (II->isStr("any"))
+ return MissingAttributeSubjectRulesRecoveryPoint::Any;
+ }
+ if (Tok.is(tok::equal))
+ return MissingAttributeSubjectRulesRecoveryPoint::Equals;
+ return MissingAttributeSubjectRulesRecoveryPoint::None;
+}
+
+/// Creates a diagnostic for the attribute subject rule parsing diagnostic that
+/// suggests the possible attribute subject rules in a fix-it together with
+/// any other missing tokens.
+DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic(
+ unsigned DiagID, AttributeList &Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) {
+ SourceLocation Loc = PRef.getEndOfPreviousToken();
+ if (Loc.isInvalid())
+ Loc = PRef.getCurToken().getLocation();
+ auto Diagnostic = PRef.Diag(Loc, DiagID);
+ std::string FixIt;
+ MissingAttributeSubjectRulesRecoveryPoint EndPoint =
+ getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken());
+ if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma)
+ FixIt = ", ";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo)
+ FixIt += "apply_to";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals)
+ FixIt += " = ";
+ SourceRange FixItRange(Loc);
+ if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) {
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet;
+ Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet);
+ if (SubjectMatchRuleSet.empty()) {
+ // FIXME: We can emit a "fix-it" with a subject list placeholder when
+ // placeholders will be supported by the fix-its.
+ return Diagnostic;
+ }
+ FixIt += "any(";
+ bool NeedsComma = false;
+ for (const auto &I : SubjectMatchRuleSet) {
+ // Ensure that the missing rule is reported in the fix-it only when it's
+ // supported in the current language mode.
+ if (!I.second)
+ continue;
+ if (NeedsComma)
+ FixIt += ", ";
+ else
+ NeedsComma = true;
+ FixIt += attr::getSubjectMatchRuleSpelling(I.first);
+ }
+ FixIt += ")";
+ // Check if we need to remove the range
+ PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch);
+ FixItRange.setEnd(PRef.getCurToken().getLocation());
+ }
+ if (FixItRange.getBegin() == FixItRange.getEnd())
+ Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt);
+ else
+ Diagnostic << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(FixItRange), FixIt);
+ return Diagnostic;
+}
+
+} // end anonymous namespace
+
+void Parser::HandlePragmaAttribute() {
+ assert(Tok.is(tok::annot_pragma_attribute) &&
+ "Expected #pragma attribute annotation token");
+ SourceLocation PragmaLoc = Tok.getLocation();
+ auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue());
+ if (Info->Action == PragmaAttributeInfo::Pop) {
+ ConsumeToken();
+ Actions.ActOnPragmaAttributePop(PragmaLoc);
+ return;
+ }
+ // Parse the actual attribute with its arguments.
+ assert(Info->Action == PragmaAttributeInfo::Push &&
+ "Unexpected #pragma attribute command");
+ PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false);
+ ConsumeToken();
+
+ ParsedAttributes &Attrs = Info->Attributes;
+ Attrs.clearListOnly();
+
+ auto SkipToEnd = [this]() {
+ SkipUntil(tok::eof, StopBeforeMatch);
+ ConsumeToken();
+ };
+
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ // Parse the CXX11 style attribute.
+ ParseCXX11AttributeSpecifier(Attrs);
+ } else if (Tok.is(tok::kw___attribute)) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute"))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "("))
+ return SkipToEnd();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_name);
+ SkipToEnd();
+ return;
+ }
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_GNU);
+ else
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr,
+ /*ScopeName=*/nullptr,
+ /*ScopeLoc=*/SourceLocation(),
+ AttributeList::AS_GNU,
+ /*Declarator=*/nullptr);
+
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ } else if (Tok.is(tok::kw___declspec)) {
+ ParseMicrosoftDeclSpecs(Attrs);
+ } else {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
+ if (Tok.getIdentifierInfo()) {
+ // If we suspect that this is an attribute suggest the use of
+ // '__attribute__'.
+ if (AttributeList::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
+ AttributeList::AS_GNU) !=
+ AttributeList::UnknownAttribute) {
+ SourceLocation InsertStartLoc = Tok.getLocation();
+ ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ ConsumeAnyToken();
+ SkipUntil(tok::r_paren, StopBeforeMatch);
+ if (Tok.isNot(tok::r_paren))
+ return SkipToEnd();
+ }
+ Diag(Tok, diag::note_pragma_attribute_use_attribute_kw)
+ << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((")
+ << FixItHint::CreateInsertion(Tok.getEndLoc(), "))");
+ }
+ }
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList() || Attrs.getList()->isInvalid()) {
+ SkipToEnd();
+ return;
+ }
+
+ // Ensure that we don't have more than one attribute.
+ if (Attrs.getList()->getNext()) {
+ SourceLocation Loc = Attrs.getList()->getNext()->getLoc();
+ Diag(Loc, diag::err_pragma_attribute_multiple_attributes);
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList()->isSupportedByPragmaAttribute()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute)
+ << Attrs.getList()->getName();
+ SkipToEnd();
+ return;
+ }
+ AttributeList &Attribute = *Attrs.getList();
+
+ // Parse the subject-list.
+ if (!TryConsumeToken(tok::comma)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Comma, *this)
+ << tok::comma;
+ SkipToEnd();
+ return;
+ }
+
+ if (Tok.isNot(tok::identifier)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->isStr("apply_to")) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ ConsumeToken();
+
+ if (!TryConsumeToken(tok::equal)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Equals, *this)
+ << tok::equal;
+ SkipToEnd();
+ return;
+ }
+
+ attr::ParsedSubjectMatchRuleSet SubjectMatchRules;
+ SourceLocation AnyLoc, LastMatchRuleEndLoc;
+ if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc,
+ LastMatchRuleEndLoc)) {
+ SkipToEnd();
+ return;
+ }
+
+ // Tokens following an ill-formed attribute will remain in the token stream
+ // and must be removed.
+ if (Tok.isNot(tok::eof)) {
+ Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute);
+ SkipToEnd();
+ return;
+ }
+
+ // Consume the eof terminator token.
+ ConsumeToken();
+
+ Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc,
+ std::move(SubjectMatchRules));
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -2395,3 +2828,104 @@ void PragmaForceCUDAHostDeviceHandler::H
PP.Diag(FirstTok.getLocation(),
diag::warn_pragma_force_cuda_host_device_bad_arg);
}
+
+/// \brief Handle the #pragma clang attribute directive.
+///
+/// The syntax is:
+/// \code
+/// #pragma clang attribute push(attribute, subject-set)
+/// #pragma clang attribute pop
+/// \endcode
+///
+/// The subject-set clause defines the set of declarations which receive the
+/// attribute. Its exact syntax is described in the LanguageExtensions document
+/// in Clang's documentation.
+///
+/// This directive instructs the compiler to begin/finish applying the specified
+/// attribute to the set of attribute-specific declarations in the active range
+/// of the pragma.
+void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstToken) {
+ Token Tok;
+ PP.Lex(Tok);
+ auto *Info = new (PP.getPreprocessorAllocator())
+ PragmaAttributeInfo(AttributesForPragmaAttribute);
+
+ // Parse the 'push' or 'pop'.
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_push_pop);
+ return;
+ }
+ const auto *II = Tok.getIdentifierInfo();
+ if (II->isStr("push"))
+ Info->Action = PragmaAttributeInfo::Push;
+ else if (II->isStr("pop"))
+ Info->Action = PragmaAttributeInfo::Pop;
+ else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Parse the actual attribute.
+ if (Info->Action == PragmaAttributeInfo::Push) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Lex the attribute tokens.
+ SmallVector<Token, 16> AttributeTokens;
+ int OpenParens = 1;
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.is(tok::l_paren))
+ OpenParens++;
+ else if (Tok.is(tok::r_paren)) {
+ OpenParens--;
+ if (OpenParens == 0)
+ break;
+ }
+
+ AttributeTokens.push_back(Tok);
+ PP.Lex(Tok);
+ }
+
+ if (AttributeTokens.empty()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute);
+ return;
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ SourceLocation EndLoc = Tok.getLocation();
+ PP.Lex(Tok);
+
+ // Terminate the attribute for parsing.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(EndLoc);
+ AttributeTokens.push_back(EOFTok);
+
+ Info->Tokens =
+ llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
+ }
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang attribute";
+
+ // Generate the annotated pragma token.
+ auto TokenArray = llvm::make_unique<Token[]>(1);
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_attribute);
+ TokenArray[0].setLocation(FirstToken.getLocation());
+ TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation());
+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
+ PP.EnterTokenStream(std::move(TokenArray), 1,
+ /*DisableMacroExpansion=*/false);
+}
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Apr 18 09:33:39 2017
@@ -382,6 +382,10 @@ Retry:
case tok::annot_pragma_dump:
HandlePragmaDump();
return StmtEmpty();
+
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Apr 18 09:33:39 2017
@@ -602,6 +602,10 @@ bool Parser::ParseTopLevelDecl(DeclGroup
ConsumeToken();
return false;
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
+ return false;
+
case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Tue Apr 18 09:33:39 2017
@@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaInternal.h"
@@ -160,12 +161,16 @@ struct ParsedAttrInfo {
unsigned IsType : 1;
unsigned IsStmt : 1;
unsigned IsKnownToGCC : 1;
+ unsigned IsSupportedByPragmaAttribute : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
bool (*ExistsInTarget)(const TargetInfo &Target);
unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
+ void (*GetPragmaAttributeMatchRules)(
+ llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
+ const LangOptions &LangOpts);
};
namespace {
@@ -192,6 +197,18 @@ bool AttributeList::diagnoseAppertainsTo
return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
}
+bool AttributeList::appliesToDecl(const Decl *D,
+ attr::SubjectMatchRule MatchRule) const {
+ return checkAttributeMatchRuleAppliesTo(D, MatchRule);
+}
+
+void AttributeList::getMatchRules(
+ const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
+ const {
+ return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
+}
+
bool AttributeList::diagnoseLangOpts(Sema &S) const {
return getInfo(*this).DiagLangOpts(S, *this);
}
@@ -216,6 +233,10 @@ bool AttributeList::isKnownToGCC() const
return getInfo(*this).IsKnownToGCC;
}
+bool AttributeList::isSupportedByPragmaAttribute() const {
+ return getInfo(*this).IsSupportedByPragmaAttribute;
+}
+
unsigned AttributeList::getSemanticSpelling() const {
return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
}
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Apr 18 09:33:39 2017
@@ -71,42 +71,35 @@ void Sema::ActOnTranslationUnitScope(Sco
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- TranslationUnitKind TUKind,
- CodeCompleteConsumer *CodeCompleter)
- : ExternalSource(nullptr),
- isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
- LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
- Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), CodeCompleter(CodeCompleter),
- CurContext(nullptr), OriginalLexicalContext(nullptr),
- MSStructPragmaOn(false),
- MSPointerToMemberRepresentationMethod(
- LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
- PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr),
- ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
- VisContext(nullptr),
- IsBuildingRecoveryCallExpr(false),
- Cleanup{}, LateTemplateParser(nullptr),
- LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
- StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
- CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
- NSNumberDecl(nullptr), NSValueDecl(nullptr),
- NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
- ValueWithBytesObjCTypeMethod(nullptr),
- NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
- NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
- GlobalNewDeleteDeclared(false),
- TUKind(TUKind),
- NumSFINAEErrors(0),
- CachedFakeTopLevelModule(nullptr),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
- VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
- Ident_super(nullptr), Ident___float128(nullptr)
-{
+ TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
+ : ExternalSource(nullptr), isMultiplexExternalSource(false),
+ FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+ Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
+ SourceMgr(PP.getSourceManager()), CollectStats(false),
+ CodeCompleter(CodeCompleter), CurContext(nullptr),
+ OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
+ MSPointerToMemberRepresentationMethod(
+ LangOpts.getMSPointerToMemberRepresentationMethod()),
+ VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
+ DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+ CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
+ PragmaAttributeCurrentTargetDecl(nullptr),
+ IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
+ LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
+ StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
+ CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr),
+ NSValueDecl(nullptr), NSStringDecl(nullptr),
+ StringWithUTF8StringMethod(nullptr),
+ ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
+ ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
+ DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
+ TUKind(TUKind), NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr),
+ AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
+ NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
+ CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
+ TyposCorrected(0), AnalysisWarnings(*this),
+ ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
+ CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
LoadedExternalKnownNamespaces = false;
@@ -731,6 +724,8 @@ void Sema::ActOnEndOfTranslationUnit() {
CheckDelayedMemberExceptionSpecs();
}
+ DiagnoseUnterminatedPragmaAttribute();
+
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
// FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
Modified: cfe/trunk/lib/Sema/SemaAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAttr.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAttr.cpp Tue Apr 18 09:33:39 2017
@@ -368,6 +368,217 @@ void Sema::AddCFAuditedAttribute(Decl *D
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
}
+namespace {
+
+Optional<attr::SubjectMatchRule>
+getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return None;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return Parent;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return false;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return IsNegated;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+CharSourceRange replacementRangeForListElement(const Sema &S,
+ SourceRange Range) {
+ // Make sure that the ',' is removed as well.
+ SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken(
+ Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ if (AfterCommaLoc.isValid())
+ return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc);
+ else
+ return CharSourceRange::getTokenRange(Range);
+}
+
+std::string
+attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ for (const auto &I : llvm::enumerate(Rules)) {
+ if (I.index())
+ OS << (I.index() == Rules.size() - 1 ? ", and " : ", ");
+ OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'";
+ }
+ return OS.str();
+}
+
+} // end anonymous namespace
+
+void Sema::ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules) {
+ SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
+ StrictSubjectMatchRuleSet;
+ Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet);
+
+ // Figure out which subject matching rules are valid.
+ if (StrictSubjectMatchRuleSet.empty()) {
+ // Check for contradicting match rules. Contradicting match rules are
+ // either:
+ // - a top-level rule and one of its sub-rules. E.g. variable and
+ // variable(is_parameter).
+ // - a sub-rule and a sibling that's negated. E.g.
+ // variable(is_thread_local) and variable(unless(is_parameter))
+ llvm::SmallDenseMap<attr::SubjectMatchRule,
+ std::pair<attr::SubjectMatchRule, SourceRange>, 2>
+ RulesToFirstSpecifiedNegatedSubRule;
+ for (const auto &Rule : Rules) {
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(Rule.first);
+ if (!ParentRule)
+ continue;
+ auto It = Rules.find(*ParentRule);
+ if (It != Rules.end()) {
+ // A sub-rule contradicts a parent rule.
+ Diag(Rule.second.getBegin(),
+ diag::err_pragma_attribute_matcher_subrule_contradicts_rule)
+ << attr::getSubjectMatchRuleSpelling(Rule.first)
+ << attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ // Keep going without removing this rule as it won't change the set of
+ // declarations that receive the attribute.
+ continue;
+ }
+ if (isNegatedAttrMatcherSubRule(Rule.first))
+ RulesToFirstSpecifiedNegatedSubRule.insert(
+ std::make_pair(*ParentRule, Rule));
+ }
+ bool IgnoreNegatedSubRules = false;
+ for (const auto &Rule : Rules) {
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(Rule.first);
+ if (!ParentRule)
+ continue;
+ auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule);
+ if (It != RulesToFirstSpecifiedNegatedSubRule.end() &&
+ It->second != Rule) {
+ // Negated sub-rule contradicts another sub-rule.
+ Diag(
+ It->second.second.getBegin(),
+ diag::
+ err_pragma_attribute_matcher_negated_subrule_contradicts_subrule)
+ << attr::getSubjectMatchRuleSpelling(It->second.first)
+ << attr::getSubjectMatchRuleSpelling(Rule.first) << Rule.second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, It->second.second));
+ // Keep going but ignore all of the negated sub-rules.
+ IgnoreNegatedSubRules = true;
+ RulesToFirstSpecifiedNegatedSubRule.erase(It);
+ }
+ }
+
+ if (!IgnoreNegatedSubRules) {
+ for (const auto &Rule : Rules)
+ SubjectMatchRules.push_back(Rule.first);
+ } else {
+ for (const auto &Rule : Rules) {
+ if (!isNegatedAttrMatcherSubRule(Rule.first))
+ SubjectMatchRules.push_back(Rule.first);
+ }
+ }
+ Rules.clear();
+ } else {
+ for (const auto &Rule : StrictSubjectMatchRuleSet) {
+ if (Rules.erase(Rule.first)) {
+ // Add the rule to the set of attribute receivers only if it's supported
+ // in the current language mode.
+ if (Rule.second)
+ SubjectMatchRules.push_back(Rule.first);
+ }
+ }
+ }
+
+ if (!Rules.empty()) {
+ auto Diagnostic =
+ Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
+ << Attribute.getName();
+ SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
+ for (const auto &Rule : Rules) {
+ ExtraRules.push_back(Rule.first);
+ Diagnostic << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ }
+ Diagnostic << attrMatcherRuleListToString(ExtraRules);
+ }
+
+ PragmaAttributeStack.push_back(
+ {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
+}
+
+void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
+ if (PragmaAttributeStack.empty()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
+ return;
+ }
+ const PragmaAttributeEntry &Entry = PragmaAttributeStack.back();
+ if (!Entry.IsUsed) {
+ assert(Entry.Attribute && "Expected an attribute");
+ Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
+ << Entry.Attribute->getName();
+ Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+ }
+ PragmaAttributeStack.pop_back();
+}
+
+void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
+ if (PragmaAttributeStack.empty())
+ return;
+ for (auto &Entry : PragmaAttributeStack) {
+ const AttributeList *Attribute = Entry.Attribute;
+ assert(Attribute && "Expected an attribute");
+
+ // Ensure that the attribute can be applied to the given declaration.
+ bool Applies = false;
+ for (const auto &Rule : Entry.MatchRules) {
+ if (Attribute->appliesToDecl(D, Rule)) {
+ Applies = true;
+ break;
+ }
+ }
+ if (!Applies)
+ continue;
+ Entry.IsUsed = true;
+ assert(!Attribute->getNext() && "Expected just one attribute");
+ PragmaAttributeCurrentTargetDecl = D;
+ ProcessDeclAttributeList(S, D, Attribute);
+ PragmaAttributeCurrentTargetDecl = nullptr;
+ }
+}
+
+void Sema::PrintPragmaAttributeInstantiationPoint() {
+ assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
+ Diags.Report(PragmaAttributeCurrentTargetDecl->getLocStart(),
+ diag::note_pragma_attribute_applied_decl_here);
+}
+
+void Sema::DiagnoseUnterminatedPragmaAttribute() {
+ if (PragmaAttributeStack.empty())
+ return;
+ Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof);
+}
+
void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
if(On)
OptimizeOffPragmaLocation = SourceLocation();
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Apr 18 09:33:39 2017
@@ -13674,6 +13674,7 @@ CreateNewDecl:
if (Attr)
ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
// If this has an identifier, add it to the scope stack.
if (TUK == TUK_Friend) {
@@ -15185,6 +15186,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S,
// Process attributes.
if (Attr) ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Apr 18 09:33:39 2017
@@ -6676,6 +6676,9 @@ void Sema::ProcessDeclAttributes(Scope *
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
+
+ // Apply additional attributes specified by '#pragma clang attribute'.
+ AddPragmaAttributes(S, D);
}
/// Is the given declaration allowed to use a forbidden type?
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Apr 18 09:33:39 2017
@@ -8445,6 +8445,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope
Namespc->setInvalidDecl();
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+ AddPragmaAttributes(DeclRegionScope, Namespc);
// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
@@ -9931,6 +9932,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope
NewTD->setInvalidDecl();
ProcessDeclAttributeList(S, NewTD, AttrList);
+ AddPragmaAttributes(S, NewTD);
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Apr 18 09:33:39 2017
@@ -993,6 +993,7 @@ ActOnStartClassInterface(Scope *S, Sourc
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+ AddPragmaAttributes(TUScope, IDecl);
PushOnScopeChains(IDecl, TUScope);
// Start the definition of this class. If we're in a redefinition case, there
@@ -1176,7 +1177,8 @@ Sema::ActOnStartProtocolInterface(Source
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
// Merge attributes from previous declarations.
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1706,7 +1708,8 @@ Sema::ActOnForwardProtocolDeclaration(So
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1805,6 +1808,7 @@ ActOnStartCategoryInterface(SourceLocati
if (AttrList)
ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+ AddPragmaAttributes(TUScope, CDecl);
CheckObjCDeclScope(CDecl);
return ActOnObjCContainerStartDefinition(CDecl);
@@ -1954,6 +1958,7 @@ Decl *Sema::ActOnStartClassImplementatio
ClassName, /*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr, ClassLoc,
true);
+ AddPragmaAttributes(TUScope, IDecl);
IDecl->startDefinition();
if (SDecl) {
IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
@@ -3043,7 +3048,7 @@ Sema::ActOnForwardClassDeclaration(Sourc
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
-
+
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
@@ -4399,6 +4404,7 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ AddPragmaAttributes(TUScope, Param);
if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
@@ -4429,6 +4435,7 @@ Decl *Sema::ActOnMethodDeclaration(
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
+ AddPragmaAttributes(TUScope, ObjCMethod);
// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
Added: cfe/trunk/test/FixIt/fixit-pragma-attribute.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-pragma-attribute.c?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/fixit-pragma-attribute.c (added)
+++ cfe/trunk/test/FixIt/fixit-pragma-attribute.c Tue Apr 18 09:33:39 2017
@@ -0,0 +1,6 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// Verify that the suggested attribute subject match rules don't include the
+// rules that are not applicable in the current language mode.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = any(record(unless(is_union)), variable, function)"
Added: cfe/trunk/test/FixIt/fixit-pragma-attribute.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-pragma-attribute.cpp?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/fixit-pragma-attribute.cpp (added)
+++ cfe/trunk/test/FixIt/fixit-pragma-attribute.cpp Tue Apr 18 09:33:39 2017
@@ -0,0 +1,83 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wno-pragma-clang-attribute %s 2>&1 | FileCheck %s
+
+#pragma clang attribute push (annotate)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:31}:"__attribute__(("
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:39-[[@LINE-2]]:39}:"))"
+#pragma clang attribute push (annotate(("test")))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:31}:"__attribute__(("
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:49-[[@LINE-2]]:49}:"))"
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum, function, function, namespace, function ))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:97-[[@LINE-1]]:107}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:118-[[@LINE-2]]:127}:""
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), function, variable(is_global), variable(is_global) ))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:112-[[@LINE-1]]:133}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:133-[[@LINE-2]]:153}:""
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:108-[[@LINE-1]]:132}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:153-[[@LINE-2]]:172}:""
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions2"))), apply_to = any(function(is_member),function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:99-[[@LINE-1]]:119}:""
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions1"))), apply_to = any(variable(is_parameter), variable(unless(is_parameter))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:130-[[@LINE-1]]:160}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:106-[[@LINE-1]]:137}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(enum, variable))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:77-[[@LINE-1]]:82}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) apply_to=function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", "
+#pragma clang attribute push (__attribute__((abi_tag("a"))) = function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))) 22)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:63}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:69}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) (function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:71}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), )
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:62}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), = function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:61}:"apply_to"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:61}:"apply_to = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), 22)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:64}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), 1, 2)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:66}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:70}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), (function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:72}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:70}:" = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:70}:" = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to 41 (22))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:78}:" = any(record(unless(is_union)), variable, function, namespace)"
+
+// Don't give fix-it to attributes without a strict subject set
+#pragma clang attribute push (__attribute__((annotate("a"))))
+// CHECK-NO: [[@LINE-1]]:61
Added: cfe/trunk/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp (added)
+++ cfe/trunk/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp Tue Apr 18 09:33:39 2017
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=namespace" %s | FileCheck --check-prefix=CHECK-NAMESPACE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=type_alias" %s | FileCheck --check-prefix=CHECK-TYPE_ALIAS %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum" %s | FileCheck --check-prefix=CHECK-ENUM %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum_constant" %s | FileCheck --check-prefix=CHECK-ENUM_CONSTANT %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record" %s | FileCheck --check-prefix=CHECK-RECORD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record(unless(is_union))" %s | FileCheck --check-prefix=CHECK-RECORD_UNLESS_IS_UNION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function" %s | FileCheck --check-prefix=CHECK-FUNCTION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function(is_member)" %s | FileCheck --check-prefix=CHECK-FUNCTION_IS_MEMBER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable" %s | FileCheck --check-prefix=CHECK-VARIABLE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_global)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_GLOBAL %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_parameter)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_PARAMETER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(unless(is_parameter))" %s | FileCheck --check-prefix=CHECK-VARIABLE_UNLESS_IS_PARAMETER %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+namespace testNamespace {
+// CHECK-NAMESPACE: NamespaceDecl{{.*}} testNamespace
+// CHECK-NAMESPACE-NEXT: AnnotateAttr{{.*}} "test"
+
+typedef int testTypedef;
+// CHECK-TYPE_ALIAS: TypedefDecl{{.*}} testTypedef
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+using testTypeAlias = double;
+// CHECK-TYPE_ALIAS: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+enum testEnum {
+ testEnumCase1,
+ testEnumCase2
+};
+// CHECK-ENUM: EnumDecl{{.*}} testEnum
+// CHECK-ENUM-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase1
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase2
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+
+struct testStructRecord {
+ int testStructRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testStructRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassRecord {
+ int testClassRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testClassRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+union testUnionRecord {
+ int testUnionRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testUnionRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl
+void testFunctionDecl();
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void testFunctionDecl() { }
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void (*testFunctionVar)();
+// CHECK-HAS_TYPE_FUNCTION_TYPE: VarDecl{{.*}} testFunctionVar
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// 'function' should not apply to variables with a function type!
+// CHECK-FUNCTION: VarDecl{{.*}} testFunctionVar
+// CHECK-FUNCTION-NOT: AnnotateAttr{{.*}} "test"
+
+class testMethods {
+ testMethods();
+ void testMethod();
+};
+void testMethods::testMethod() { }
+void testFunctionNotMethod();
+// CHECK-FUNCTION-LABEL: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXConstructorDecl{{.*}} testMethods
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: CompoundStmt
+// CHECK-CXX_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: FunctionDecl{{.*}} testFunctionNotMethod
+// CHECK-FUNCTION_IS_MEMBER-NOT: AnnotateAttr{{.*}} "test"
+
+int testVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+void testVarFunction(int testParam) {
+// CHECK-VARIABLE: VarDecl{{.*}} testParam
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+
+ int testLocalVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+}
+class testVarClass {
+ static int testStaticVar;
+};
+// CHECK-VARIABLE: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+
+
+}
+
+#pragma clang attribute pop
Added: cfe/trunk/test/Misc/pragma-attribute-cxx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-cxx.cpp?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-cxx.cpp (added)
+++ cfe/trunk/test/Misc/pragma-attribute-cxx.cpp Tue Apr 18 09:33:39 2017
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test -std=c++11 -fcxx-exceptions %s | FileCheck %s
+// expected-no-diagnostics
+
+class testClass1 {
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass1
+// CHECK-NOT: AnnotateAttr
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+class testClass2 {
+ void testMethod1(int param);
+
+ testClass2();
+
+ testClass2 *operator -> ();
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass2
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK: CXXMethodDecl{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXConstructorDecl
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXMethodDecl{{.*}} operator->
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute push (__attribute__((annotate("method"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+void testClass2::testMethod1(int param) {
+
+#pragma clang attribute pop
+}
+// CHECK-LABEL: CXXMethodDecl{{.*}}prev{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+
+namespace testNamespace {
+}
+// CHECK-LABEL: NamespaceDecl{{.*}} testNamespace
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassForward;
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClassForward
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+namespace testNamespaceAlias = testNamespace;
+// CHECK-LABEL: NamespaceAliasDecl{{.*}} testNamespaceAlias
+// CHECK-NOT: AnnotateAttr
+
+using testTypeAlias = testClass2;
+// CHECK-LABEL: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK: AnnotateAttr{{.*}} "test"
+
+void testCatchVariable() {
+ try {
+ } catch (int testCatch) {
+ }
+ testCatchVariable();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testCatchVariable
+// CHECK: CXXCatchStmt
+// CHECK-NEXT: VarDecl{{.*}} testCatch
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+void testLambdaMethod() {
+ auto l = [] () { };
+ testLambdaMethod();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testLambdaMethod
+// CHECK: LambdaExpr
+// CHECK-NEXT: CXXRecordDecl
+// CHECK-NEXT: CXXMethodDecl{{.*}} operator()
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((require_constant_initialization)), apply_to=variable(is_global))
+
+int testCI1 = 1;
+// CHECK-LABEL: VarDecl{{.*}} testCI1
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: RequireConstantInitAttr
+
+#pragma clang attribute pop
+
+int testNoCI = 0;
+// CHECK-LABEL: VarDecl{{.*}} testNoCI
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: RequireConstantInitAttr
+
+// Check support for CXX11 style attributes
+#pragma clang attribute push ([[noreturn]], apply_to = function)
+
+void testNoReturn();
+// CHECK-LABEL: FunctionDecl{{.*}} testNoReturn
+// CHECK-NEXT: CXX11NoReturnAttr
+
+#pragma clang attribute pop
Added: cfe/trunk/test/Misc/pragma-attribute-objc-subject-match-rules.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-objc-subject-match-rules.m?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-objc-subject-match-rules.m (added)
+++ cfe/trunk/test/Misc/pragma-attribute-objc-subject-match-rules.m Tue Apr 18 09:33:39 2017
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_interface" %s | FileCheck --check-prefix=CHECK-OBJC_INTERFACE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_protocol" %s | FileCheck --check-prefix=CHECK-OBJC_PROTOCOL %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_category" %s | FileCheck --check-prefix=CHECK-OBJC_CATEGORY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method(is_instance)" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD_IS_INSTANCE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_property" %s | FileCheck --check-prefix=CHECK-OBJC_PROPERTY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=block" %s | FileCheck --check-prefix=CHECK-BLOCK %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+ at interface testInterface
+ at end
+// CHECK-OBJC_INTERFACE: ObjCInterfaceDecl{{.*}} testInterface
+// CHECK-OBJC_INTERFACE-NEXT: AnnotateAttr{{.*}} "test"
+
+ at interface testInterface ()
+ at end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+ at interface testInterface (testCategory)
+ at end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-OBJC_INTERFACE-LABEL: ObjCProtocolDecl
+ at protocol testProtocol
+ at end
+// CHECK-OBJC_PROTOCOL: ObjCProtocolDecl{{.*}} testProtocol
+// CHECK-OBJC_PROTOCOL-NEXT: AnnotateAttr{{.*}} "test"
+
+ at interface methodContainer
+- (void) testInstanceMethod;
++ (void) testClassMethod;
+ at end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+ at implementation methodContainer
+- (void) testInstanceMethod { }
++ (void) testClassMethod { }
+ at end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+ at interface propertyContainer {
+ int testIvar;
+// CHECK-FIELD: ObjCIvarDecl{{.*}} testIvar
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+}
+ at property int testProperty;
+// CHECK-OBJC_PROPERTY: ObjCPropertyDecl{{.*}} testProperty
+// CHECK-OBJC_PROPERTY-NEXT: AnnotateAttr{{.*}} "test"
+
+ at end
+
+void (^testBlockVar)();
+// CHECK-BLOCK: VarDecl{{.*}} testBlockVar
+// CHECK-BLOCK-NOT: AnnotateAttr{{.*}} "test"
+
+void testBlock() {
+ (void)(^ { });
+}
+// CHECK-BLOCK-LABEL: BlockDecl
+// CHECK-BLOCK-NEXT: CompoundStmt
+// CHECK-BLOCK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: FunctionDecl{{.*}} testBlock
+// CHECK-HAS_TYPE_FUNCTION_TYPE: BlockDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// The attribute applies to function, but not to block:
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+
+#pragma clang attribute pop
Added: cfe/trunk/test/Misc/pragma-attribute-objc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-objc.m?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-objc.m (added)
+++ cfe/trunk/test/Misc/pragma-attribute-objc.m Tue Apr 18 09:33:39 2017
@@ -0,0 +1,164 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(objc_interface, objc_protocol, objc_property, field, objc_method, variable))
+#pragma clang attribute push (__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+
+ at interface testInterface1
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface1
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr{{.*}}
+
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar1;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar1
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+ at property int testProp1;
+// CHECK-LABEL: ObjCPropertyDecl{{.*}} testProp1
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+- (void)testIm:(int) x;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
++ (void)testCm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+// Implicit getters/setters shouldn't receive the attributes.
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProp1
+// CHECK-NOT: AnnotateAttr
+// CHECK-LABEL: ObjCMethodDecl{{.*}}setTestProp1
+// CHECK-NOT: AnnotateAttr
+
+ at end
+
+// @implementation can't receive explicit attributes, so don't add the pragma
+// attributes to them.
+ at implementation testInterface1
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testInterface1
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar2;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar2
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+// Don't add attributes to implicit parameters!
+- (void)testIm:(int) x {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
++ (void)testCm {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+ _Pragma("clang attribute push (__attribute__((annotate(\"applied at container start\"))), apply_to=objc_interface)");
+}
+
+// Implicit ivars shouldn't receive the attributes.
+// CHECK-LABEL: ObjCIvarDecl{{.*}}_testProp1
+// CHECK-NOT: AnnotateAttr
+
+ at end
+
+ at implementation testImplWithoutInterface // expected-warning {{cannot find interface declaration for 'testImplWithoutInterface'}}
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testImplWithoutInterface
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr
+// CHECK-NEXT: AnnotateAttr{{.*}} "applied at container start"
+
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testImplWithoutInterface
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+ at end
+
+#pragma clang attribute pop
+
+ at protocol testProtocol
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+
+- (void)testProtIm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProtIm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+ at end
+
+ at protocol testForwardProtocol;
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testForwardProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+
+// Categories can't receive explicit attributes, so don't add pragma attributes
+// to them.
+ at interface testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+ at end
+
+ at implementation testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryImplDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+ at end
+
+// @class/@compatibility_alias declarations can't receive explicit attributes,
+// so don't add pragma attributes to them.
+ at class testClass;
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testClass
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+ at compatibility_alias testCompat testInterface1;
+// CHECK-LABEL: ObjCCompatibleAliasDecl{{.*}}testCompat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+#pragma clang attribute pop // objc_subclassing_restricted
+
+ at interface testInterface3
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface3
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+ at end
+
+#pragma clang attribute pop // annotate("test")
+
+ at interface testInterface4
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface4
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+ at end
Added: cfe/trunk/test/Misc/pragma-attribute-strict-subjects.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-strict-subjects.c?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-strict-subjects.c (added)
+++ cfe/trunk/test/Misc/pragma-attribute-strict-subjects.c Tue Apr 18 09:33:39 2017
@@ -0,0 +1,222 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-clang-attribute -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+// Check for contradictions in rules for attribute without a strict subject set:
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// expected-error at -1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
+// expected-error at -2 {{redundant attribute subject matcher sub-rule 'variable(is_global)'; 'variable' already matches those declarations}}
+
+// Ensure that we've recovered from the error:
+int testRecoverSubRuleContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverSubRuleContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "subRuleContradictions"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// expected-error at -1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}}
+// We have just one error, don't error on 'variable(is_global)'
+
+// Ensure that we've recovered from the error:
+int testRecoverNegatedContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverNegatedContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+void testRecoverNegatedContradictionFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverNegatedContradictionFunc
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+#pragma clang attribute pop
+
+// Verify the strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testRecoverStrictnessVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverStrictnessVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: AbiTagAttr
+
+void testRecoverStrictnessFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverStrictnessFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverStrictnessStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverStrictnessStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testRecoverExtraVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverExtraVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AbiTagAttr
+
+void testRecoverExtraFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverExtraFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverExtraStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverExtraStruct
+// CHECK-NEXT: AbiTagAttr
+
+enum testNoEnumAbiTag { CaseCase };
+// CHECK-LABEL: EnumDecl{{.*}} testNoEnumAbiTag
+// CHECK-NO: AbiTagAttr
+
+#pragma clang attribute pop
+
+// Verify the non-strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testSubset1Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset1Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset1Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset1Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset1Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset1Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+
+int testSubset2Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset2Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset2Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset2Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset2Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset2Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union))))
+
+int testSubset3Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset3Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset3Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset3Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset3Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset3Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+
+int testSubset4Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset4Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset4Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset4Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset4Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset4Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+
+int testSubset5Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset5Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset5Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset5Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset5Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset5Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function))
+
+int testSubset6Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset6Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset6Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset6Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset6Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset6Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+
+int testSubset7Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset7Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset7Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset7Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset7Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset7Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'enum'}}
+
+int testSubsetRecoverVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetRecoverVar
+// CHECK-NEXT: AbiTagAttr
+
+void testSubsetRecoverFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetRecoverFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubsetRecoverStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetRecoverStruct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = enum)
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testSubsetNoVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetNoVar
+// CHECK-NOT: AbiTagAttr
+
+void testSubsetNoFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetNoFunc
+// CHECK-NOT: AbiTagAttr
+
+struct testSubsetNoStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetNoStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
Added: cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test (added)
+++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test Tue Apr 18 09:33:39 2017
@@ -0,0 +1,62 @@
+// RUN: clang-tblgen -gen-clang-test-pragma-attribute-supported-attributes -I%src_include_dir %src_include_dir/clang/Basic/Attr.td -o - | FileCheck %s
+
+// The number of supported attributes should never go down!
+
+// CHECK: #pragma clang attribute supports 57 attributes:
+// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUWavesPerEU (SubjectMatchRule_function)
+// CHECK-NEXT: AVRSignal (SubjectMatchRule_function)
+// CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace)
+// CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias)
+// CHECK-NEXT: AllocSize (SubjectMatchRule_function)
+// CHECK-NEXT: Annotate ()
+// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
+// CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Consumable (SubjectMatchRule_record)
+// CHECK-NEXT: Convergent (SubjectMatchRule_function)
+// CHECK-NEXT: DLLExport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DLLImport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: EnableIf (SubjectMatchRule_function)
+// CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum)
+// CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
+// CHECK-NEXT: Flatten (SubjectMatchRule_function)
+// CHECK-NEXT: IFunc (SubjectMatchRule_function)
+// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
+// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
+// CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)
+// CHECK-NEXT: NoDuplicate (SubjectMatchRule_function)
+// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
+// CHECK-NEXT: NotTailCalled (SubjectMatchRule_function)
+// CHECK-NEXT: ObjCBoxable (SubjectMatchRule_record)
+// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRuntimeName (SubjectMatchRule_objc_interface, SubjectMatchRule_objc_protocol)
+// CHECK-NEXT: ObjCRuntimeVisible (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: ObjCSubclassingRestricted (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
+// CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
+// CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
+// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: SwiftContext (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
+// CHECK-NEXT: Target (SubjectMatchRule_function)
+// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)
+// CHECK-NEXT: XRayInstrument (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)
Added: cfe/trunk/test/Parser/pragma-attribute-declspec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-attribute-declspec.cpp?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Parser/pragma-attribute-declspec.cpp (added)
+++ cfe/trunk/test/Parser/pragma-attribute-declspec.cpp Tue Apr 18 09:33:39 2017
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -verify -Wno-pragma-clang-attribute -fms-extensions -fms-compatibility %s
+
+#pragma clang attribute push(__declspec(dllexport), apply_to = function)
+
+void function();
+
+#pragma clang attribute pop
+
+#pragma clang attribute push(__declspec(dllexport, dllimport), apply_to = function) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+
+#pragma clang attribute push(__declspec(align), apply_to = variable) // expected-error {{attribute 'align' is not supported by '#pragma clang attribute'}}
+
+#pragma clang attribute push(__declspec(), apply_to = variable) // A noop
Added: cfe/trunk/test/Parser/pragma-attribute.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-attribute.cpp?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Parser/pragma-attribute.cpp (added)
+++ cfe/trunk/test/Parser/pragma-attribute.cpp Tue Apr 18 09:33:39 2017
@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -Wno-pragma-clang-attribute -verify -std=c++11 %s
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = function)
+
+void function();
+
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(variable(is_parameter), function))
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = variable(unless(is_parameter)))
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(variable(unless(is_parameter))))
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a")))) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) apply_to=function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) = function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) any(function)) // expected-error {{expected ','}}
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))) 22) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) (function)) // expected-error {{expected ','}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), ) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), = any(function)) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), any(function)) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply = any(function )) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), to = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_only_to = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to any(function)) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to function) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to) // expected-error {{expected '='}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to 41 (22)) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any {) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any function) // expected-error {{expected '('}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = { function, enum }) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(function ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(function, )) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum ) // expected-error {{expected ')'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = () ) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( + ) ) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any()) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, 42 )) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( diag )) // expected-error {{unknown attribute subject rule 'diag'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( a )) // expected-error {{unknown attribute subject rule 'a'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, for)) // expected-error {{unknown attribute subject rule 'for'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function42, for )) // expected-error {{unknown attribute subject rule 'function42'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(hasType)) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = hasType) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = hasType(functionType)) // OK
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable( )) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable( ) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is ) )) // expected-error {{unknown attribute subject matcher sub-rule 'is'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_parameter, not) )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable is_parameter )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable ( ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = variable ( // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (is ()) )) // expected-error {{unknown attribute subject matcher sub-rule 'is'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (42) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, namespace("test") )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'namespace' matcher does not support sub-rules}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable ("test" )) // expected-error {{expected ')'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = enum(is_parameter)) // expected-error {{invalid use of attribute subject matcher sub-rule 'is_parameter'; 'enum' matcher does not support sub-rules}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(enum(is_parameter))) // expected-error {{invalid use of attribute subject matcher sub-rule 'is_parameter'; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any (function, variable (unless) )) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any (function, variable (unless() )) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any ( function, variable (unless(is)) )) // expected-error {{unknown attribute subject matcher sub-rule 'unless(is)'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter, not)) )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter), not) ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable unless is_parameter )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless is_parameter) )) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (unless(42)) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum(unless("test")) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (unless(is_global)) )) // expected-error {{unknown attribute subject matcher sub-rule 'unless(is_global)'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum(unless(is_parameter)) )) // expected-error {{invalid use of attribute subject matcher sub-rule 'unless(is_parameter)'; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, function )) // expected-error {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, function, function )) // expected-error 2 {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum, function )) // expected-error {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum, enum, function )) // expected-error {{duplicate attribute subject matcher 'enum'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), variable(is_global) )) // expected-error {{duplicate attribute subject matcher 'variable(is_global)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), function, variable(is_global), variable(is_global) )) // expected-error 2 {{duplicate attribute subject matcher 'variable(is_global)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter)), variable(unless(is_parameter)) )) // expected-error {{duplicate attribute subject matcher 'variable(unless(is_parameter))'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter)), variable(unless(is_parameter)), enum, variable(unless(is_parameter)) )) // expected-error 2 {{duplicate attribute subject matcher 'variable(unless(is_parameter))'}}
+
+#pragma clang attribute // expected-error {{expected 'push' or 'pop' after '#pragma clang attribute'}}
+#pragma clang attribute 42 // expected-error {{expected 'push' or 'pop' after '#pragma clang attribute'}}
+#pragma clang attribute pushpop // expected-error {{unexpected argument 'pushpop' to '#pragma clang attribute'; expected 'push' or 'pop'}}
+
+#pragma clang attribute push // expected-error {{expected '('}}
+#pragma clang attribute push ( // expected-error {{expected an attribute after '('}}
+#pragma clang attribute push (__attribute__((annotate)) // expected-error {{expected ')'}}
+#pragma clang attribute push () // expected-error {{expected an attribute after '('}}
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = function) () // expected-warning {{extra tokens at end of '#pragma clang attribute'}}
+// expected-error at -1 {{expected unqualified-id}}
+// expected-error at -2 {{unterminated '#pragma clang attribute push' at end of file}}
+
+#pragma clang attribute pop () // expected-warning {{extra tokens at end of '#pragma clang attribute'}}
+
+;
+
+#pragma clang attribute push (__attribute__((42))) // expected-error {{expected identifier that represents an attribute name}}
+
+#pragma clang attribute push (__attribute__((annotate)) foo) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((annotate)), apply_to=function foo) // expected-error {{extra tokens after attribute in a '#pragma clang attribute push'}}
+
+#pragma clang attribute push (__attribute__((availability(macos, foo=1))), apply_to=function) // expected-error {{'foo' is not an availability stage; use 'introduced', 'deprecated', or 'obsoleted'}}
+// expected-error at -1 {{attribute 'availability' is not supported by '#pragma clang attribute'}}
+#pragma clang attribute push (__attribute__((availability(macos, 1))), apply_to=function) // expected-error {{expected 'introduced', 'deprecated', or 'obsoleted'}}
+
+#pragma clang attribute push (__attribute__((used)), apply_to=function) // expected-error {{attribute 'used' is not supported by '#pragma clang attribute'}}
+
+void statementPragmasAndPragmaExpression() {
+#pragma clang attribute push (__attribute__((annotate("hello"))), apply_to=variable)
+#pragma clang attribute pop
+int x = 0;
+_Pragma("clang attribute push (__attribute__((annotate(\"hi\"))), apply_to = function)");
+
+_Pragma("clang attribute push (__attribute__((annotate(\"hi\"))), apply_to = any(function(is_method ))"); // expected-error {{expected ')'}}
+}
+
+_Pragma("clang attribute pop");
+
+#pragma clang attribute push (__attribute__((address_space(0))), apply_to=variable) // expected-error {{attribute 'address_space' is not supported by '#pragma clang attribute'}}
+
+// Check support for CXX11 style attributes
+#pragma clang attribute push ([[noreturn]], apply_to = any(function))
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[clang::disable_tail_calls]], apply_to = function)
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[gnu::abi_tag]], apply_to=any(function))
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[clang::disable_tail_calls, noreturn]], apply_to = function) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+#pragma clang attribute push ([[clang::disable_tail_calls, noreturn]]) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+
+#pragma clang attribute push ([[gnu::abi_tag]], apply_to=namespace)
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[fallthrough]], apply_to=function) // expected-error {{attribute 'fallthrough' is not supported by '#pragma clang attribute'}}
+#pragma clang attribute push ([[clang::fallthrough]], apply_to=function) // expected-error {{attribute 'fallthrough' is not supported by '#pragma clang attribute'}}
+
+#pragma clang attribute push ([[]], apply_to = function) // A noop
+
+#pragma clang attribute push ([[noreturn ""]], apply_to=function) // expected-error {{expected ']'}}
+#pragma clang attribute pop
+#pragma clang attribute push ([[noreturn 42]]) // expected-error {{expected ']'}} expected-error {{expected ','}}
+
+#pragma clang attribute push(__attribute__, apply_to=function) // expected-error {{expected '(' after 'attribute'}}
+#pragma clang attribute push(__attribute__(), apply_to=function) // expected-error {{expected '(' after '('}}
+#pragma clang attribute push(__attribute__(()), apply_to=function) // expected-error {{expected identifier that represents an attribute name}}
+#pragma clang attribute push(__attribute__((annotate, apply_to=function))) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"), apply_to=function))) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate), apply_to=function)) // expected-error {{expected ')'}}
+
+#pragma clang attribute push (42) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+#pragma clang attribute push (test) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+#pragma clang attribute push (annotate) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+// expected-note at -1 {{use the GNU '__attribute__' syntax}}
+#pragma clang attribute push (annotate("test")) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+// expected-note at -1 {{use the GNU '__attribute__' syntax}}
Added: cfe/trunk/test/Sema/pragma-attribute-strict-subjects.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pragma-attribute-strict-subjects.c?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Sema/pragma-attribute-strict-subjects.c (added)
+++ cfe/trunk/test/Sema/pragma-attribute-strict-subjects.c Tue Apr 18 09:33:39 2017
@@ -0,0 +1,153 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragmas -verify %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(function, variable))
+
+#pragma clang attribute pop
+
+// Check for contradictions in rules for attribute without a strict subject set:
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// expected-error at -1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
+// expected-error at -2 {{redundant attribute subject matcher sub-rule 'variable(is_global)'; 'variable' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions2"))), apply_to = any(function(is_member), function))
+// expected-error at -1 {{redundant attribute subject matcher sub-rule 'function(is_member)'; 'function' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions3"))), apply_to = any(variable, variable(unless(is_parameter))))
+// expected-error at -1 {{redundant attribute subject matcher sub-rule 'variable(unless(is_parameter))'; 'variable' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions1"))), apply_to = any(variable(is_parameter), variable(unless(is_parameter))))
+// expected-error at -1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_parameter)'}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// expected-error at -1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}}
+// We have just one error, don't error on 'variable(is_global)'
+
+#pragma clang attribute pop
+
+// Verify the strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable, record(unless(is_union))))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union)), function))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(enum_constant, function, record(unless(is_union)), variable, variable(is_parameter)))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'variable(is_parameter)', and 'enum_constant'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), enum))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+#pragma clang attribute pop
+
+// Verify the non-strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union))))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+
+#pragma clang attribute pop
+
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'enum'}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = enum)
+// expected-error at -1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+#pragma clang attribute pop
+
+// Handle attributes whose subjects are supported only in other language modes:
+
+#pragma clang attribute push(__attribute__((abi_tag("b"))), apply_to = any(namespace, record(unless(is_union)), variable, function))
+// 'namespace' is accepted!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((abi_tag("b"))), apply_to = any(namespace))
+// 'namespace' is accepted!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+// No error!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+// No error!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_interface, objc_protocol))
+// expected-error at -1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_protocol))
+// expected-error at -1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+// Don't report an error about missing 'objc_interface' as we aren't parsing
+// Objective-C.
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_interface, objc_protocol))
+// expected-error at -1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_protocol))
+// expected-error at -1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+// Don't report an error about missing 'objc_interface' as we aren't parsing
+// Objective-C.
+#pragma clang attribute pop
+
+// Use of matchers from other language modes should not cause for attributes
+// without subject list:
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = objc_method)
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(objc_interface, objc_protocol))
+
+#pragma clang attribute pop
Added: cfe/trunk/test/Sema/pragma-attribute.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pragma-attribute.c?rev=300556&view=auto
==============================================================================
--- cfe/trunk/test/Sema/pragma-attribute.c (added)
+++ cfe/trunk/test/Sema/pragma-attribute.c Tue Apr 18 09:33:39 2017
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma clang attribute pop // expected-error {{'#pragma clang attribute pop' with no matching '#pragma clang attribute push'}}
+
+// Don't verify unused attributes.
+#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-warning {{unused attribute 'annotate' in '#pragma clang attribute push' region}}
+#pragma clang attribute pop // expected-note {{'#pragma clang attribute push' regions ends here}}
+
+// Ensure we only report any errors once.
+#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-error 4 {{'annotate' attribute takes one argument}}
+
+void test5_begin(); // expected-note {{when applied to this declaration}}
+void test5_1(); // expected-note {{when applied to this declaration}}
+
+#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes one argument}}
+
+void test5_2(); // expected-note 2 {{when applied to this declaration}}
+
+#pragma clang attribute push (__attribute__((annotate("hello", "world"))), apply_to = function) // expected-error {{'annotate' attribute takes one argument}}
+
+void test5_3(); // expected-note 3 {{when applied to this declaration}}
+
+#pragma clang attribute pop
+#pragma clang attribute pop
+#pragma clang attribute pop
+
+// Verify that the warnings are reported for each receiver declaration
+
+#pragma clang attribute push (__attribute__((optnone)), apply_to = function) // expected-note 2 {{conflicting attribute is here}}
+
+__attribute__((always_inline)) void optnone1() { } // expected-warning {{'always_inline' attribute ignored}}
+// expected-note at -1 {{when applied to this declaration}}
+
+void optnone2() { }
+
+__attribute__((always_inline)) void optnone3() { } // expected-warning {{'always_inline' attribute ignored}}
+// expected-note at -1 {{when applied to this declaration}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[]], apply_to = function) // A noop
+
+#pragma clang attribute pop // expected-error {{'#pragma clang attribute pop' with no matching '#pragma clang attribute push'}}
+
+#pragma clang attribute push (__attribute__((annotate("func"))), apply_to = function) // expected-error {{unterminated '#pragma clang attribute push' at end of file}}
+
+void function();
Modified: cfe/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/lit.cfg?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/test/lit.cfg (original)
+++ cfe/trunk/test/lit.cfg Tue Apr 18 09:33:39 2017
@@ -284,6 +284,8 @@ if config.host_triple and config.host_tr
else:
config.substitutions.append( ('%target_itanium_abi_host_triple', '') )
+config.substitutions.append( ('%src_include_dir', config.clang_src_dir + '/include') )
+
# FIXME: Find nicer way to prohibit this.
config.substitutions.append(
(' clang ', """*** Do not use 'clang' in tests, use '%clang'. ***""") )
Modified: cfe/trunk/test/lit.site.cfg.in
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/lit.site.cfg.in?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/test/lit.site.cfg.in (original)
+++ cfe/trunk/test/lit.site.cfg.in Tue Apr 18 09:33:39 2017
@@ -10,6 +10,7 @@ config.llvm_shlib_dir = "@SHLIBDIR@"
config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
config.clang_obj_root = "@CLANG_BINARY_DIR@"
+config.clang_src_dir = "@CLANG_SOURCE_DIR@"
config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.target_triple = "@TARGET_TRIPLE@"
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Tue Apr 18 09:33:39 2017
@@ -12,13 +12,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -1522,6 +1524,334 @@ static void emitClangAttrLateParsedList(
OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
}
+static bool hasGNUorCXX11Spelling(const Record &Attribute) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
+ for (const auto &I : Spellings) {
+ if (I.variety() == "GNU" || I.variety() == "CXX11")
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+struct AttributeSubjectMatchRule {
+ const Record *MetaSubject;
+ const Record *Constraint;
+
+ AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint)
+ : MetaSubject(MetaSubject), Constraint(Constraint) {
+ assert(MetaSubject && "Missing subject");
+ }
+
+ bool isSubRule() const { return Constraint != nullptr; }
+
+ std::vector<Record *> getSubjects() const {
+ return (Constraint ? Constraint : MetaSubject)
+ ->getValueAsListOfDefs("Subjects");
+ }
+
+ std::vector<Record *> getLangOpts() const {
+ if (Constraint) {
+ // Lookup the options in the sub-rule first, in case the sub-rule
+ // overrides the rules options.
+ std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts");
+ if (!Opts.empty())
+ return Opts;
+ }
+ return MetaSubject->getValueAsListOfDefs("LangOpts");
+ }
+
+ // Abstract rules are used only for sub-rules
+ bool isAbstractRule() const { return getSubjects().empty(); }
+
+ std::string getName() const {
+ return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name");
+ }
+
+ bool isNegatedSubRule() const {
+ assert(isSubRule() && "Not a sub-rule");
+ return Constraint->getValueAsBit("Negated");
+ }
+
+ std::string getSpelling() const {
+ std::string Result = MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += '(';
+ if (isNegatedSubRule())
+ Result += "unless(";
+ Result += getName();
+ if (isNegatedSubRule())
+ Result += ')';
+ Result += ')';
+ }
+ return Result;
+ }
+
+ std::string getEnumValueName() const {
+ std::string Result =
+ "SubjectMatchRule_" + MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += "_";
+ if (isNegatedSubRule())
+ Result += "not_";
+ Result += Constraint->getValueAsString("Name");
+ }
+ if (isAbstractRule())
+ Result += "_abstract";
+ return Result;
+ }
+
+ std::string getEnumValue() const { return "attr::" + getEnumValueName(); }
+
+ static const char *EnumName;
+};
+
+const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule";
+
+struct PragmaClangAttributeSupport {
+ std::vector<AttributeSubjectMatchRule> Rules;
+ llvm::DenseMap<const Record *, AttributeSubjectMatchRule> SubjectsToRules;
+
+ PragmaClangAttributeSupport(RecordKeeper &Records);
+
+ bool isAttributedSupported(const Record &Attribute);
+
+ void emitMatchRuleList(raw_ostream &OS);
+
+ std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS);
+
+ void generateParsingHelpers(raw_ostream &OS);
+};
+
+} // end anonymous namespace
+
+PragmaClangAttributeSupport::PragmaClangAttributeSupport(
+ RecordKeeper &Records) {
+ std::vector<Record *> MetaSubjects =
+ Records.getAllDerivedDefinitions("AttrSubjectMatcherRule");
+ auto MapFromSubjectsToRules = [this](const Record *SubjectContainer,
+ const Record *MetaSubject,
+ const Record *Constraint = nullptr) {
+ Rules.emplace_back(MetaSubject, Constraint);
+ std::vector<Record *> ApplicableSubjects =
+ SubjectContainer->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : ApplicableSubjects) {
+ bool Inserted =
+ SubjectsToRules.try_emplace(Subject, MetaSubject, Constraint).second;
+ if (!Inserted) {
+ PrintFatalError("Attribute subject match rules should not represent"
+ "same attribute subjects.");
+ }
+ }
+ };
+ for (const auto *MetaSubject : MetaSubjects) {
+ MapFromSubjectsToRules(MetaSubject, MetaSubject);
+ std::vector<Record *> Constraints =
+ MetaSubject->getValueAsListOfDefs("Constraints");
+ for (const auto *Constraint : Constraints)
+ MapFromSubjectsToRules(Constraint, MetaSubject, Constraint);
+ }
+}
+
+static PragmaClangAttributeSupport &
+getPragmaAttributeSupport(RecordKeeper &Records) {
+ static PragmaClangAttributeSupport Instance(Records);
+ return Instance;
+}
+
+void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) {
+ OS << "#ifndef ATTR_MATCH_SUB_RULE\n";
+ OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, "
+ "IsNegated) "
+ << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n";
+ OS << "#endif\n";
+ for (const auto &Rule : Rules) {
+ OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '(';
+ OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", "
+ << Rule.isAbstractRule();
+ if (Rule.isSubRule())
+ OS << ", "
+ << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue()
+ << ", " << Rule.isNegatedSubRule();
+ OS << ")\n";
+ }
+ OS << "#undef ATTR_MATCH_SUB_RULE\n";
+}
+
+bool PragmaClangAttributeSupport::isAttributedSupported(
+ const Record &Attribute) {
+ if (Attribute.getValueAsBit("ForcePragmaAttributeSupport"))
+ return true;
+ // Opt-out rules:
+ // FIXME: The documentation check should be moved before
+ // the ForcePragmaAttributeSupport check after annotate is documented.
+ // No documentation present.
+ if (Attribute.isValueUnset("Documentation"))
+ return false;
+ std::vector<Record *> Docs = Attribute.getValueAsListOfDefs("Documentation");
+ if (Docs.empty())
+ return false;
+ if (Docs.size() == 1 && Docs[0]->getName() == "Undocumented")
+ return false;
+ // An attribute requires delayed parsing (LateParsed is on)
+ if (Attribute.getValueAsBit("LateParsed"))
+ return false;
+ // An attribute has no GNU/CXX11 spelling
+ if (!hasGNUorCXX11Spelling(Attribute))
+ return false;
+ // An attribute subject list has a subject that isn't covered by one of the
+ // subject match rules or has no subjects at all.
+ if (Attribute.isValueUnset("Subjects"))
+ return false;
+ const Record *SubjectObj = Attribute.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ if (Subjects.empty())
+ return false;
+ for (const auto *Subject : Subjects) {
+ if (SubjectsToRules.find(Subject) == SubjectsToRules.end())
+ return false;
+ }
+ return true;
+}
+
+std::string
+PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
+ raw_ostream &OS) {
+ if (!isAttributedSupported(Attr))
+ return "nullptr";
+ // Generate a function that constructs a set of matching rules that describe
+ // to which declarations the attribute should apply to.
+ std::string FnName = "matchRulesFor" + Attr.getName().str();
+ std::stringstream SS;
+ SS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<"
+ << AttributeSubjectMatchRule::EnumName
+ << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n";
+ if (Attr.isValueUnset("Subjects")) {
+ SS << "}\n\n";
+ OS << SS.str();
+ return FnName;
+ }
+ const Record *SubjectObj = Attr.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : Subjects) {
+ auto It = SubjectsToRules.find(Subject);
+ assert(It != SubjectsToRules.end() &&
+ "This attribute is unsupported by #pragma clang attribute");
+ AttributeSubjectMatchRule Rule = It->getSecond();
+ // The rule might be language specific, so only subtract it from the given
+ // rules if the specific language options are specified.
+ std::vector<Record *> LangOpts = Rule.getLangOpts();
+ SS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue()
+ << ", /*IsSupported=*/";
+ if (!LangOpts.empty()) {
+ for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
+ std::string Part = (*I)->getValueAsString("Name");
+ if ((*I)->getValueAsBit("Negated"))
+ SS << "!";
+ SS << "LangOpts." + Part;
+ if (I + 1 != E)
+ SS << " || ";
+ }
+ } else
+ SS << "true";
+ SS << "));\n";
+ }
+ SS << "}\n\n";
+ OS << SS.str();
+ return FnName;
+}
+
+void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
+ // Generate routines that check the names of sub-rules.
+ OS << "Optional<attr::SubjectMatchRule> "
+ "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n";
+ OS << " return None;\n";
+ OS << "}\n\n";
+
+ std::map<const Record *, std::vector<AttributeSubjectMatchRule>>
+ SubMatchRules;
+ for (const auto &Rule : Rules) {
+ if (!Rule.isSubRule())
+ continue;
+ SubMatchRules[Rule.MetaSubject].push_back(Rule);
+ }
+
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_"
+ << SubMatchRule.first->getValueAsString("Name")
+ << "(StringRef Name, bool IsUnless) {\n";
+ OS << " if (IsUnless)\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << "}\n\n";
+ }
+
+ // Generate the function that checks for the top-level rules.
+ OS << "std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*)(StringRef, "
+ "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n";
+ OS << " return "
+ "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*) (StringRef, "
+ "bool)>>(Name).\n";
+ for (const auto &Rule : Rules) {
+ if (Rule.isSubRule())
+ continue;
+ std::string SubRuleFunction;
+ if (SubMatchRules.count(Rule.MetaSubject))
+ SubRuleFunction = "isAttributeSubjectMatchSubRuleFor_" + Rule.getName();
+ else
+ SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor";
+ OS << " Case(\"" << Rule.getName() << "\", std::make_pair("
+ << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n";
+ }
+ OS << " Default(std::make_pair(None, "
+ "defaultIsAttributeSubjectMatchSubRuleFor));\n";
+ OS << "}\n\n";
+
+ // Generate the function that checks for the submatch rules.
+ OS << "const char *validAttributeSubjectMatchSubRules("
+ << AttributeSubjectMatchRule::EnumName << " Rule) {\n";
+ OS << " switch (Rule) {\n";
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << " case "
+ << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue()
+ << ":\n";
+ OS << " return \"'";
+ bool IsFirst = true;
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!IsFirst)
+ OS << ", '";
+ IsFirst = false;
+ if (Rule.isNegatedSubRule())
+ OS << "unless(";
+ OS << Rule.getName();
+ if (Rule.isNegatedSubRule())
+ OS << ')';
+ OS << "'";
+ }
+ OS << "\";\n";
+ }
+ OS << " default: return nullptr;\n";
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
template <typename Fn>
static void forEachUniqueSpelling(const Record &Attr, Fn &&F) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
@@ -2109,6 +2439,17 @@ void EmitClangAttrList(RecordKeeper &Rec
OS << "#undef PRAGMA_SPELLING_ATTR\n";
}
+// Emits the enumeration list for attributes.
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader(
+ "List of all attribute subject matching rules that Clang recognizes", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+ emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr);
+ PragmaAttributeSupport.emitMatchRuleList(OS);
+ OS << "#undef ATTR_MATCH_RULE\n";
+}
+
// Emits the code to read an attribute from a precompiled header.
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute deserialization code", OS);
@@ -2704,9 +3045,13 @@ static std::string GetSubjectWithSuffix(
return B + "Decl";
}
+static std::string functionNameForCustomAppertainsTo(const Record &Subject) {
+ return "is" + Subject.getName().str();
+}
+
static std::string GenerateCustomAppertainsTo(const Record &Subject,
raw_ostream &OS) {
- std::string FnName = "is" + Subject.getName().str();
+ std::string FnName = functionNameForCustomAppertainsTo(Subject);
// If this code has already been generated, simply return the previous
// instance of it.
@@ -2791,6 +3136,42 @@ static std::string GenerateAppertainsTo(
return FnName;
}
+static void
+emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport,
+ raw_ostream &OS) {
+ OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, "
+ << AttributeSubjectMatchRule::EnumName << " rule) {\n";
+ OS << " switch (rule) {\n";
+ for (const auto &Rule : PragmaAttributeSupport.Rules) {
+ if (Rule.isAbstractRule()) {
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n";
+ OS << " return false;\n";
+ continue;
+ }
+ std::vector<Record *> Subjects = Rule.getSubjects();
+ assert(!Subjects.empty() && "Missing subjects");
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " return ";
+ for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) {
+ // If the subject has custom code associated with it, use the function
+ // that was generated for GenerateAppertainsTo to check if the declaration
+ // is valid.
+ if ((*I)->isSubClassOf("SubsetSubject"))
+ OS << functionNameForCustomAppertainsTo(**I) << "(D)";
+ else
+ OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)";
+
+ if (I + 1 != E)
+ OS << " || ";
+ }
+ OS << ";\n";
+ }
+ OS << " }\n";
+ OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n";
+ OS << "}\n\n";
+}
+
static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
OS << "const AttributeList &) {\n";
@@ -2949,6 +3330,9 @@ static bool IsKnownToGCC(const Record &A
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Parsed attribute helpers", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+
// Get the list of parsed attributes, and accept the optional list of
// duplicates due to the ParseKind.
ParsedAttrMap Dupes;
@@ -2982,10 +3366,13 @@ void EmitClangAttrParsedAttrImpl(RecordK
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", " << I->second->isSubClassOf("StmtAttr");
SS << ", " << IsKnownToGCC(*I->second);
+ SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS);
+ SS << ", "
+ << PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
SS << " }";
if (I + 1 != E)
@@ -2997,6 +3384,9 @@ void EmitClangAttrParsedAttrImpl(RecordK
OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
OS << SS.str();
OS << "};\n\n";
+
+ // Generate the attribute match rules.
+ emitAttributeMatchRules(PragmaAttributeSupport, OS);
}
// Emits the kind list of parsed attributes
@@ -3136,6 +3526,11 @@ void EmitClangAttrParserStringSwitches(R
emitClangAttrLateParsedList(Records, OS);
}
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS) {
+ getPragmaAttributeSupport(Records).generateParsingHelpers(OS);
+}
+
class DocumentationData {
public:
const Record *Documentation;
@@ -3167,8 +3562,8 @@ enum SpellingKind {
Pragma = 1 << 5
};
-static void WriteDocumentation(const DocumentationData &Doc,
- raw_ostream &OS) {
+static void WriteDocumentation(RecordKeeper &Records,
+ const DocumentationData &Doc, raw_ostream &OS) {
// FIXME: there is no way to have a per-spelling category for the attribute
// documentation. This may not be a limiting factor since the spellings
// should generally be consistently applied across the category.
@@ -3250,7 +3645,7 @@ static void WriteDocumentation(const Doc
// List what spelling syntaxes the attribute supports.
OS << ".. csv-table:: Supported Syntaxes\n";
OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
- OS << " \"Pragma\"\n\n";
+ OS << " \"Pragma\", \"Pragma clang attribute\"\n\n";
OS << " \"";
if (SupportedSpellings & GNU) OS << "X";
OS << "\",\"";
@@ -3261,6 +3656,9 @@ static void WriteDocumentation(const Doc
if (SupportedSpellings & Keyword) OS << "X";
OS << "\", \"";
if (SupportedSpellings & Pragma) OS << "X";
+ OS << "\", \"";
+ if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute))
+ OS << "X";
OS << "\"\n\n";
// If the attribute is deprecated, print a message about it, and possibly
@@ -3327,7 +3725,40 @@ void EmitClangAttrDocs(RecordKeeper &Rec
// Walk over each of the attributes in the category and write out their
// documentation.
for (const auto &Doc : I.second)
- WriteDocumentation(Doc, OS);
+ WriteDocumentation(Records, Doc, OS);
+ }
+}
+
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS) {
+ PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records);
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+ unsigned NumAttrs = 0;
+ for (const auto &I : Attrs) {
+ if (Support.isAttributedSupported(*I.second))
+ ++NumAttrs;
+ }
+ OS << "#pragma clang attribute supports " << NumAttrs << " attributes:\n";
+ for (const auto &I : Attrs) {
+ if (!Support.isAttributedSupported(*I.second))
+ continue;
+ OS << I.first;
+ if (I.second->isValueUnset("Subjects")) {
+ OS << " ()\n";
+ continue;
+ }
+ const Record *SubjectObj = I.second->getValueAsDef("Subjects");
+ std::vector<Record *> Subjects =
+ SubjectObj->getValueAsListOfDefs("Subjects");
+ OS << " (";
+ for (const auto &Subject : llvm::enumerate(Subjects)) {
+ if (Subject.index())
+ OS << ", ";
+ OS << Support.SubjectsToRules.find(Subject.value())
+ ->getSecond()
+ .getEnumValueName();
+ }
+ OS << ")\n";
}
}
Modified: cfe/trunk/utils/TableGen/TableGen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGen.cpp?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGen.cpp (original)
+++ cfe/trunk/utils/TableGen/TableGen.cpp Tue Apr 18 09:33:39 2017
@@ -25,8 +25,10 @@ using namespace clang;
enum ActionType {
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
+ GenClangAttrSubjectMatchRulesParserStringSwitches,
GenClangAttrImpl,
GenClangAttrList,
+ GenClangAttrSubjectMatchRuleList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrHasAttributeImpl,
@@ -54,7 +56,8 @@ enum ActionType {
GenArmNeonTest,
GenAttrDocs,
GenDiagDocs,
- GenOptDocs
+ GenOptDocs,
+ GenTestPragmaAttributeSupportedAttributes
};
namespace {
@@ -66,10 +69,17 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrParserStringSwitches,
"gen-clang-attr-parser-string-switches",
"Generate all parser-related attribute string switches"),
+ clEnumValN(GenClangAttrSubjectMatchRulesParserStringSwitches,
+ "gen-clang-attr-subject-match-rules-parser-string-switches",
+ "Generate all parser-related attribute subject match rule"
+ "string switches"),
clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
"Generate clang attribute implementations"),
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
"Generate a clang attribute list"),
+ clEnumValN(GenClangAttrSubjectMatchRuleList,
+ "gen-clang-attr-subject-match-rule-list",
+ "Generate a clang attribute subject match rule list"),
clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
@@ -80,8 +90,7 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrSpellingListIndex,
"gen-clang-attr-spelling-index",
"Generate a clang attribute spelling index"),
- clEnumValN(GenClangAttrASTVisitor,
- "gen-clang-attr-ast-visitor",
+ clEnumValN(GenClangAttrASTVisitor, "gen-clang-attr-ast-visitor",
"Generate a recursive AST visitor for clang attributes"),
clEnumValN(GenClangAttrTemplateInstantiate,
"gen-clang-attr-template-instantiate",
@@ -137,8 +146,11 @@ cl::opt<ActionType> Action(
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
"Generate diagnostic documentation"),
- clEnumValN(GenOptDocs, "gen-opt-docs",
- "Generate option documentation")));
+ clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"),
+ clEnumValN(GenTestPragmaAttributeSupportedAttributes,
+ "gen-clang-test-pragma-attribute-supported-attributes",
+ "Generate a list of attributes supported by #pragma clang "
+ "attribute for testing purposes")));
cl::opt<std::string>
ClangComponent("clang-component",
@@ -153,12 +165,18 @@ bool ClangTableGenMain(raw_ostream &OS,
case GenClangAttrParserStringSwitches:
EmitClangAttrParserStringSwitches(Records, OS);
break;
+ case GenClangAttrSubjectMatchRulesParserStringSwitches:
+ EmitClangAttrSubjectMatchRulesParserStringSwitches(Records, OS);
+ break;
case GenClangAttrImpl:
EmitClangAttrImpl(Records, OS);
break;
case GenClangAttrList:
EmitClangAttrList(Records, OS);
break;
+ case GenClangAttrSubjectMatchRuleList:
+ EmitClangAttrSubjectMatchRuleList(Records, OS);
+ break;
case GenClangAttrPCHRead:
EmitClangAttrPCHRead(Records, OS);
break;
@@ -244,6 +262,9 @@ bool ClangTableGenMain(raw_ostream &OS,
case GenOptDocs:
EmitClangOptDocs(Records, OS);
break;
+ case GenTestPragmaAttributeSupportedAttributes:
+ EmitTestPragmaAttributeSupportedAttributes(Records, OS);
+ break;
}
return false;
Modified: cfe/trunk/utils/TableGen/TableGenBackends.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGenBackends.h?rev=300556&r1=300555&r2=300556&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGenBackends.h (original)
+++ cfe/trunk/utils/TableGen/TableGenBackends.h Tue Apr 18 09:33:39 2017
@@ -33,9 +33,12 @@ void EmitClangASTNodes(RecordKeeper &RK,
const std::string &N, const std::string &S);
void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS);
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS);
@@ -72,6 +75,9 @@ void EmitClangAttrDocs(RecordKeeper &Rec
void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS);
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS);
+
} // end namespace clang
#endif
More information about the cfe-commits
mailing list