forked from OSchip/llvm-project
Add #pragma clang attribute
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 llvm-svn: 300539
This commit is contained in:
parent
a4e79cca77
commit
0a849f47d2
|
@ -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.
|
||||
|
|
|
@ -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<["x86", "x86_64", "arm", "thumb"]> {
|
|||
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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -28,6 +28,11 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list
|
|||
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
|
||||
|
|
|
@ -461,7 +461,9 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
|
|||
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">;
|
||||
|
|
|
@ -979,6 +979,43 @@ def err_pragma_optimize_invalid_argument : Error<
|
|||
"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">;
|
||||
|
|
|
@ -750,6 +750,25 @@ def err_pragma_loop_compatibility : Error<
|
|||
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">;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,3 +2,9 @@ clang_tablegen(AttrParserStringSwitches.inc -gen-clang-attr-parser-string-switch
|
|||
-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)
|
||||
|
|
|
@ -184,6 +184,7 @@ class Parser : public CodeCompletionHandler {
|
|||
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.
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 Syntax, const IdentifierInfo *Scope,
|
|||
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -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,421 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
|
|||
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"
|
||||
}
|
||||
}
|
||||
|
||||
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>,
|
||||
llvm::function_ref<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 +2827,104 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -602,6 +602,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
|||
ConsumeToken();
|
||||
return false;
|
||||
|
||||
case tok::annot_pragma_attribute:
|
||||
HandlePragmaAttribute();
|
||||
return false;
|
||||
|
||||
case tok::eof:
|
||||
// Late template parsing can begin.
|
||||
if (getLangOpts().DelayedTemplateParsing)
|
||||
|
|
|
@ -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(Sema &S, const Decl *D) const {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -71,42 +71,35 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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, Decl *theEnumDecl, Decl *lastEnumConst,
|
|||
|
||||
// Process attributes.
|
||||
if (Attr) ProcessDeclAttributeList(S, New, Attr);
|
||||
AddPragmaAttributes(S, New);
|
||||
|
||||
// Register this decl in the current scope stack.
|
||||
New->setAccess(TheEnumDecl->getAccess());
|
||||
|
|
|
@ -6676,6 +6676,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
|
|||
// 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?
|
||||
|
|
|
@ -8445,6 +8445,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
|||
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 *S,
|
|||
NewTD->setInvalidDecl();
|
||||
|
||||
ProcessDeclAttributeList(S, NewTD, AttrList);
|
||||
AddPragmaAttributes(S, NewTD);
|
||||
|
||||
CheckTypedefForVariablyModifiedType(S, NewTD);
|
||||
Invalid |= NewTD->isInvalidDecl();
|
||||
|
|
|
@ -993,6 +993,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
|
|||
|
||||
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(SourceLocation AtProtoInterfaceLoc,
|
|||
|
||||
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(SourceLocation AtProtocolLoc,
|
|||
|
||||
if (attrList)
|
||||
ProcessDeclAttributeList(TUScope, PDecl, attrList);
|
||||
|
||||
AddPragmaAttributes(TUScope, PDecl);
|
||||
|
||||
if (PrevDecl)
|
||||
mergeDeclAttributes(PDecl, PrevDecl);
|
||||
|
||||
|
@ -1805,6 +1808,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
|||
|
||||
if (AttrList)
|
||||
ProcessDeclAttributeList(TUScope, CDecl, AttrList);
|
||||
AddPragmaAttributes(TUScope, CDecl);
|
||||
|
||||
CheckObjCDeclScope(CDecl);
|
||||
return ActOnObjCContainerStartDefinition(CDecl);
|
||||
|
@ -1954,6 +1958,7 @@ Decl *Sema::ActOnStartClassImplementation(
|
|||
ClassName, /*typeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr, ClassLoc,
|
||||
true);
|
||||
AddPragmaAttributes(TUScope, IDecl);
|
||||
IDecl->startDefinition();
|
||||
if (SDecl) {
|
||||
IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
|
||||
|
@ -3043,7 +3048,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
|||
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;
|
||||
|
|
|
@ -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)"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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))
|
||||
|
||||
@interface testInterface
|
||||
@end
|
||||
// CHECK-OBJC_INTERFACE: ObjCInterfaceDecl{{.*}} testInterface
|
||||
// CHECK-OBJC_INTERFACE-NEXT: AnnotateAttr{{.*}} "test"
|
||||
|
||||
@interface testInterface ()
|
||||
@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"
|
||||
|
||||
@interface testInterface (testCategory)
|
||||
@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
|
||||
@protocol testProtocol
|
||||
@end
|
||||
// CHECK-OBJC_PROTOCOL: ObjCProtocolDecl{{.*}} testProtocol
|
||||
// CHECK-OBJC_PROTOCOL-NEXT: AnnotateAttr{{.*}} "test"
|
||||
|
||||
@interface methodContainer
|
||||
- (void) testInstanceMethod;
|
||||
+ (void) testClassMethod;
|
||||
@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"
|
||||
|
||||
@implementation methodContainer
|
||||
- (void) testInstanceMethod { }
|
||||
+ (void) testClassMethod { }
|
||||
@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"
|
||||
@interface propertyContainer {
|
||||
int testIvar;
|
||||
// CHECK-FIELD: ObjCIvarDecl{{.*}} testIvar
|
||||
// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
|
||||
|
||||
}
|
||||
@property int testProperty;
|
||||
// CHECK-OBJC_PROPERTY: ObjCPropertyDecl{{.*}} testProperty
|
||||
// CHECK-OBJC_PROPERTY-NEXT: AnnotateAttr{{.*}} "test"
|
||||
|
||||
@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
|
|
@ -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)
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@end
|
||||
|
||||
// @implementation can't receive explicit attributes, so don't add the pragma
|
||||
// attributes to them.
|
||||
@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
|
||||
|
||||
@end
|
||||
|
||||
@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
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
@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
|
||||
|
||||
@end
|
||||
|
||||
@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.
|
||||
@interface testInterface1(testCat)
|
||||
// CHECK-LABEL: ObjCCategoryDecl{{.*}}testCat
|
||||
// CHECK-NOT: AnnotateAttr
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
|
||||
@end
|
||||
|
||||
@implementation testInterface1(testCat)
|
||||
// CHECK-LABEL: ObjCCategoryImplDecl{{.*}}testCat
|
||||
// CHECK-NOT: AnnotateAttr
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
|
||||
@end
|
||||
|
||||
// @class/@compatibility_alias declarations can't receive explicit attributes,
|
||||
// so don't add pragma attributes to them.
|
||||
@class testClass;
|
||||
// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testClass
|
||||
// CHECK-NOT: AnnotateAttr
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
|
||||
@compatibility_alias testCompat testInterface1;
|
||||
// CHECK-LABEL: ObjCCompatibleAliasDecl{{.*}}testCompat
|
||||
// CHECK-NOT: AnnotateAttr
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
|
||||
#pragma clang attribute pop // objc_subclassing_restricted
|
||||
|
||||
@interface testInterface3
|
||||
// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface3
|
||||
// CHECK-NEXT: AnnotateAttr{{.*}} "test"
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
@end
|
||||
|
||||
#pragma clang attribute pop // annotate("test")
|
||||
|
||||
@interface testInterface4
|
||||
// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface4
|
||||
// CHECK-NOT: AnnotateAttr
|
||||
// CHECK-NOT: ObjCSubclassingRestrictedAttr
|
||||
@end
|
|
@ -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@-1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
|
||||
// expected-error@-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@-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@-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@-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@-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
|
|
@ -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)
|
|
@ -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
|
|
@ -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@-1 {{expected unqualified-id}}
|
||||
// expected-error@-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@-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@-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@-1 {{use the GNU '__attribute__' syntax}}
|
|
@ -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@-1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
|
||||
// expected-error@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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
|
|
@ -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@-1 {{when applied to this declaration}}
|
||||
|
||||
void optnone2() { }
|
||||
|
||||
__attribute__((always_inline)) void optnone3() { } // expected-warning {{'always_inline' attribute ignored}}
|
||||
// expected-note@-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();
|
|
@ -284,6 +284,8 @@ if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@':
|
|||
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'. ***""") )
|
||||
|
|
|
@ -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@"
|
||||
|
|
|
@ -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(RecordKeeper &Records, raw_ostream &OS)
|
|||
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>, "
|
||||
"llvm::function_ref<Optional<attr::SubjectMatchRule> (StringRef, "
|
||||
"bool)>> isAttributeSubjectMatchRule(StringRef Name) {\n";
|
||||
OS << " return "
|
||||
"llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, "
|
||||
"llvm::function_ref<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 &Records, raw_ostream &OS) {
|
|||
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(const Record *R) {
|
|||
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,40 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
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}\n\n";
|
||||
}
|
||||
|
||||
static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
|
||||
OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
|
||||
OS << "const AttributeList &) {\n";
|
||||
|
@ -2949,6 +3328,9 @@ static bool IsKnownToGCC(const Record &Attr) {
|
|||
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 +3364,13 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
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 +3382,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
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 +3524,11 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
|
|||
emitClangAttrLateParsedList(Records, OS);
|
||||
}
|
||||
|
||||
void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
|
||||
raw_ostream &OS) {
|
||||
getPragmaAttributeSupport(Records).generateParsingHelpers(OS);
|
||||
}
|
||||
|
||||
class DocumentationData {
|
||||
public:
|
||||
const Record *Documentation;
|
||||
|
@ -3167,8 +3560,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 +3643,7 @@ static void WriteDocumentation(const DocumentationData &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 +3654,9 @@ static void WriteDocumentation(const DocumentationData &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 +3723,40 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
|
|||
// 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";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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, RecordKeeper &Records) {
|
|||
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, RecordKeeper &Records) {
|
|||
case GenOptDocs:
|
||||
EmitClangOptDocs(Records, OS);
|
||||
break;
|
||||
case GenTestPragmaAttributeSupportedAttributes:
|
||||
EmitTestPragmaAttributeSupportedAttributes(Records, OS);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -33,9 +33,12 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
|
|||
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 &Records, raw_ostream &OS);
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue