From 583e75cce441388bc562fa225d23499261a0091e Mon Sep 17 00:00:00 2001 From: Dimitry Andric <dim@FreeBSD.org> Date: Thu, 20 Apr 2017 21:20:51 +0000 Subject: [PATCH] Vendor import of clang trunk r300890: https://llvm.org/svn/llvm-project/cfe/trunk@300890 --- bindings/python/clang/__init__.py | 8 - bindings/python/clang/cindex.py | 112 +++- .../tests/cindex/test_translation_unit.py | 7 +- docs/LanguageExtensions.rst | 175 ++++++ docs/SanitizerCoverage.rst | 192 ------- docs/doxygen.cfg.in | 8 +- include/clang/AST/Decl.h | 5 +- include/clang/AST/StmtOpenMP.h | 193 +++++-- include/clang/AST/TypeLoc.h | 6 +- include/clang/Basic/Attr.td | 128 ++++- include/clang/Basic/AttrSubjectMatchRules.h | 32 ++ include/clang/Basic/CMakeLists.txt | 5 + include/clang/Basic/DiagnosticGroups.td | 8 +- include/clang/Basic/DiagnosticLexKinds.td | 6 +- include/clang/Basic/DiagnosticParseKinds.td | 37 ++ include/clang/Basic/DiagnosticSemaKinds.td | 35 +- include/clang/Basic/IdentifierTable.h | 13 + include/clang/Basic/LangOptions.def | 2 + include/clang/Basic/TokenKinds.def | 3 + include/clang/Driver/CLCompatOptions.td | 6 + include/clang/Driver/Options.td | 9 + include/clang/Index/IndexSymbol.h | 3 +- include/clang/Lex/Lexer.h | 2 + include/clang/Lex/Token.h | 8 + include/clang/Parse/CMakeLists.txt | 6 + include/clang/Parse/Parser.h | 7 + include/clang/Sema/AttributeList.h | 8 + include/clang/Sema/Sema.h | 32 ++ lib/AST/ASTContext.cpp | 6 +- lib/AST/Decl.cpp | 4 +- lib/AST/DeclPrinter.cpp | 11 + lib/AST/ExternalASTMerger.cpp | 39 +- lib/AST/ItaniumMangle.cpp | 4 +- lib/AST/StmtOpenMP.cpp | 98 ++-- lib/ASTMatchers/Dynamic/Registry.cpp | 1 + lib/Basic/Attributes.cpp | 11 + lib/Basic/OpenMPKinds.cpp | 6 +- lib/Basic/Targets.cpp | 9 +- lib/CodeGen/BackendUtil.cpp | 15 +- lib/CodeGen/CGCall.cpp | 83 ++- lib/CodeGen/CGCall.h | 1 - lib/CodeGen/CGDebugInfo.cpp | 39 +- lib/CodeGen/CGDecl.cpp | 8 +- lib/CodeGen/CGExpr.cpp | 38 +- lib/CodeGen/CGExprConstant.cpp | 6 +- lib/CodeGen/CGObjC.cpp | 18 +- lib/CodeGen/CGStmt.cpp | 2 +- lib/CodeGen/CGVTables.cpp | 7 +- lib/CodeGen/CodeGenModule.cpp | 13 +- lib/CodeGen/CodeGenModule.h | 7 +- lib/CodeGen/CodeGenTypeCache.h | 6 + lib/CodeGen/ModuleBuilder.cpp | 2 +- lib/Driver/SanitizerArgs.cpp | 46 +- lib/Driver/ToolChains/Clang.cpp | 36 +- lib/Driver/ToolChains/CommonArgs.cpp | 23 +- lib/Driver/ToolChains/CommonArgs.h | 6 +- lib/Driver/ToolChains/Gnu.cpp | 38 +- lib/Driver/ToolChains/MinGW.cpp | 24 +- lib/Driver/ToolChains/MinGW.h | 1 + lib/Format/FormatTokenLexer.cpp | 3 + lib/Format/TokenAnnotator.cpp | 7 +- lib/Frontend/CompilerInvocation.cpp | 5 +- lib/Headers/smmintrin.h | 239 +++----- lib/Headers/xmmintrin.h | 2 +- lib/Index/CommentToXML.cpp | 4 +- lib/Index/IndexDecl.cpp | 14 +- lib/Index/IndexSymbol.cpp | 2 + lib/Index/IndexTypeSourceInfo.cpp | 5 +- lib/Index/IndexingContext.cpp | 1 + lib/Index/IndexingContext.h | 3 +- lib/Lex/Lexer.cpp | 67 ++- lib/Lex/ModuleMap.cpp | 3 +- lib/Lex/PPLexerChange.cpp | 5 +- lib/Parse/ParsePragma.cpp | 534 +++++++++++++++++ lib/Parse/ParseStmt.cpp | 4 + lib/Parse/Parser.cpp | 10 + lib/Sema/AttributeList.cpp | 21 + lib/Sema/JumpDiagnostics.cpp | 9 + lib/Sema/Sema.cpp | 67 +-- lib/Sema/SemaAttr.cpp | 213 +++++++ lib/Sema/SemaCXXScopeSpec.cpp | 2 + lib/Sema/SemaChecking.cpp | 4 - lib/Sema/SemaCoroutine.cpp | 85 ++- lib/Sema/SemaDecl.cpp | 5 + lib/Sema/SemaDeclAttr.cpp | 28 +- lib/Sema/SemaDeclCXX.cpp | 2 + lib/Sema/SemaDeclObjC.cpp | 13 +- lib/Sema/SemaExpr.cpp | 6 + lib/Sema/SemaOpenMP.cpp | 84 ++- lib/Sema/SemaStmt.cpp | 1 + lib/Sema/SemaTemplate.cpp | 21 +- lib/Sema/SemaTemplateInstantiate.cpp | 7 +- lib/Serialization/ASTReaderStmt.cpp | 7 + lib/Serialization/ASTWriterStmt.cpp | 7 + test/CodeGen/debug-info-vla.c | 4 +- test/CodeGen/fp-contract-on-asm.c | 18 + test/CodeGen/thinlto-backend-option.ll | 13 + test/CodeGenCXX/cxx1z-class-deduction.cpp | 21 + test/CodeGenCXX/debug-info.cpp | 2 +- test/CodeGenCXX/ubsan-suppress-checks.cpp | 28 +- .../unaligned-duplicated-mangle-name.cpp | 20 + test/CodeGenCXX/windows-itanium-dllexport.cpp | 25 + test/CodeGenCoroutines/coro-alloc.cpp | 23 +- test/CodeGenObjC/empty-collection-literals.m | 2 +- .../amdgpu-debug-info-variable-expression.cl | 3 +- test/CodeGenOpenCL/byval.cl | 18 + test/CodeGenOpenCL/lifetime.cl | 15 + test/CoverageMapping/pr32679.cpp | 32 ++ test/Driver/arm-default-build-attributes.s | 20 + test/Driver/avr-mmcu.c | 5 + test/Driver/cl-options.c | 3 + test/Driver/clang_f_opts.c | 5 + test/Driver/fopenmp.c | 16 +- test/Driver/fsanitize-coverage.c | 21 +- test/Driver/linux-as.c | 27 + test/Driver/modules-ts.cpp | 2 +- test/FixIt/fixit-pragma-attribute.c | 6 + test/FixIt/fixit-pragma-attribute.cpp | 83 +++ test/Index/Core/index-source.cpp | 20 + test/Lexer/cxx1z-trigraphs.cpp | 7 +- test/Lexer/newline-nul.c | Bin 0 -> 332 bytes test/Misc/ast-print-out-of-line-func.cpp | 41 ++ ...agma-attribute-cxx-subject-match-rules.cpp | 169 ++++++ test/Misc/pragma-attribute-cxx.cpp | 106 ++++ ...ragma-attribute-objc-subject-match-rules.m | 113 ++++ test/Misc/pragma-attribute-objc.m | 164 ++++++ test/Misc/pragma-attribute-strict-subjects.c | 222 ++++++++ ...a-attribute-supported-attributes-list.test | 64 +++ test/Modules/odr_hash.cpp | 191 +++---- .../umbrella-header-include-builtin.mm | 8 + .../distribute_parallel_for_ast_print.cpp | 37 +- .../distribute_parallel_for_messages.cpp | 118 ++++ test/Parser/editor-placeholder-recovery.cpp | 71 +++ test/Parser/placeholder-recovery.m | 13 +- test/Parser/pragma-attribute-declspec.cpp | 13 + test/Parser/pragma-attribute.cpp | 181 ++++++ test/Preprocessor/init.c | 3 + test/Sema/alloc-align-attr.c | 6 +- test/Sema/attr-availability.c | 2 +- test/Sema/attr-selectany.c | 3 +- test/Sema/pragma-attribute-strict-subjects.c | 153 +++++ test/Sema/pragma-attribute.c | 47 ++ test/SemaCXX/attr-selectany.cpp | 2 +- .../coroutine-unhandled_exception-warning.cpp | 15 +- test/SemaCXX/coroutines.cpp | 52 ++ ...xx1z-class-template-argument-deduction.cpp | 35 ++ test/SemaCXX/warn-unused-result.cpp | 46 ++ test/SemaObjC/foreach.m | 24 + test/lit.cfg | 2 + test/lit.site.cfg.in | 1 + tools/driver/cc1as_main.cpp | 4 +- unittests/Driver/ToolChainTest.cpp | 2 +- unittests/Format/FormatTestComments.cpp | 2 +- utils/TableGen/ClangAttrEmitter.cpp | 536 +++++++++++++++++- utils/TableGen/TableGen.cpp | 31 +- utils/TableGen/TableGenBackends.h | 6 + 156 files changed, 5023 insertions(+), 1053 deletions(-) create mode 100644 include/clang/Basic/AttrSubjectMatchRules.h create mode 100644 test/CodeGen/fp-contract-on-asm.c create mode 100644 test/CodeGen/thinlto-backend-option.ll create mode 100644 test/CodeGenCXX/cxx1z-class-deduction.cpp create mode 100644 test/CodeGenCXX/unaligned-duplicated-mangle-name.cpp create mode 100644 test/CodeGenOpenCL/byval.cl create mode 100644 test/CodeGenOpenCL/lifetime.cl create mode 100644 test/CoverageMapping/pr32679.cpp create mode 100644 test/Driver/arm-default-build-attributes.s create mode 100644 test/Driver/avr-mmcu.c create mode 100644 test/FixIt/fixit-pragma-attribute.c create mode 100644 test/FixIt/fixit-pragma-attribute.cpp create mode 100644 test/Lexer/newline-nul.c create mode 100644 test/Misc/pragma-attribute-cxx-subject-match-rules.cpp create mode 100644 test/Misc/pragma-attribute-cxx.cpp create mode 100644 test/Misc/pragma-attribute-objc-subject-match-rules.m create mode 100644 test/Misc/pragma-attribute-objc.m create mode 100644 test/Misc/pragma-attribute-strict-subjects.c create mode 100644 test/Misc/pragma-attribute-supported-attributes-list.test create mode 100644 test/OpenMP/distribute_parallel_for_messages.cpp create mode 100644 test/Parser/editor-placeholder-recovery.cpp create mode 100644 test/Parser/pragma-attribute-declspec.cpp create mode 100644 test/Parser/pragma-attribute.cpp create mode 100644 test/Sema/pragma-attribute-strict-subjects.c create mode 100644 test/Sema/pragma-attribute.c diff --git a/bindings/python/clang/__init__.py b/bindings/python/clang/__init__.py index fba49e38c9be..88f30812383f 100644 --- a/bindings/python/clang/__init__.py +++ b/bindings/python/clang/__init__.py @@ -20,13 +20,5 @@ The available modules are: Bindings for the Clang indexing library. """ - -# Python 3 uses unicode for strings. The bindings, in particular the interaction -# with ctypes, need modifying to handle conversions between unicode and -# c-strings. -import sys -if sys.version_info[0] != 2: - raise Exception("Only Python 2 is supported.") - __all__ = ['cindex'] diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 48fc8b13a209..0cd5617e43a8 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -67,6 +67,60 @@ import collections import clang.enumerations +import sys +if sys.version_info[0] == 3: + # Python 3 strings are unicode, translate them to/from utf8 for C-interop. + class c_interop_string(c_char_p): + + def __init__(self, p=None): + if p is None: + p = "" + if isinstance(p, str): + p = p.encode("utf8") + super(c_char_p, self).__init__(p) + + def __str__(self): + return self.value + + @property + def value(self): + if super(c_char_p, self).value is None: + return None + return super(c_char_p, self).value.decode("utf8") + + @classmethod + def from_param(cls, param): + if isinstance(param, str): + return cls(param) + if isinstance(param, bytes): + return cls(param) + raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__)) + + @staticmethod + def to_python_string(x, *args): + return x.value + + def b(x): + if isinstance(x, bytes): + return x + return x.encode('utf8') + + xrange = range + +elif sys.version_info[0] == 2: + # Python 2 strings are utf8 byte strings, no translation is needed for + # C-interop. + c_interop_string = c_char_p + + def _to_python_string(x, *args): + return x + + c_interop_string.to_python_string = staticmethod(_to_python_string) + + def b(x): + return x + + # ctypes doesn't implicitly convert c_void_p to the appropriate wrapper # object. This is a problem, because it means that from_parameter will see an # integer and pass the wrong value on platforms where int != void*. Work around @@ -157,6 +211,7 @@ class _CXString(Structure): assert isinstance(res, _CXString) return conf.lib.clang_getCString(res) + class SourceLocation(Structure): """ A SourceLocation represents a particular location within a source file. @@ -596,7 +651,7 @@ class CursorKind(BaseEnumeration): @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" - return filter(None, CursorKind._kinds) + return [x for x in CursorKind._kinds if not x is None] def is_declaration(self): """Test if this is a declaration kind.""" @@ -2128,7 +2183,7 @@ class Type(Structure): """ Retrieve the offset of a field in the record. """ - return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname)) + return conf.lib.clang_Type_getOffsetOf(self, fieldname) def get_ref_qualifier(self): """ @@ -2239,7 +2294,7 @@ class CompletionChunk: def spelling(self): if self.__kindNumber in SpellingCache: return SpellingCache[self.__kindNumber] - return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling + return conf.lib.clang_getCompletionChunkText(self.cs, self.key) # We do not use @CachedProperty here, as the manual implementation is # apparently still significantly faster. Please profile carefully if you @@ -2345,7 +2400,7 @@ class CompletionString(ClangObject): return " | ".join([str(a) for a in self]) \ + " || Priority: " + str(self.priority) \ + " || Availability: " + str(self.availability) \ - + " || Brief comment: " + str(self.briefComment.spelling) + + " || Brief comment: " + str(self.briefComment) availabilityKinds = { 0: CompletionChunk.Kind("Available"), @@ -2542,7 +2597,7 @@ class TranslationUnit(ClangObject): args_array = None if len(args) > 0: - args_array = (c_char_p * len(args))(* args) + args_array = (c_char_p * len(args))(*[b(x) for x in args]) unsaved_array = None if len(unsaved_files) > 0: @@ -2551,8 +2606,8 @@ class TranslationUnit(ClangObject): if hasattr(contents, "read"): contents = contents.read() - unsaved_array[i].name = name - unsaved_array[i].contents = contents + unsaved_array[i].name = b(name) + unsaved_array[i].contents = b(contents) unsaved_array[i].length = len(contents) ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array, @@ -2797,8 +2852,8 @@ class TranslationUnit(ClangObject): print(value) if not isinstance(value, str): raise TypeError('Unexpected unsaved file contents.') - unsaved_files_array[i].name = name - unsaved_files_array[i].contents = value + unsaved_files_array[i].name = b(name) + unsaved_files_array[i].contents = b(value) unsaved_files_array[i].length = len(value) ptr = conf.lib.clang_codeCompleteAt(self, path, line, column, unsaved_files_array, len(unsaved_files), options) @@ -2833,7 +2888,7 @@ class File(ClangObject): @property def name(self): """Return the complete file and path name of the file.""" - return conf.lib.clang_getCString(conf.lib.clang_getFileName(self)) + return conf.lib.clang_getFileName(self) @property def time(self): @@ -3064,7 +3119,7 @@ functionList = [ [c_object_p]), ("clang_CompilationDatabase_fromDirectory", - [c_char_p, POINTER(c_uint)], + [c_interop_string, POINTER(c_uint)], c_object_p, CompilationDatabase.from_result), @@ -3074,7 +3129,7 @@ functionList = [ CompileCommands.from_result), ("clang_CompilationDatabase_getCompileCommands", - [c_object_p, c_char_p], + [c_object_p, c_interop_string], c_object_p, CompileCommands.from_result), @@ -3109,7 +3164,7 @@ functionList = [ c_uint), ("clang_codeCompleteAt", - [TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int], + [TranslationUnit, c_interop_string, c_int, c_int, c_void_p, c_int, c_int], POINTER(CCRStructure)), ("clang_codeCompleteGetDiagnostic", @@ -3125,7 +3180,7 @@ functionList = [ c_object_p), ("clang_createTranslationUnit", - [Index, c_char_p], + [Index, c_interop_string], c_object_p), ("clang_CXXConstructor_isConvertingConstructor", @@ -3215,7 +3270,8 @@ functionList = [ ("clang_formatDiagnostic", [Diagnostic, c_uint], - _CXString), + _CXString, + _CXString.from_result), ("clang_getArgType", [Type, c_uint], @@ -3255,7 +3311,8 @@ functionList = [ ("clang_getCompletionBriefComment", [c_void_p], - _CXString), + _CXString, + _CXString.from_result), ("clang_getCompletionChunkCompletionString", [c_void_p, c_int], @@ -3267,7 +3324,8 @@ functionList = [ ("clang_getCompletionChunkText", [c_void_p, c_int], - _CXString), + _CXString, + _CXString.from_result), ("clang_getCompletionPriority", [c_void_p], @@ -3275,7 +3333,8 @@ functionList = [ ("clang_getCString", [_CXString], - c_char_p), + c_interop_string, + c_interop_string.to_python_string), ("clang_getCursor", [TranslationUnit, SourceLocation], @@ -3422,12 +3481,13 @@ functionList = [ Type.from_result), ("clang_getFile", - [TranslationUnit, c_char_p], + [TranslationUnit, c_interop_string], c_object_p), ("clang_getFileName", [File], - _CXString), # TODO go through _CXString.from_result? + _CXString, + _CXString.from_result), ("clang_getFileTime", [File], @@ -3551,7 +3611,8 @@ functionList = [ ("clang_getTUResourceUsageName", [c_uint], - c_char_p), + c_interop_string, + c_interop_string.to_python_string), ("clang_getTypeDeclaration", [Type], @@ -3646,7 +3707,7 @@ functionList = [ bool), ("clang_parseTranslationUnit", - [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int], + [Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int], c_object_p), ("clang_reparseTranslationUnit", @@ -3654,7 +3715,7 @@ functionList = [ c_int), ("clang_saveTranslationUnit", - [TranslationUnit, c_char_p, c_uint], + [TranslationUnit, c_interop_string, c_uint], c_int), ("clang_tokenize", @@ -3726,7 +3787,7 @@ functionList = [ Type.from_result), ("clang_Type_getOffsetOf", - [Type, c_char_p], + [Type, c_interop_string], c_longlong), ("clang_Type_getSizeOf", @@ -3785,7 +3846,8 @@ def register_functions(lib, ignore_errors): def register(item): return register_function(lib, item, ignore_errors) - map(register, functionList) + for f in functionList: + register(f) class Config: library_path = None diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py index be6cd671ae0c..65d1ee02ffa4 100644 --- a/bindings/python/tests/cindex/test_translation_unit.py +++ b/bindings/python/tests/cindex/test_translation_unit.py @@ -59,9 +59,12 @@ int SOME_DEFINE; assert spellings[-1] == 'y' def test_unsaved_files_2(): - import StringIO + try: + from StringIO import StringIO + except: + from io import StringIO tu = TranslationUnit.from_source('fake.c', unsaved_files = [ - ('fake.c', StringIO.StringIO('int x;'))]) + ('fake.c', StringIO('int x;'))]) spellings = [c.spelling for c in tu.cursor.get_children()] assert spellings[-1] == 'x' diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index a8fb4623b637..187dae751be1 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -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. diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst index 8ff5bdf3a3d2..d69afba4daca 100644 --- a/docs/SanitizerCoverage.rst +++ b/docs/SanitizerCoverage.rst @@ -25,17 +25,10 @@ following compile-time flags: **extra** slowdown). * ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown). -You may also specify ``-fsanitize-coverage=indirect-calls`` for -additional `caller-callee coverage`_. - At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``, ``LSAN_OPTIONS``, ``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as appropriate. For the standalone coverage mode, use ``UBSAN_OPTIONS``. -To get `Coverage counters`_, add ``-fsanitize-coverage=8bit-counters`` -to one of the above compile-time flags. At runtime, use -``*SAN_OPTIONS=coverage=1:coverage_counters=1``. - Example: .. code-block:: console @@ -199,135 +192,9 @@ edges by introducing new dummy blocks and then instruments those blocks: |/ C -Bitset -====== - -When ``coverage_bitset=1`` run-time flag is given, the coverage will also be -dumped as a bitset (text file with 1 for blocks that have been executed and 0 -for blocks that were not). - -.. code-block:: console - - % clang++ -fsanitize=address -fsanitize-coverage=edge cov.cc - % ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out - main - % ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out 1 - foo - main - % head *bitset* - ==> a.out.38214.bitset-sancov <== - 01101 - ==> a.out.6128.bitset-sancov <== - 11011% - -For a given executable the length of the bitset is always the same (well, -unless dlopen/dlclose come into play), so the bitset coverage can be -easily used for bitset-based corpus distillation. - -Caller-callee coverage -====================== - -**Deprecated, don't use** - -Every indirect function call is instrumented with a run-time function call that -captures caller and callee. At the shutdown time the process dumps a separate -file called ``caller-callee.PID.sancov`` which contains caller/callee pairs as -pairs of lines (odd lines are callers, even lines are callees) - -.. code-block:: console - - a.out 0x4a2e0c - a.out 0x4a6510 - a.out 0x4a2e0c - a.out 0x4a87f0 - -Current limitations: - -* Only the first 14 callees for every caller are recorded, the rest are silently - ignored. -* The output format is not very compact since caller and callee may reside in - different modules and we need to spell out the module names. -* The routine that dumps the output is not optimized for speed -* Only Linux x86_64 is tested so far. -* Sandboxes are not supported. - -Coverage counters -================= - -**Deprecated, don't use** - -This experimental feature is inspired by -`AFL <http://lcamtuf.coredump.cx/afl/technical_details.txt>`__'s coverage -instrumentation. With additional compile-time and run-time flags you can get -more sensitive coverage information. In addition to boolean values assigned to -every basic block (edge) the instrumentation will collect imprecise counters. -On exit, every counter will be mapped to a 8-bit bitset representing counter -ranges: ``1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+`` and those 8-bit bitsets will -be dumped to disk. - -.. code-block:: console - - % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=edge,8bit-counters - % ASAN_OPTIONS="coverage=1:coverage_counters=1" ./a.out - % ls -l *counters-sancov - ... a.out.17110.counters-sancov - % xxd *counters-sancov - 0000000: 0001 0100 01 - -These counters may also be used for in-process coverage-guided fuzzers. See -``include/sanitizer/coverage_interface.h``: - -.. code-block:: c++ - - // The coverage instrumentation may optionally provide imprecise counters. - // Rather than exposing the counter values to the user we instead map - // the counters to a bitset. - // Every counter is associated with 8 bits in the bitset. - // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+ - // The i-th bit is set to 1 if the counter value is in the i-th range. - // This counter-based coverage implementation is *not* thread-safe. - - // Returns the number of registered coverage counters. - uintptr_t __sanitizer_get_number_of_counters(); - // Updates the counter 'bitset', clears the counters and returns the number of - // new bits in 'bitset'. - // If 'bitset' is nullptr, only clears the counters. - // Otherwise 'bitset' should be at least - // __sanitizer_get_number_of_counters bytes long and 8-aligned. - uintptr_t - __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); - -Tracing basic blocks -==================== - -**Deprecated, don't use** - -Experimental support for basic block (or edge) tracing. -With ``-fsanitize-coverage=trace-bb`` the compiler will insert -``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge -(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``). -Example: - -.. code-block:: console - - % clang -g -fsanitize=address -fsanitize-coverage=edge,trace-bb foo.cc - % ASAN_OPTIONS=coverage=1 ./a.out - -This will produce two files after the process exit: -`trace-points.PID.sancov` and `trace-events.PID.sancov`. -The first file will contain a textual description of all the instrumented points in the program -in the form that you can feed into llvm-symbolizer (e.g. `a.out 0x4dca89`), one per line. -The second file will contain the actual execution trace as a sequence of 4-byte integers --- these integers are the indices into the array of instrumented points (the first file). - -Basic block tracing is currently supported only for single-threaded applications. - - Tracing PCs =========== -**Deprecated, don't use** - *Experimental* feature similar to tracing basic blocks, but with a different API. With ``-fsanitize-coverage=trace-pc`` the compiler will insert ``__sanitizer_cov_trace_pc()`` on every edge. @@ -529,62 +396,3 @@ memory-mapped file as soon as it collected. Note that on 64-bit platforms, this method writes 2x more data than the default, because it stores full PC values instead of 32-bit offsets. -In-process fuzzing -================== - -Coverage data could be useful for fuzzers and sometimes it is preferable to run -a fuzzer in the same process as the code being fuzzed (in-process fuzzer). - -You can use ``__sanitizer_get_total_unique_coverage()`` from -``<sanitizer/coverage_interface.h>`` which returns the number of currently -covered entities in the program. This will tell the fuzzer if the coverage has -increased after testing every new input. - -If a fuzzer finds a bug in the ASan run, you will need to save the reproducer -before exiting the process. Use ``__asan_set_death_callback`` from -``<sanitizer/asan_interface.h>`` to do that. - -An example of such fuzzer can be found in `the LLVM tree -<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/README.txt?view=markup>`_. - -Performance -=========== - -This coverage implementation is **fast**. With function-level coverage -(``-fsanitize-coverage=func``) the overhead is not measurable. With -basic-block-level coverage (``-fsanitize-coverage=bb``) the overhead varies -between 0 and 25%. - -============== ========= ========= ========= ========= ========= ========= - benchmark cov0 cov1 diff 0-1 cov2 diff 0-2 diff 1-2 -============== ========= ========= ========= ========= ========= ========= - 400.perlbench 1296.00 1307.00 1.01 1465.00 1.13 1.12 - 401.bzip2 858.00 854.00 1.00 1010.00 1.18 1.18 - 403.gcc 613.00 617.00 1.01 683.00 1.11 1.11 - 429.mcf 605.00 582.00 0.96 610.00 1.01 1.05 - 445.gobmk 896.00 880.00 0.98 1050.00 1.17 1.19 - 456.hmmer 892.00 892.00 1.00 918.00 1.03 1.03 - 458.sjeng 995.00 1009.00 1.01 1217.00 1.22 1.21 -462.libquantum 497.00 492.00 0.99 534.00 1.07 1.09 - 464.h264ref 1461.00 1467.00 1.00 1543.00 1.06 1.05 - 471.omnetpp 575.00 590.00 1.03 660.00 1.15 1.12 - 473.astar 658.00 652.00 0.99 715.00 1.09 1.10 - 483.xalancbmk 471.00 491.00 1.04 582.00 1.24 1.19 - 433.milc 616.00 627.00 1.02 627.00 1.02 1.00 - 444.namd 602.00 601.00 1.00 654.00 1.09 1.09 - 447.dealII 630.00 634.00 1.01 653.00 1.04 1.03 - 450.soplex 365.00 368.00 1.01 395.00 1.08 1.07 - 453.povray 427.00 434.00 1.02 495.00 1.16 1.14 - 470.lbm 357.00 375.00 1.05 370.00 1.04 0.99 - 482.sphinx3 927.00 928.00 1.00 1000.00 1.08 1.08 -============== ========= ========= ========= ========= ========= ========= - -Why another coverage? -===================== - -Why did we implement yet another code coverage? - * We needed something that is lightning fast, plays well with - AddressSanitizer, and does not significantly increase the binary size. - * Traditional coverage implementations based in global counters - `suffer from contention on counters - <https://groups.google.com/forum/#!topic/llvm-dev/cDqYgnxNEhY>`_. diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in index ef96605ed1c1..13ed72222bea 100644 --- a/docs/doxygen.cfg.in +++ b/docs/doxygen.cfg.in @@ -132,7 +132,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -144,7 +144,7 @@ FULL_PATH_NAMES = NO # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = ../.. +STRIP_FROM_PATH = @abs_srcdir@/.. # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -153,7 +153,7 @@ STRIP_FROM_PATH = ../.. # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = @abs_srcdir@/../include # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -513,7 +513,7 @@ SHOW_GROUPED_MEMB_INC = NO # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. -FORCE_LOCAL_INCLUDES = NO +FORCE_LOCAL_INCLUDES = YES # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ad723a3e2b8f..573ea55de1fd 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2082,10 +2082,7 @@ public: const Attr *getUnusedResultAttr() const; /// \brief Returns true if this function or its return type has the - /// warn_unused_result attribute. If the return type has the attribute and - /// this function is a method of the return type's class, then false will be - /// returned to avoid spurious warnings on member methods such as assignment - /// operators. + /// warn_unused_result attribute. bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; } /// \brief Returns the storage class as written in the source. For the diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index 13af142ca3ab..463af06fddab 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -318,8 +318,9 @@ class OMPLoopDirective : public OMPExecutableDirective { /// \brief Offsets to the stored exprs. /// This enumeration contains offsets to all the pointers to children /// expressions stored in OMPLoopDirective. - /// The first 9 children are nesessary for all the loop directives, and - /// the next 10 are specific to the worksharing ones. + /// The first 9 children are necessary for all the loop directives, + /// the next 8 are specific to the worksharing ones, and the next 11 are + /// used for combined constructs containing two pragmas associated to loops. /// After the fixed children, three arrays of length CollapsedNum are /// allocated: loop counters, their updates and final values. /// PrevLowerBound and PrevUpperBound are used to communicate blocking @@ -344,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective { // specify the offset to the end (and start of the following counters/ // updates/finals arrays). DefaultEnd = 9, - // The following 12 exprs are used by worksharing and distribute loops only. + // The following 8 exprs are used by worksharing and distribute loops only. IsLastIterVariableOffset = 9, LowerBoundVariableOffset = 10, UpperBoundVariableOffset = 11, @@ -353,13 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective { NextLowerBoundOffset = 14, NextUpperBoundOffset = 15, NumIterationsOffset = 16, + // Offset to the end for worksharing loop directives. + WorksharingEnd = 17, PrevLowerBoundVariableOffset = 17, PrevUpperBoundVariableOffset = 18, DistIncOffset = 19, PrevEnsureUpperBoundOffset = 20, + CombinedLowerBoundVariableOffset = 21, + CombinedUpperBoundVariableOffset = 22, + CombinedEnsureUpperBoundOffset = 23, + CombinedInitOffset = 24, + CombinedConditionOffset = 25, + CombinedNextLowerBoundOffset = 26, + CombinedNextUpperBoundOffset = 27, // Offset to the end (and start of the following counters/updates/finals - // arrays) for worksharing loop directives. - WorksharingEnd = 21, + // arrays) for combined distribute loop directives. + CombinedDistributeEnd = 28, }; /// \brief Get the counters storage. @@ -423,11 +433,12 @@ protected: /// \brief Offset to the start of children expression arrays. static unsigned getArraysOffset(OpenMPDirectiveKind Kind) { - return (isOpenMPWorksharingDirective(Kind) || - isOpenMPTaskLoopDirective(Kind) || - isOpenMPDistributeDirective(Kind)) - ? WorksharingEnd - : DefaultEnd; + if (isOpenMPLoopBoundSharingDirective(Kind)) + return CombinedDistributeEnd; + if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) || + isOpenMPDistributeDirective(Kind)) + return WorksharingEnd; + return DefaultEnd; } /// \brief Children number. @@ -515,33 +526,60 @@ protected: *std::next(child_begin(), NumIterationsOffset) = NI; } void setPrevLowerBoundVariable(Expr *PrevLB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB; } void setPrevUpperBoundVariable(Expr *PrevUB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB; } void setDistInc(Expr *DistInc) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), DistIncOffset) = DistInc; } void setPrevEnsureUpperBound(Expr *PrevEUB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB; } + void setCombinedLowerBoundVariable(Expr *CombLB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB; + } + void setCombinedUpperBoundVariable(Expr *CombUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB; + } + void setCombinedEnsureUpperBound(Expr *CombEUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB; + } + void setCombinedInit(Expr *CombInit) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedInitOffset) = CombInit; + } + void setCombinedCond(Expr *CombCond) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedConditionOffset) = CombCond; + } + void setCombinedNextLowerBound(Expr *CombNLB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB; + } + void setCombinedNextUpperBound(Expr *CombNUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB; + } void setCounters(ArrayRef<Expr *> A); void setPrivateCounters(ArrayRef<Expr *> A); void setInits(ArrayRef<Expr *> A); @@ -549,6 +587,33 @@ protected: void setFinals(ArrayRef<Expr *> A); public: + /// The expressions built to support OpenMP loops in combined/composite + /// pragmas (e.g. pragma omp distribute parallel for) + struct DistCombinedHelperExprs { + /// DistributeLowerBound - used when composing 'omp distribute' with + /// 'omp for' in a same construct. + Expr *LB; + /// DistributeUpperBound - used when composing 'omp distribute' with + /// 'omp for' in a same construct. + Expr *UB; + /// DistributeEnsureUpperBound - used when composing 'omp distribute' + /// with 'omp for' in a same construct, EUB depends on DistUB + Expr *EUB; + /// Distribute loop iteration variable init used when composing 'omp + /// distribute' + /// with 'omp for' in a same construct + Expr *Init; + /// Distribute Loop condition used when composing 'omp distribute' + /// with 'omp for' in a same construct + Expr *Cond; + /// Update of LowerBound for statically sheduled omp loops for + /// outer loop in combined constructs (e.g. 'distribute parallel for') + Expr *NLB; + /// Update of UpperBound for statically sheduled omp loops for + /// outer loop in combined constructs (e.g. 'distribute parallel for') + Expr *NUB; + }; + /// \brief The expressions built for the OpenMP loop CodeGen for the /// whole collapsed loop nest. struct HelperExprs { @@ -611,6 +676,9 @@ public: /// Init statement for all captured expressions. Stmt *PreInits; + /// Expressions used when combining OpenMP loop pragmas + DistCombinedHelperExprs DistCombinedFields; + /// \brief Check if all the expressions are built (does not check the /// worksharing ones). bool builtAll() { @@ -654,6 +722,13 @@ public: Finals[i] = nullptr; } PreInits = nullptr; + DistCombinedFields.LB = nullptr; + DistCombinedFields.UB = nullptr; + DistCombinedFields.EUB = nullptr; + DistCombinedFields.Init = nullptr; + DistCombinedFields.Cond = nullptr; + DistCombinedFields.NLB = nullptr; + DistCombinedFields.NUB = nullptr; } }; @@ -757,37 +832,71 @@ public: *std::next(child_begin(), NumIterationsOffset))); } Expr *getPrevLowerBoundVariable() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevLowerBoundVariableOffset))); } Expr *getPrevUpperBoundVariable() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevUpperBoundVariableOffset))); } Expr *getDistInc() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), DistIncOffset))); } Expr *getPrevEnsureUpperBound() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevEnsureUpperBoundOffset))); } + Expr *getCombinedLowerBoundVariable() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedLowerBoundVariableOffset))); + } + Expr *getCombinedUpperBoundVariable() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedUpperBoundVariableOffset))); + } + Expr *getCombinedEnsureUpperBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedEnsureUpperBoundOffset))); + } + Expr *getCombinedInit() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedInitOffset))); + } + Expr *getCombinedCond() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedConditionOffset))); + } + Expr *getCombinedNextLowerBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedNextLowerBoundOffset))); + } + Expr *getCombinedNextUpperBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedNextUpperBoundOffset))); + } const Stmt *getBody() const { // This relies on the loop form is already checked by Sema. Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 525f848a9fab..ad95f6f8effa 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1544,7 +1544,11 @@ class DependentSizedArrayTypeLoc : public InheritingConcreteTypeLoc<ArrayTypeLoc, DependentSizedArrayTypeLoc, DependentSizedArrayType> { - +public: + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + ArrayTypeLoc::initializeLocal(Context, Loc); + setSizeExpr(getTypePtr()->getSizeExpr()); + } }; class VariableArrayTypeLoc : diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index c5d2c7fc618b..44893fbd036c 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -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,112 @@ 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]; +} + +// Aggregate attribute subject match rules are abstract match rules that can't +// be used directly in #pragma clang attribute. Instead, users have to use +// subject match rules that correspond to attribute subjects that derive from +// the specified subject. +class AttrSubjectMatcherAggregateRule<AttrSubject subject> { + AttrSubject Subject = subject; +} + +def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>; + class Attr { // The various ways in which an attribute can be spelled in source list<Spelling> Spellings; @@ -305,6 +413,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 +594,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]; } @@ -536,7 +655,7 @@ def Availability : InheritableAttr { } }]; let HasCustomParsing = 1; let DuplicatesAllowedWhileMerging = 1; -// let Subjects = SubjectList<[Named]>; + let Subjects = SubjectList<[Named]>; let Documentation = [AvailabilityDocs]; } @@ -547,7 +666,7 @@ def ExternalSourceSymbol : InheritableAttr { StringArgument<"definedIn", 1>, BoolArgument<"generatedDeclaration", 1>]; let HasCustomParsing = 1; -// let Subjects = SubjectList<[Named]>; + let Subjects = SubjectList<[Named]>; let Documentation = [ExternalSourceSymbolDocs]; } @@ -2242,9 +2361,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> { let Documentation = [DLLImportDocs]; } -def SelectAny : InheritableAttr { - let Spellings = [Declspec<"selectany">]; - let LangOpts = [MicrosoftExt]; +def SelectAny : InheritableAttr, TargetSpecificAttr<TargetWindows> { + let Spellings = [Declspec<"selectany">, GCC<"selectany">]; let Documentation = [Undocumented]; } diff --git a/include/clang/Basic/AttrSubjectMatchRules.h b/include/clang/Basic/AttrSubjectMatchRules.h new file mode 100644 index 000000000000..4c88adf57f17 --- /dev/null +++ b/include/clang/Basic/AttrSubjectMatchRules.h @@ -0,0 +1,32 @@ +//===-- 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<int, SourceRange>; + +} // end namespace attr +} // end namespace clang + +#endif diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt index e4929b5b52b9..3e0fb8728c48 100644 --- a/include/clang/Basic/CMakeLists.txt +++ b/include/clang/Basic/CMakeLists.txt @@ -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 diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 9f5f9888a819..4cde1c81fd4d 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -36,7 +36,9 @@ def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer" def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">; def BitFieldWidth : DiagGroup<"bitfield-width">; -def Coroutine : DiagGroup<"coroutine">; +def CoroutineMissingUnhandledException : + DiagGroup<"coroutine-missing-unhandled-exception">; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>; def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; def LiteralConversion : DiagGroup<"literal-conversion">; @@ -459,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">; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 7f7022b49e3d..cf33d5fba3d7 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -242,6 +242,7 @@ def warn_bad_character_encoding : ExtWarn< "illegal character encoding in character literal">, InGroup<InvalidSourceEncoding>; def err_lexing_string : Error<"failure when lexing a string">; +def err_placeholder_in_source : Error<"editor placeholder in source file">; //===----------------------------------------------------------------------===// @@ -594,8 +595,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; -def err_mmap_umbrella_dir_not_found : Error< - "umbrella directory '%0' not found">; def err_mmap_umbrella_clash : Error< "umbrella for module '%0' already covers this directory">; def err_mmap_module_id : Error< @@ -656,6 +655,9 @@ def note_implicit_top_level_module_import_here : Note< def warn_uncovered_module_header : Warning< "umbrella header for module '%0' does not include header '%1'">, InGroup<IncompleteUmbrella>; +def warn_mmap_umbrella_dir_not_found : Warning< + "umbrella directory '%0' not found">, + InGroup<IncompleteUmbrella>; def err_expected_id_building_module : Error< "expected a module name in '__building_module' expression">; def warn_use_of_private_header_outside_module : Warning< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index aebf8a9f3574..d95e43c10c55 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9b2cfe495ce2..6cb872cc27c5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; @@ -4981,6 +5000,8 @@ def note_protected_by_if_available : Note< "jump enters controlled statement of if available">; def note_protected_by_vla : Note< "jump bypasses initialization of variable length array">; +def note_protected_by_objc_fast_enumeration : Note< + "jump enters Objective-C fast enumeration loop">; def note_protected_by_objc_try : Note< "jump bypasses initialization of @try block">; def note_protected_by_objc_catch : Note< @@ -8854,6 +8875,11 @@ def err_coroutine_invalid_func_context : Error< def err_implied_coroutine_type_not_found : Error< "%0 type was not found; include <experimental/coroutine> before defining " "a coroutine">; +def err_implicit_coroutine_std_nothrow_type_not_found : Error< + "std::nothrow was not found; include <new> before defining a coroutine which " + "uses get_return_object_on_allocation_failure()">; +def err_malformed_std_nothrow : Error< + "std::nothrow must be a valid variable declaration">; def err_malformed_std_coroutine_handle : Error< "std::experimental::coroutine_handle must be a class template">; def err_coroutine_handle_missing_member : Error< @@ -8873,16 +8899,21 @@ def err_coroutine_promise_return_ill_formed : Error< "%0 declares both 'return_value' and 'return_void'">; def note_coroutine_promise_implicit_await_transform_required_here : Note< "call to 'await_transform' implicitly required by 'co_await' here">; -def note_coroutine_promise_call_implicitly_required : Note< +def note_coroutine_promise_suspend_implicitly_required : Note< "call to '%select{initial_suspend|final_suspend}0' implicitly " "required by the %select{initial suspend point|final suspend point}0">; def err_coroutine_promise_unhandled_exception_required : Error< "%0 is required to declare the member 'unhandled_exception()'">; def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning< "%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">, - InGroup<Coroutine>; + InGroup<CoroutineMissingUnhandledException>; def err_coroutine_promise_get_return_object_on_allocation_failure : Error< "%0: 'get_return_object_on_allocation_failure()' must be a static member function">; +def err_coroutine_promise_new_requires_nothrow : Error< + "%0 is required to have a non-throwing noexcept specification when the promise " + "type declares 'get_return_object_on_allocation_failure()'">; +def note_coroutine_promise_call_implicitly_required : Note< + "call to %0 implicitly required by coroutine function here">; } let CategoryName = "Documentation Issue" in { diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index a5fd14104d3c..9b1ba4a98e6f 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -355,6 +355,19 @@ public: RecomputeNeedsHandleIdentifier(); } + /// Return true if this identifier is an editor placeholder. + /// + /// Editor placeholders are produced by the code-completion engine and are + /// represented as characters between '<#' and '#>' in the source code. An + /// example of auto-completed call with a placeholder parameter is shown + /// below: + /// \code + /// function(<#int x#>); + /// \endcode + bool isEditorPlaceholder() const { + return getName().startswith("<#") && getName().endswith("#>"); + } + /// \brief Provide less than operator for lexicographical sorting. bool operator<(const IdentifierInfo &RHS) const { return getName() < RHS.getName(); diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index c8e197299754..6ae34a89fe28 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -266,6 +266,8 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") +LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 48e0c33f0e86..968b203a3827 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -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) diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index 9b6ab3a5ef2b..61902653e210 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -172,6 +172,12 @@ def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">, HelpText<"Enable trigraphs">, Alias<ftrigraphs>; def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">, HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>; +def _SLASH_Zc_twoPhase : CLFlag<"Zc:twoPhase">, + HelpText<"Enable two-phase name lookup in templates">, + Alias<fno_delayed_template_parsing>; +def _SLASH_Zc_twoPhase_ : CLFlag<"Zc:twoPhase-">, + HelpText<"Disable two-phase name lookup in templates">, + Alias<fdelayed_template_parsing>; def _SLASH_Z7 : CLFlag<"Z7">, HelpText<"Enable CodeView debug information in object files">; def _SLASH_Zd : CLFlag<"Zd">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 36b24a02b2fe..1272a36ecc70 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -1487,6 +1487,12 @@ def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>, def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>, Flags<[CC1Option]>; +def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Treat editor placeholders as valid source code">; +def fno_allow_editor_placeholders : Flag<["-"], + "fno-allow-editor-placeholders">, Group<f_Group>; + def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">; def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>, @@ -1646,6 +1652,8 @@ def march_EQ : Joined<["-"], "march=">, Group<m_Group>; def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>; def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>; def mimplicit_it_EQ : Joined<["-"], "mimplicit-it=">, Group<m_Group>; +def mdefault_build_attributes : Joined<["-"], "mdefault-build-attributes">, Group<m_Group>; +def mno_default_build_attributes : Joined<["-"], "mno-default-build-attributes">, Group<m_Group>; def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>; def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>; def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>; @@ -1653,6 +1661,7 @@ def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>; def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>; def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>; def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>; +def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>; def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>; def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>; def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>; diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h index 217d6b1fb1cc..bc34938fb405 100644 --- a/include/clang/Index/IndexSymbol.h +++ b/include/clang/Index/IndexSymbol.h @@ -106,8 +106,9 @@ enum class SymbolRole : uint32_t { RelationAccessorOf = 1 << 15, RelationContainedBy = 1 << 16, RelationIBTypeOf = 1 << 17, + RelationSpecializationOf = 1 << 18, }; -static const unsigned SymbolRoleBitNum = 18; +static const unsigned SymbolRoleBitNum = 19; typedef unsigned SymbolRoleSet; /// Represents a relation to another symbol for a symbol occurrence. diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 830c25a2e4d2..6ac6316d1248 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -638,6 +638,8 @@ private: bool IsStartOfConflictMarker(const char *CurPtr); bool HandleEndOfConflictMarker(const char *CurPtr); + bool lexEditorPlaceholder(Token &Result, const char *CurPtr); + bool isCodeCompletionPoint(const char *CurPtr) const; void cutOffLexing() { BufferPtr = BufferEnd; } diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 4393e205ffaf..02a1fef70f2b 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -84,6 +84,7 @@ public: StringifiedInMacro = 0x100, // This string or character literal is formed by // macro stringizing or charizing operator. CommaAfterElided = 0x200, // The comma following this token was elided (MS). + IsEditorPlaceholder = 0x400, // This identifier is a placeholder. }; tok::TokenKind getKind() const { return Kind; } @@ -298,6 +299,13 @@ public: /// Returns true if the comma after this token was elided. bool commaAfterElided() const { return getFlag(CommaAfterElided); } + + /// Returns true if this token is an editor placeholder. + /// + /// Editor placeholders are produced by the code-completion engine and are + /// represented as characters between '<#' and '#>' in the source code. The + /// lexer uses identifier tokens to represent placeholders. + bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } }; /// \brief Information about the conditional stack (\#if directives) diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt index ec75f7b96b14..2cc7e54b3b01 100644 --- a/include/clang/Parse/CMakeLists.txt +++ b/include/clang/Parse/CMakeLists.txt @@ -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) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 5f4e5fb4b215..8d0935dec1b6 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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. diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 7c1678086c2f..f3b042c9ce79 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -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; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5a3cdfb77c9c..bd68842c9f73 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7b337b061a03..4626052a8acb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -9414,10 +9414,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { if (!NodeOrVector.template is<ASTContext::ParentVector *>()) { auto *Vector = new ASTContext::ParentVector( 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); - if (auto *Node = - NodeOrVector - .template dyn_cast<ast_type_traits::DynTypedNode *>()) - delete Node; + delete NodeOrVector + .template dyn_cast<ast_type_traits::DynTypedNode *>(); NodeOrVector = Vector; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2b22e5bb50a5..094e8dcff088 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3003,9 +3003,7 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const { const Attr *FunctionDecl::getUnusedResultAttr() const { QualType RetType = getReturnType(); if (RetType->isRecordType()) { - const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl(); - const auto *MD = dyn_cast<CXXMethodDecl>(this); - if (Ret && !(MD && MD->getCorrespondingMethodInClass(Ret, true))) { + if (const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl()) { if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>()) return R; } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 5d841a197f26..bc8a34c93653 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -478,6 +478,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->isFunctionTemplateSpecialization()) Out << "template<> "; + else if (!D->getDescribedFunctionTemplate()) { + for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists(); + I < NumTemplateParams; ++I) + printTemplateParameters(D->getTemplateParameterList(I)); + } CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D); CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D); @@ -1055,6 +1060,12 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { prettyPrintPragmas(D->getTemplatedDecl()); + // Print any leading template parameter lists. + if (const FunctionDecl *FD = D->getTemplatedDecl()) { + for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists(); + I < NumTemplateParams; ++I) + printTemplateParameters(FD->getTemplateParameterList(I)); + } VisitRedeclarableTemplateDecl(D); // Never print "instantiations" for deduction guides (they don't really diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp index 2d4d0185ff2a..8849cfc3c80b 100644 --- a/lib/AST/ExternalASTMerger.cpp +++ b/lib/AST/ExternalASTMerger.cpp @@ -89,25 +89,21 @@ bool IsForwardDeclaration(Decl *D) { } } +template <typename CallbackType> void ForEachMatchingDC( const DeclContext *DC, llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers, - std::function<void(const ExternalASTMerger::ImporterPair &IP, - Source<const DeclContext *> SourceDC)> - Callback) { + CallbackType Callback) { for (const ExternalASTMerger::ImporterPair &IP : Importers) { - Source<TranslationUnitDecl *> SourceTU( - IP.Forward->getFromContext().getTranslationUnitDecl()); - Source<const DeclContext *> SourceDC = - LookupSameContext(SourceTU, DC, *IP.Reverse); - if (SourceDC.get()) { + Source<TranslationUnitDecl *> SourceTU = + IP.Forward->getFromContext().getTranslationUnitDecl(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) Callback(IP, SourceDC); - } } } bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { - return std::any_of(Decls.begin(), Decls.end(), [&C](const Candidate &D) { + return llvm::any_of(Decls, [&](const Candidate &D) { return C.first.get()->getKind() == D.first.get()->getKind(); }); } @@ -139,15 +135,15 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, } }; - ForEachMatchingDC(DC, Importers, [Name, &FilterFoundDecl]( - const ImporterPair &IP, - Source<const DeclContext *> SourceDC) { - DeclarationName FromName = IP.Reverse->Import(Name); - DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); - for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); - } - }); + ForEachMatchingDC( + DC, Importers, + [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { + DeclarationName FromName = IP.Reverse->Import(Name); + DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); + } + }); llvm::ArrayRef<Candidate> DeclsToReport = CompleteDecls.empty() ? ForwardDecls : CompleteDecls; @@ -170,15 +166,14 @@ void ExternalASTMerger::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Result) { ForEachMatchingDC( - DC, Importers, [DC, IsKindWeWant](const ImporterPair &IP, - Source<const DeclContext *> SourceDC) { + DC, Importers, + [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { for (const Decl *SourceDecl : SourceDC.get()->decls()) { if (IsKindWeWant(SourceDecl->getKind())) { Decl *ImportedDecl = IP.Forward->Import(const_cast<Decl *>(SourceDecl)); assert(ImportedDecl->getDeclContext() == DC); (void)ImportedDecl; - (void)DC; } } }); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 29fcdd7be924..7db0b4d8e4ff 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1455,10 +1455,12 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { Qualifiers MethodQuals = - Qualifiers::fromCVRMask(Method->getTypeQualifiers()); + Qualifiers::fromCVRUMask(Method->getTypeQualifiers()); // We do not consider restrict a distinguishing attribute for overloading // purposes so we must not mangle it. MethodQuals.removeRestrict(); + // __unaligned is not currently mangled in any way, so remove it. + MethodQuals.removeUnaligned(); mangleQualifiers(MethodQuals); mangleRefQualifier(Method->getRefQualifier()); } diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp index a812884cd927..cccb2f075b65 100644 --- a/lib/AST/StmtOpenMP.cpp +++ b/lib/AST/StmtOpenMP.cpp @@ -147,10 +147,6 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -201,10 +197,6 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -368,10 +360,6 @@ OMPParallelForDirective *OMPParallelForDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -421,10 +409,6 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -759,10 +743,6 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -904,10 +884,6 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -957,10 +933,6 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1009,10 +981,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1095,6 +1063,13 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1153,6 +1128,13 @@ OMPDistributeParallelForSimdDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1200,10 +1182,6 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1256,10 +1234,6 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1352,10 +1326,6 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1407,10 +1377,6 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1474,6 +1440,13 @@ OMPTeamsDistributeParallelForSimdDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1534,6 +1507,13 @@ OMPTeamsDistributeParallelForDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1606,10 +1586,6 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); @@ -1676,6 +1652,13 @@ OMPTargetTeamsDistributeParallelForDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1739,6 +1722,13 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create( Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); Dir->setPreInits(Exprs.PreInits); + Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); + Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); + Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB); + Dir->setCombinedInit(Exprs.DistCombinedFields.Init); + Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); + Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); + Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); return Dir; } @@ -1789,10 +1779,6 @@ OMPTargetTeamsDistributeSimdDirective::Create( Dir->setNextLowerBound(Exprs.NLB); Dir->setNextUpperBound(Exprs.NUB); Dir->setNumIterations(Exprs.NumIterations); - Dir->setPrevLowerBoundVariable(Exprs.PrevLB); - Dir->setPrevUpperBoundVariable(Exprs.PrevUB); - Dir->setDistInc(Exprs.DistInc); - Dir->setPrevEnsureUpperBound(Exprs.PrevEUB); Dir->setCounters(Exprs.Counters); Dir->setPrivateCounters(Exprs.PrivateCounters); Dir->setInits(Exprs.Inits); diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 9fa693038194..6f935620888f 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -296,6 +296,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isCatchAll); REGISTER_MATCHER(isClass); REGISTER_MATCHER(isConst); + REGISTER_MATCHER(isConstexpr); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isCopyAssignmentOperator); REGISTER_MATCHER(isCopyConstructor); diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp index c215366fc398..b7570d03c85a 100644 --- a/lib/Basic/Attributes.cpp +++ b/lib/Basic/Attributes.cpp @@ -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"); +} diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 5a8bb61eaadf..76a0e18c2d73 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -854,14 +854,10 @@ bool clang::isOpenMPTaskingDirective(OpenMPDirectiveKind Kind) { bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) { return Kind == OMPD_distribute_parallel_for || Kind == OMPD_distribute_parallel_for_simd || - Kind == OMPD_distribute_simd || Kind == OMPD_teams_distribute || - Kind == OMPD_teams_distribute_simd || Kind == OMPD_teams_distribute_parallel_for_simd || Kind == OMPD_teams_distribute_parallel_for || - Kind == OMPD_target_teams_distribute || Kind == OMPD_target_teams_distribute_parallel_for || - Kind == OMPD_target_teams_distribute_parallel_for_simd || - Kind == OMPD_target_teams_distribute_simd; + Kind == OMPD_target_teams_distribute_parallel_for_simd; } void clang::getOpenMPCaptureRegions( diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index a457f6deee75..d7f1793e377c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -5467,9 +5467,11 @@ public: Builder.defineMacro("__arm__"); // For bare-metal none-eabi. if (getTriple().getOS() == llvm::Triple::UnknownOS && - getTriple().getEnvironment() == llvm::Triple::EABI) + (getTriple().getEnvironment() == llvm::Triple::EABI || + getTriple().getEnvironment() == llvm::Triple::EABIHF)) Builder.defineMacro("__ELF__"); + // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); @@ -6118,6 +6120,11 @@ public: MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__aarch64__"); + // For bare-metal none-eabi. + if (getTriple().getOS() == llvm::Triple::UnknownOS && + (getTriple().getEnvironment() == llvm::Triple::EABI || + getTriple().getEnvironment() == llvm::Triple::EABIHF)) + Builder.defineMacro("__ELF__"); // Target properties. Builder.defineMacro("_LP64"); diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 855d6795b9d6..20059d922f90 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -83,9 +83,6 @@ class EmitAssemblyHelper { return TargetIRAnalysis(); } - /// Set LLVM command line options passed through -backend-option. - void setCommandLineOpts(); - void CreatePasses(legacy::PassManager &MPM, legacy::FunctionPassManager &FPM); /// Generates the TargetMachine. @@ -372,7 +369,9 @@ static void initTargetOptions(llvm::TargetOptions &Options, // Set FP fusion mode. switch (LangOpts.getDefaultFPContractMode()) { case LangOptions::FPC_Off: - Options.AllowFPOpFusion = llvm::FPOpFusion::Strict; + // Preserve any contraction performed by the front-end. (Strict performs + // splitting of the muladd instrinsic in the backend.) + Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break; case LangOptions::FPC_On: Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; @@ -604,7 +603,7 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM, PMBuilder.populateModulePassManager(MPM); } -void EmitAssemblyHelper::setCommandLineOpts() { +static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) { SmallVector<const char *, 16> BackendArgs; BackendArgs.push_back("clang"); // Fake program name. if (!CodeGenOpts.DebugPass.empty()) { @@ -677,7 +676,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) { TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr); - setCommandLineOpts(); + setCommandLineOpts(CodeGenOpts); bool UsesCodeGen = (Action != Backend_EmitNothing && Action != Backend_EmitBC && @@ -806,7 +805,7 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) { void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) { TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr); - setCommandLineOpts(); + setCommandLineOpts(CodeGenOpts); // The new pass manager always makes a target machine available to passes // during construction. @@ -944,6 +943,8 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); + setCommandLineOpts(CGOpts); + // We can simply import the values mentioned in the combined index, since // we should only invoke this using the individual indexes written out // via a WriteIndexesThinBackend. diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 8af32055fc4c..26235257b19d 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -1586,9 +1586,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { case ABIArgInfo::Indirect: { assert(NumIRArgs == 1); - // indirect arguments are always on the stack, which is addr space #0. + // indirect arguments are always on the stack, which is alloca addr space. llvm::Type *LTy = ConvertTypeForMem(it->type); - ArgTypes[FirstIRArg] = LTy->getPointerTo(); + ArgTypes[FirstIRArg] = LTy->getPointerTo( + CGM.getDataLayout().getAllocaAddrSpace()); break; } @@ -1761,7 +1762,7 @@ void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) { void CodeGenModule::ConstructAttributeList( StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo, - AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) { + llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) { llvm::AttrBuilder FuncAttrs; llvm::AttrBuilder RetAttrs; @@ -1930,13 +1931,8 @@ void CodeGenModule::ConstructAttributeList( RetAttrs.addAttribute(llvm::Attribute::NonNull); } - // Attach return attributes. - if (RetAttrs.hasAttributes()) { - PAL.push_back(llvm::AttributeList::get( - getLLVMContext(), llvm::AttributeList::ReturnIndex, RetAttrs)); - } - bool hasUsedSRet = false; + SmallVector<llvm::AttributeSet, 4> ArgAttrs(IRFunctionArgs.totalIRArgs()); // Attach attributes to sret. if (IRFunctionArgs.hasSRetArg()) { @@ -1945,16 +1941,16 @@ void CodeGenModule::ConstructAttributeList( hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); - PAL.push_back(llvm::AttributeList::get( - getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs)); + ArgAttrs[IRFunctionArgs.getSRetArgNo()] = + llvm::AttributeSet::get(getLLVMContext(), SRETAttrs); } // Attach attributes to inalloca argument. if (IRFunctionArgs.hasInallocaArg()) { llvm::AttrBuilder Attrs; Attrs.addAttribute(llvm::Attribute::InAlloca); - PAL.push_back(llvm::AttributeList::get( - getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs)); + ArgAttrs[IRFunctionArgs.getInallocaArgNo()] = + llvm::AttributeSet::get(getLLVMContext(), Attrs); } unsigned ArgNo = 0; @@ -1967,10 +1963,12 @@ void CodeGenModule::ConstructAttributeList( // Add attribute for padding argument, if necessary. if (IRFunctionArgs.hasPaddingArg(ArgNo)) { - if (AI.getPaddingInReg()) - PAL.push_back(llvm::AttributeList::get( - getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1, - llvm::Attribute::InReg)); + if (AI.getPaddingInReg()) { + ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] = + llvm::AttributeSet::get( + getLLVMContext(), + llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg)); + } } // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we @@ -2085,15 +2083,15 @@ void CodeGenModule::ConstructAttributeList( unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); for (unsigned i = 0; i < NumIRArgs; i++) - PAL.push_back(llvm::AttributeList::get(getLLVMContext(), - FirstIRArg + i + 1, Attrs)); + ArgAttrs[FirstIRArg + i] = + llvm::AttributeSet::get(getLLVMContext(), Attrs); } } assert(ArgNo == FI.arg_size()); - if (FuncAttrs.hasAttributes()) - PAL.push_back(llvm::AttributeList::get( - getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs)); + AttrList = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs), + llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs); } /// An argument came in as a promoted argument; demote it back to its @@ -2204,8 +2202,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (IRFunctionArgs.hasSRetArg()) { auto AI = cast<llvm::Argument>(FnArgs[IRFunctionArgs.getSRetArgNo()]); AI->setName("agg.result"); - AI->addAttr(llvm::AttributeList::get(getLLVMContext(), AI->getArgNo() + 1, - llvm::Attribute::NoAlias)); + AI->addAttr(llvm::Attribute::NoAlias); } // Track if we received the parameter as a pointer (indirect, byval, or @@ -2296,9 +2293,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) { if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(), PVD->getFunctionScopeIndex())) - AI->addAttr(llvm::AttributeList::get(getLLVMContext(), - AI->getArgNo() + 1, - llvm::Attribute::NonNull)); + AI->addAttr(llvm::Attribute::NonNull); QualType OTy = PVD->getOriginalType(); if (const auto *ArrTy = @@ -2315,12 +2310,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::AttrBuilder Attrs; Attrs.addDereferenceableAttr( getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize); - AI->addAttr(llvm::AttributeList::get( - getLLVMContext(), AI->getArgNo() + 1, Attrs)); + AI->addAttrs(Attrs); } else if (getContext().getTargetAddressSpace(ETy) == 0) { - AI->addAttr(llvm::AttributeList::get(getLLVMContext(), - AI->getArgNo() + 1, - llvm::Attribute::NonNull)); + AI->addAttr(llvm::Attribute::NonNull); } } } else if (const auto *ArrTy = @@ -2330,34 +2322,26 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // we know that it must be nonnull. if (ArrTy->getSizeModifier() == VariableArrayType::Static && !getContext().getTargetAddressSpace(ArrTy->getElementType())) - AI->addAttr(llvm::AttributeList::get(getLLVMContext(), - AI->getArgNo() + 1, - llvm::Attribute::NonNull)); + AI->addAttr(llvm::Attribute::NonNull); } const auto *AVAttr = PVD->getAttr<AlignValueAttr>(); if (!AVAttr) if (const auto *TOTy = dyn_cast<TypedefType>(OTy)) AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>(); - if (AVAttr) { + if (AVAttr) { llvm::Value *AlignmentValue = EmitScalarExpr(AVAttr->getAlignment()); llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(AlignmentValue); - unsigned Alignment = - std::min((unsigned) AlignmentCI->getZExtValue(), - +llvm::Value::MaximumAlignment); - - llvm::AttrBuilder Attrs; - Attrs.addAlignmentAttr(Alignment); - AI->addAttr(llvm::AttributeList::get(getLLVMContext(), - AI->getArgNo() + 1, Attrs)); + unsigned Alignment = std::min((unsigned)AlignmentCI->getZExtValue(), + +llvm::Value::MaximumAlignment); + AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment)); } } if (Arg->getType().isRestrictQualified()) - AI->addAttr(llvm::AttributeList::get( - getLLVMContext(), AI->getArgNo() + 1, llvm::Attribute::NoAlias)); + AI->addAttr(llvm::Attribute::NoAlias); // LLVM expects swifterror parameters to be used in very restricted // ways. Copy the value into a less-restricted temporary. @@ -4113,13 +4097,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // Compute the calling convention and attributes. unsigned CallingConv; - CodeGen::AttributeListType AttributeList; + llvm::AttributeList Attrs; CGM.ConstructAttributeList(CalleePtr->getName(), CallInfo, - Callee.getAbstractInfo(), - AttributeList, CallingConv, + Callee.getAbstractInfo(), Attrs, CallingConv, /*AttrOnCallSite=*/true); - llvm::AttributeList Attrs = - llvm::AttributeList::get(getLLVMContext(), AttributeList); // Apply some call-site-specific attributes. // TODO: work this into building the attribute set. diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 97221e20c195..7e10407fc31c 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -39,7 +39,6 @@ namespace clang { class VarDecl; namespace CodeGen { -typedef SmallVector<llvm::AttributeList, 8> AttributeListType; /// Abstract information about a function or function prototype. class CGCalleeInfo { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 818b51543d30..2f6a2b95fb61 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -3466,17 +3466,17 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, // functions there won't be an implicit param at arg1 and // otherwise it is 'self' or 'this'. if (isa<ImplicitParamDecl>(VD) && ArgNo && *ArgNo == 1) - Flags |= llvm::DINode::FlagObjectPointer; - if (auto *Arg = dyn_cast<llvm::Argument>(Storage)) - if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() && - !VD->getType()->isPointerType()) - Expr.push_back(llvm::dwarf::DW_OP_deref); + Flags |= llvm::DINode::FlagObjectPointer; + // Note: Older versions of clang used to emit byval references with an extra + // DW_OP_deref, because they referenced the IR arg directly instead of + // referencing an alloca. Newer versions of LLVM don't treat allocas + // differently from other function arguments when used in a dbg.declare. auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back()); - StringRef Name = VD->getName(); if (!Name.empty()) { if (VD->hasAttr<BlocksAttr>()) { + // Here, we need an offset *into* the alloca. CharUnits offset = CharUnits::fromQuantity(32); Expr.push_back(llvm::dwarf::DW_OP_plus); // offset of __forwarding field @@ -3488,22 +3488,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); Expr.push_back(offset.getQuantity()); - - // Create the descriptor for the variable. - auto *D = ArgNo - ? DBuilder.createParameterVariable(Scope, VD->getName(), - *ArgNo, Unit, Line, Ty) - : DBuilder.createAutoVariable(Scope, VD->getName(), Unit, - Line, Ty, Align); - - // Insert an llvm.dbg.declare into the current block. - DBuilder.insertDeclare( - Storage, D, DBuilder.createExpression(Expr), - llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), - Builder.GetInsertBlock()); - return; - } else if (isa<VariableArrayType>(VD->getType())) - Expr.push_back(llvm::dwarf::DW_OP_deref); + } } else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) { // If VD is an anonymous union then Storage represents value for // all union fields. @@ -3606,8 +3591,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( ->getElementOffset(blockInfo.getCapture(VD).getIndex())); SmallVector<int64_t, 9> addr; - if (isa<llvm::AllocaInst>(Storage)) - addr.push_back(llvm::dwarf::DW_OP_deref); + addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus); addr.push_back(offset.getQuantity()); if (isByRef) { @@ -3633,12 +3617,11 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( // Insert an llvm.dbg.declare into the current block. auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt); + auto *Expr = DBuilder.createExpression(addr); if (InsertPoint) - DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL, - InsertPoint); + DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint); else - DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL, - Builder.GetInsertBlock()); + DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock()); } void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 0f959043a22e..10a0b46d9028 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -924,7 +924,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size, return nullptr; llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size); - Addr = Builder.CreateBitCast(Addr, Int8PtrTy); + Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr}); C->setDoesNotThrow(); @@ -932,7 +932,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size, } void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { - Addr = Builder.CreateBitCast(Addr, Int8PtrTy); + Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr}); C->setDoesNotThrow(); @@ -1728,7 +1728,7 @@ llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() { if (LifetimeStartFn) return LifetimeStartFn; LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_start, Int8PtrTy); + llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy); return LifetimeStartFn; } @@ -1737,7 +1737,7 @@ llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() { if (LifetimeEndFn) return LifetimeEndFn; LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_end, Int8PtrTy); + llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy); return LifetimeEndFn; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 265ef27a46b0..719147a58e08 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -533,6 +533,15 @@ bool CodeGenFunction::sanitizePerformTypeCheck() const { SanOpts.has(SanitizerKind::Vptr); } +/// Check if a runtime null check for \p Ptr can be omitted. +static bool canOmitPointerNullCheck(llvm::Value *Ptr) { + // Note: do not perform any constant-folding in this function. That is best + // left to the IR builder. + + // Pointers to alloca'd memory are non-null. + return isa<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases()); +} + void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *Ptr, QualType Ty, CharUnits Alignment, @@ -554,19 +563,28 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast || TCK == TCK_UpcastToVirtualBase; if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) && - !SkippedChecks.has(SanitizerKind::Null)) { + !SkippedChecks.has(SanitizerKind::Null) && + !canOmitPointerNullCheck(Ptr)) { // The glvalue must not be an empty glvalue. llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr); - if (AllowNullPointers) { - // When performing pointer casts, it's OK if the value is null. - // Skip the remaining checks in that case. - Done = createBasicBlock("null"); - llvm::BasicBlock *Rest = createBasicBlock("not.null"); - Builder.CreateCondBr(IsNonNull, Rest, Done); - EmitBlock(Rest); - } else { - Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null)); + // The IR builder can constant-fold the null check if the pointer points to + // a constant. + bool PtrIsNonNull = + IsNonNull == llvm::ConstantInt::getTrue(getLLVMContext()); + + // Skip the null check if the pointer is known to be non-null. + if (!PtrIsNonNull) { + if (AllowNullPointers) { + // When performing pointer casts, it's OK if the value is null. + // Skip the remaining checks in that case. + Done = createBasicBlock("null"); + llvm::BasicBlock *Rest = createBasicBlock("not.null"); + Builder.CreateCondBr(IsNonNull, Rest, Done); + EmitBlock(Rest); + } else { + Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null)); + } } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 3db15c646f43..53c184130709 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -201,7 +201,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; if (CGM.getDataLayout().isBigEndian()) { - Tmp = Tmp.lshr(NewFieldWidth); + Tmp.lshrInPlace(NewFieldWidth); Tmp = Tmp.trunc(BitsInPreviousByte); // We want the remaining high bits. @@ -210,7 +210,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, Tmp = Tmp.trunc(BitsInPreviousByte); // We want the remaining low bits. - FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.lshrInPlace(BitsInPreviousByte); FieldValue = FieldValue.trunc(NewFieldWidth); } } @@ -273,7 +273,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, // We want the low bits. Tmp = FieldValue.trunc(CharWidth); - FieldValue = FieldValue.lshr(CharWidth); + FieldValue.lshrInPlace(CharWidth); } Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 3a09a15dbc15..76e7df861f74 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -126,10 +126,12 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, QualType IdTy(CGM.getContext().getObjCIdType()); llvm::Constant *Constant = CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName); - Address Addr(Constant, Context.getTypeAlignInChars(IdTy)); - LValue LV = MakeAddrLValue(Addr, IdTy); - return Builder.CreateBitCast(EmitLoadOfScalar(LV, E->getLocStart()), - ConvertType(E->getType())); + LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy); + llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getLocStart()); + cast<llvm::LoadInst>(Ptr)->setMetadata( + CGM.getModule().getMDKindID("invariant.load"), + llvm::MDNode::get(getLLVMContext(), None)); + return Builder.CreateBitCast(Ptr, ConvertType(E->getType())); } // Compute the type of the array we're initializing. @@ -1848,12 +1850,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, F->addFnAttr(llvm::Attribute::NonLazyBind); } - if (IsForwarding(Name)) { - llvm::AttrBuilder B; - B.addAttribute(llvm::Attribute::Returned); - - F->arg_begin()->addAttr(llvm::AttributeList::get(F->getContext(), 1, B)); - } + if (IsForwarding(Name)) + F->arg_begin()->addAttr(llvm::Attribute::Returned); } return RTF; diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 0ebfd99363c1..683f366ebe45 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1166,7 +1166,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { if (Rem) Rem--; SwitchInsn->addCase(Builder.getInt(LHS), CaseDest); - LHS++; + ++LHS; } return; } diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 7b0c8bf7d6e9..1869c0e809df 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -379,12 +379,9 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD, // Apply the standard set of call attributes. unsigned CallingConv; - CodeGen::AttributeListType AttributeList; - CGM.ConstructAttributeList(CalleePtr->getName(), - *CurFnInfo, MD, AttributeList, + llvm::AttributeList Attrs; + CGM.ConstructAttributeList(CalleePtr->getName(), *CurFnInfo, MD, Attrs, CallingConv, /*AttrOnCallSite=*/true); - llvm::AttributeList Attrs = - llvm::AttributeList::get(getLLVMContext(), AttributeList); Call->setAttributes(Attrs); Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d48bff9c30a3..19203973ff1b 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -111,6 +111,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, C.getTargetInfo().getMaxPointerWidth()); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); + AllocaInt8PtrTy = Int8Ty->getPointerTo( + M.getDataLayout().getAllocaAddrSpace()); RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC(); BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC(); @@ -839,10 +841,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, const CGFunctionInfo &Info, llvm::Function *F) { unsigned CallingConv; - AttributeListType AttributeList; - ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv, - false); - F->setAttributes(llvm::AttributeList::get(getLLVMContext(), AttributeList)); + llvm::AttributeList PAL; + ConstructAttributeList(F->getName(), Info, D, PAL, CallingConv, false); + F->setAttributes(PAL); F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); } @@ -3793,6 +3794,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { AddDeferredUnusedCoverageMapping(D); break; + case Decl::CXXDeductionGuide: + // Function-like, but does not result in code emission. + break; + case Decl::Var: case Decl::Decomposition: // Skip variable templates diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index d0b2dd717c8c..c4985ba41db1 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1020,11 +1020,12 @@ public: /// \param CalleeInfo - The callee information these attributes are being /// constructed for. If valid, the attributes applied to this decl may /// contribute to the function attributes and calling convention. - /// \param PAL [out] - On return, the attribute list to use. + /// \param Attrs [out] - On return, the attribute list to use. /// \param CallingConv [out] - On return, the LLVM calling convention to use. void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info, - CGCalleeInfo CalleeInfo, AttributeListType &PAL, - unsigned &CallingConv, bool AttrOnCallSite); + CGCalleeInfo CalleeInfo, + llvm::AttributeList &Attrs, unsigned &CallingConv, + bool AttrOnCallSite); /// Adds attributes to F according to our CodeGenOptions and LangOptions, as /// though we had emitted it ourselves. We remove any attributes on F that diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h index 47e26bcaa1b6..8ce9860cc638 100644 --- a/lib/CodeGen/CodeGenTypeCache.h +++ b/lib/CodeGen/CodeGenTypeCache.h @@ -60,6 +60,12 @@ struct CodeGenTypeCache { llvm::PointerType *Int8PtrPtrTy; }; + /// void* in alloca address space + union { + llvm::PointerType *AllocaVoidPtrTy; + llvm::PointerType *AllocaInt8PtrTy; + }; + /// The size and alignment of the builtin C type 'int'. This comes /// up enough in various ABI lowering tasks to be worth pre-computing. union { diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 89090c8b6a1b..fc642850d60a 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -197,7 +197,7 @@ namespace { // Provide some coverage mapping even for methods that aren't emitted. // Don't do this for templated classes though, as they may not be // instantiable. - if (!MD->getParent()->getDescribedClassTemplate()) + if (!MD->getParent()->isDependentContext()) Builder->AddDeferredUnusedCoverageMapping(MD); } diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index b05596a99f6e..8e61aadbf326 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -469,34 +469,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, int LegacySanitizeCoverage; if (Arg->getNumValues() == 1 && !StringRef(Arg->getValue(0)) - .getAsInteger(0, LegacySanitizeCoverage) && - LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { - switch (LegacySanitizeCoverage) { - case 0: - CoverageFeatures = 0; - Arg->claim(); - break; - case 1: - D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) - << "-fsanitize-coverage=func"; - CoverageFeatures = CoverageFunc; - break; - case 2: - D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) - << "-fsanitize-coverage=bb"; - CoverageFeatures = CoverageBB; - break; - case 3: - D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) - << "-fsanitize-coverage=edge"; - CoverageFeatures = CoverageEdge; - break; - case 4: + .getAsInteger(0, LegacySanitizeCoverage)) { + CoverageFeatures = 0; + Arg->claim(); + if (LegacySanitizeCoverage != 0) { D.Diag(diag::warn_drv_deprecated_arg) - << Arg->getAsString(Args) - << "-fsanitize-coverage=edge,indirect-calls"; - CoverageFeatures = CoverageEdge | CoverageIndirCall; - break; + << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; } continue; } @@ -530,16 +508,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Basic block tracing and 8-bit counters require some type of coverage // enabled. int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge; - if ((CoverageFeatures & CoverageTraceBB) && - !(CoverageFeatures & CoverageTypes)) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) + if (CoverageFeatures & CoverageTraceBB) + D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=trace-bb" - << "-fsanitize-coverage=(func|bb|edge)"; - if ((CoverageFeatures & Coverage8bitCounters) && - !(CoverageFeatures & CoverageTypes)) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fsanitize-coverage=trace-pc-guard"; + if (CoverageFeatures & Coverage8bitCounters) + D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=8bit-counters" - << "-fsanitize-coverage=(func|bb|edge)"; + << "-fsanitize-coverage=trace-pc-guard"; // trace-pc w/o func/bb/edge implies edge. if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) && !(CoverageFeatures & CoverageTypes)) diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index f8eeeb4eef69..49708e7d7242 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -649,8 +649,24 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, CmdArgs.push_back("-x"); if (Args.hasArg(options::OPT_rewrite_objc)) CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); - else - CmdArgs.push_back(types::getTypeName(Input.getType())); + else { + // Map the driver type to the frontend type. This is mostly an identity + // mapping, except that the distinction between module interface units + // and other source files does not exist at the frontend layer. + const char *ClangType; + switch (Input.getType()) { + case types::TY_CXXModule: + ClangType = "c++"; + break; + case types::TY_PP_CXXModule: + ClangType = "c++-cpp-output"; + break; + default: + ClangType = types::getTypeName(Input.getType()); + break; + } + CmdArgs.push_back(ClangType); + } } static void appendUserToPath(SmallVectorImpl<char> &Result) { @@ -2290,6 +2306,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, true)) CmdArgs.push_back("-fno-strict-return"); + if (Args.hasFlag(options::OPT_fallow_editor_placeholders, + options::OPT_fno_allow_editor_placeholders, false)) + CmdArgs.push_back("-fallow-editor-placeholders"); if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, options::OPT_fno_strict_vtable_pointers, false)) @@ -4996,6 +5015,19 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::x86_64: AddX86TargetArgs(Args, CmdArgs); break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + // This isn't in AddARMTargetArgs because we want to do this for assembly + // only, not C/C++. + if (Args.hasFlag(options::OPT_mdefault_build_attributes, + options::OPT_mno_default_build_attributes, true)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-arm-add-build-attributes"); + } + break; } // Consume all the warning flags. Usually this would be handled more diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index e5f4a3b8d605..93b66eb6954a 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -261,6 +261,12 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); return arm::getARMTargetCPU(MCPU, MArch, T); } + + case llvm::Triple::avr: + if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ)) + return A->getValue(); + return ""; + case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -426,11 +432,12 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, } } -void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, - const ArgList &Args) { +bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, + const ArgList &Args, bool IsOffloadingHost, + bool GompNeedsRT) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) - return; + return false; switch (TC.getDriver().getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: @@ -438,16 +445,24 @@ void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, break; case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); + + if (GompNeedsRT) + CmdArgs.push_back("-lrt"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; case Driver::OMPRT_Unknown: // Already diagnosed. - break; + return false; } + if (IsOffloadingHost) + CmdArgs.push_back("-lomptarget"); + addArchSpecificRPath(TC, Args, CmdArgs); + + return true; } static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h index f5747aa85f22..fdeb6669b0a8 100644 --- a/lib/Driver/ToolChains/CommonArgs.h +++ b/lib/Driver/ToolChains/CommonArgs.h @@ -59,8 +59,10 @@ void AddAssemblerKPIC(const ToolChain &ToolChain, void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -void addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, - const llvm::opt::ArgList &Args); +/// Returns true, if an OpenMP runtime has been added. +bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, + const llvm::opt::ArgList &Args, + bool IsOffloadingHost = false, bool GompNeedsRT = false); llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index 549e24cbd2b3..313bf38c2860 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -586,37 +586,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); - if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false)) { + // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that + // require librt. Most modern Linux platforms do, but some may not. + if (addOpenMPRuntime(CmdArgs, ToolChain, Args, + JA.isHostOffloading(Action::OFK_OpenMP), + /* GompNeedsRT= */ true)) // OpenMP runtimes implies pthreads when using the GNU toolchain. // FIXME: Does this really make sense for all GNU toolchains? WantPthread = true; - // Also link the particular OpenMP runtimes. - switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { - case Driver::OMPRT_OMP: - CmdArgs.push_back("-lomp"); - break; - case Driver::OMPRT_GOMP: - CmdArgs.push_back("-lgomp"); - - // FIXME: Exclude this for platforms with libgomp that don't require - // librt. Most modern Linux platforms require it, but some may not. - CmdArgs.push_back("-lrt"); - break; - case Driver::OMPRT_IOMP5: - CmdArgs.push_back("-liomp5"); - break; - case Driver::OMPRT_Unknown: - // Already diagnosed. - break; - } - if (JA.isHostOffloading(Action::OFK_OpenMP)) - CmdArgs.push_back("-lomptarget"); - - addArchSpecificRPath(ToolChain, Args, CmdArgs); - } - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); if (WantPthread && !isAndroid) @@ -770,6 +748,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); break; } + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: { + Args.AddLastArg(CmdArgs, options::OPT_march_EQ); + Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + break; + } case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: diff --git a/lib/Driver/ToolChains/MinGW.cpp b/lib/Driver/ToolChains/MinGW.cpp index ca5bf06f7e7d..7550bab486f1 100644 --- a/lib/Driver/ToolChains/MinGW.cpp +++ b/lib/Driver/ToolChains/MinGW.cpp @@ -285,28 +285,30 @@ void toolchains::MinGW::findGccLibDir() { } } +llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { + llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; + Gccs.emplace_back(getTriple().getArchName()); + Gccs[0] += "-w64-mingw32-gcc"; + Gccs.emplace_back("mingw32-gcc"); + // Please do not add "gcc" here + for (StringRef CandidateGcc : Gccs) + if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc)) + return GPPName; + return make_error_code(std::errc::no_such_file_or_directory); +} + toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); -// In Windows there aren't any standard install locations, we search -// for gcc on the PATH. In Linux the base is always /usr. -#ifdef LLVM_ON_WIN32 if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; - else if (llvm::ErrorOr<std::string> GPPName = - llvm::sys::findProgramByName("gcc")) + else if (llvm::ErrorOr<std::string> GPPName = findGcc()) Base = llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get())); else Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); -#else - if (getDriver().SysRoot.size()) - Base = getDriver().SysRoot; - else - Base = "/usr"; -#endif Base += llvm::sys::path::get_separator(); findGccLibDir(); diff --git a/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h index 9d2468ffa234..cf1628a4ccdd 100644 --- a/lib/Driver/ToolChains/MinGW.h +++ b/lib/Driver/ToolChains/MinGW.h @@ -93,6 +93,7 @@ private: mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; void findGccLibDir(); + llvm::ErrorOr<std::string> findGcc(); }; } // end namespace toolchains diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp index 4ee43d6937e0..1acc0c306512 100644 --- a/lib/Format/FormatTokenLexer.cpp +++ b/lib/Format/FormatTokenLexer.cpp @@ -467,6 +467,9 @@ FormatToken *FormatTokenLexer::getNextToken() { if (pos >= 0 && Text[pos] == '\r') --pos; // See whether there is an odd number of '\' before this. + // FIXME: This is wrong. A '\' followed by a newline is always removed, + // regardless of whether there is another '\' before it. + // FIXME: Newlines can also be escaped by a '?' '?' '/' trigraph. unsigned count = 0; for (; pos >= 0; --pos, ++count) if (Text[pos] != '\\') diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 004800fc2a4e..bbc2d1e52b63 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -796,10 +796,11 @@ private: while (CurrentToken) { FormatToken *Tok = CurrentToken; next(); - if (Tok->isOneOf(Keywords.kw___has_include, - Keywords.kw___has_include_next)) { + if (Tok->is(tok::l_paren)) + parseParens(); + else if (Tok->isOneOf(Keywords.kw___has_include, + Keywords.kw___has_include_next)) parseHasInclude(); - } } return Type; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index ab9f20304c9c..0e0eb40eb334 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1353,13 +1353,11 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) .Case("c++", IK_CXX) - .Case("c++-module", IK_CXX) .Case("objective-c", IK_ObjC) .Case("objective-c++", IK_ObjCXX) .Case("cpp-output", IK_PreprocessedC) .Case("assembler-with-cpp", IK_Asm) .Case("c++-cpp-output", IK_PreprocessedCXX) - .Case("c++-module-cpp-output", IK_PreprocessedCXX) .Case("cuda-cpp-output", IK_PreprocessedCuda) .Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC) @@ -2324,6 +2322,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.getAllArgValues(OPT_fxray_always_instrument); Opts.XRayNeverInstrumentFiles = Args.getAllArgValues(OPT_fxray_never_instrument); + + // -fallow-editor-placeholders + Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h index dccba4e40b2d..1c94aca69381 100644 --- a/lib/Headers/smmintrin.h +++ b/lib/Headers/smmintrin.h @@ -56,8 +56,7 @@ /// __m128 _mm_ceil_ps(__m128 X); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float] values to be rounded up. @@ -74,8 +73,7 @@ /// __m128d _mm_ceil_pd(__m128d X); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double] values to be rounded up. @@ -94,8 +92,7 @@ /// __m128 _mm_ceil_ss(__m128 X, __m128 Y); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are @@ -120,8 +117,7 @@ /// __m128d _mm_ceil_sd(__m128d X, __m128d Y); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is @@ -144,8 +140,7 @@ /// __m128 _mm_floor_ps(__m128 X); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float] values to be rounded down. @@ -162,8 +157,7 @@ /// __m128d _mm_floor_pd(__m128d X); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. @@ -182,8 +176,7 @@ /// __m128 _mm_floor_ss(__m128 X, __m128 Y); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are @@ -208,8 +201,7 @@ /// __m128d _mm_floor_sd(__m128d X, __m128d Y); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is @@ -233,8 +225,7 @@ /// __m128 _mm_round_ps(__m128 X, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float]. @@ -269,8 +260,7 @@ /// __m128 _mm_round_ss(__m128 X, __m128 Y, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are @@ -310,8 +300,7 @@ /// __m128d _mm_round_pd(__m128d X, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. @@ -333,7 +322,6 @@ #define _mm_round_pd(X, M) __extension__ ({ \ (__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M)); }) - /// \brief Copies the upper element of the first 128-bit vector operand to the /// corresponding upper element of the 128-bit result vector of [2 x double]. /// Rounds the lower element of the second 128-bit vector operand to an @@ -347,8 +335,7 @@ /// __m128d _mm_round_sd(__m128d X, __m128d Y, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is @@ -388,8 +375,7 @@ /// __m128d _mm_blend_pd(__m128d V1, __m128d V2, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VBLENDPD / BLENDPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction. /// /// \param V1 /// A 128-bit vector of [2 x double]. @@ -419,8 +405,7 @@ /// __m128 _mm_blend_ps(__m128 V1, __m128 V2, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VBLENDPS / BLENDPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VBLENDPS / BLENDPS </c> instruction. /// /// \param V1 /// A 128-bit vector of [4 x float]. @@ -447,8 +432,7 @@ /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VBLENDVPD / BLENDVPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VBLENDVPD / BLENDVPD </c> instruction. /// /// \param __V1 /// A 128-bit vector of [2 x double]. @@ -475,8 +459,7 @@ _mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VBLENDVPS / BLENDVPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VBLENDVPS / BLENDVPS </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x float]. @@ -503,8 +486,7 @@ _mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPBLENDVB / PBLENDVB </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPBLENDVB / PBLENDVB </c> instruction. /// /// \param __V1 /// A 128-bit vector of [16 x i8]. @@ -535,8 +517,7 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M) /// __m128i _mm_blend_epi16(__m128i V1, __m128i V2, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPBLENDW / PBLENDW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPBLENDW / PBLENDW </c> instruction. /// /// \param V1 /// A 128-bit vector of [8 x i16]. @@ -569,8 +550,7 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMULLD / PMULLD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMULLD / PMULLD </c> instruction. /// /// \param __V1 /// A 128-bit integer vector. @@ -589,8 +569,7 @@ _mm_mullo_epi32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMULDQ / PMULDQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMULDQ / PMULDQ </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x i32]. @@ -617,8 +596,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) /// __m128 _mm_dp_ps(__m128 X, __m128 Y, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VDPPS / DPPS </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VDPPS / DPPS </c> instruction. /// /// \param X /// A 128-bit vector of [4 x float]. @@ -652,8 +630,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) /// __m128d _mm_dp_pd(__m128d X, __m128d Y, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VDPPD / DPPD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VDPPD / DPPD </c> instruction. /// /// \param X /// A 128-bit vector of [2 x double]. @@ -680,8 +657,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VMOVNTDQA / MOVNTDQA </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VMOVNTDQA / MOVNTDQA </c> instruction. /// /// \param __V /// A pointer to a 128-bit aligned memory location that contains the integer @@ -701,8 +677,7 @@ _mm_stream_load_si128 (__m128i const *__V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMINSB / PMINSB </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMINSB / PMINSB </c> instruction. /// /// \param __V1 /// A 128-bit vector of [16 x i8]. @@ -721,8 +696,7 @@ _mm_min_epi8 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMAXSB / PMAXSB </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMAXSB / PMAXSB </c> instruction. /// /// \param __V1 /// A 128-bit vector of [16 x i8]. @@ -741,8 +715,7 @@ _mm_max_epi8 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMINUW / PMINUW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMINUW / PMINUW </c> instruction. /// /// \param __V1 /// A 128-bit vector of [8 x u16]. @@ -761,8 +734,7 @@ _mm_min_epu16 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMAXUW / PMAXUW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMAXUW / PMAXUW </c> instruction. /// /// \param __V1 /// A 128-bit vector of [8 x u16]. @@ -781,8 +753,7 @@ _mm_max_epu16 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMINSD / PMINSD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMINSD / PMINSD </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x i32]. @@ -801,8 +772,7 @@ _mm_min_epi32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMAXSD / PMAXSD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMAXSD / PMAXSD </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x i32]. @@ -821,8 +791,7 @@ _mm_max_epi32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMINUD / PMINUD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMINUD / PMINUD </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x u32]. @@ -841,8 +810,7 @@ _mm_min_epu32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMAXUD / PMAXUD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMAXUD / PMAXUD </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x u32]. @@ -867,7 +835,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// __m128 _mm_insert_ps(__m128 X, __m128 Y, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VINSERTPS </i> </c> instruction. +/// This intrinsic corresponds to the <c> VINSERTPS </c> instruction. /// /// \param X /// A 128-bit vector source operand of [4 x float]. With the exception of @@ -907,7 +875,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// int _mm_extract_ps(__m128 X, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VEXTRACTPS / EXTRACTPS </i> </c> +/// This intrinsic corresponds to the <c> VEXTRACTPS / EXTRACTPS </c> /// instruction. /// /// \param X @@ -951,8 +919,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// __m128i _mm_insert_epi8(__m128i X, int I, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPINSRB / PINSRB </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPINSRB / PINSRB </c> instruction. /// /// \param X /// A 128-bit integer vector of [16 x i8]. This vector is copied to the @@ -997,8 +964,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// __m128i _mm_insert_epi32(__m128i X, int I, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPINSRD / PINSRD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPINSRD / PINSRD </c> instruction. /// /// \param X /// A 128-bit integer vector of [4 x i32]. This vector is copied to the @@ -1009,7 +975,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// specified by \a N. /// \param N /// An immediate value. Bits [1:0] specify the bit offset in the result at -/// which the integer \a I is written. +/// which the integer \a I is written. \n /// 00: Bits [31:0] of the result are used for insertion. \n /// 01: Bits [63:32] of the result are used for insertion. \n /// 10: Bits [95:64] of the result are used for insertion. \n @@ -1019,6 +985,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) ({ __v4si __a = (__v4si)(__m128i)(X); \ __a[(N) & 3] = (I); \ (__m128i)__a;})) + #ifdef __x86_64__ /// \brief Constructs a 128-bit vector of [2 x i64] by first making a copy of /// the 128-bit integer vector parameter, and then inserting the 64-bit @@ -1031,8 +998,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// __m128i _mm_insert_epi64(__m128i X, long long I, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPINSRQ / PINSRQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPINSRQ / PINSRQ </c> instruction. /// /// \param X /// A 128-bit integer vector of [2 x i64]. This vector is copied to the @@ -1043,7 +1009,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// specified by \a N. /// \param N /// An immediate value. Bit [0] specifies the bit offset in the result at -/// which the integer \a I is written. +/// which the integer \a I is written. \n /// 0: Bits [63:0] of the result are used for insertion. \n /// 1: Bits [127:64] of the result are used for insertion. \n /// \returns A 128-bit integer vector containing the constructed values. @@ -1065,14 +1031,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// int _mm_extract_epi8(__m128i X, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPEXTRB / PEXTRB </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPEXTRB / PEXTRB </c> instruction. /// /// \param X /// A 128-bit integer vector. /// \param N -/// An immediate value. Bits [3:0] specify which 8-bit vector element -/// from the argument \a X to extract and copy to the result. \n +/// An immediate value. Bits [3:0] specify which 8-bit vector element from +/// the argument \a X to extract and copy to the result. \n /// 0000: Bits [7:0] of parameter \a X are extracted. \n /// 0001: Bits [15:8] of the parameter \a X are extracted. \n /// 0010: Bits [23:16] of the parameter \a X are extracted. \n @@ -1105,14 +1070,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// int _mm_extract_epi32(__m128i X, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPEXTRD / PEXTRD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPEXTRD / PEXTRD </c> instruction. /// /// \param X /// A 128-bit integer vector. /// \param N -/// An immediate value. Bits [1:0] specify which 32-bit vector element -/// from the argument \a X to extract and copy to the result. \n +/// An immediate value. Bits [1:0] specify which 32-bit vector element from +/// the argument \a X to extract and copy to the result. \n /// 00: Bits [31:0] of the parameter \a X are extracted. \n /// 01: Bits [63:32] of the parameter \a X are extracted. \n /// 10: Bits [95:64] of the parameter \a X are extracted. \n @@ -1122,6 +1086,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) #define _mm_extract_epi32(X, N) (__extension__ \ ({ __v4si __a = (__v4si)(__m128i)(X); \ (int)__a[(N) & 3];})) + #ifdef __x86_64__ /// \brief Extracts a 64-bit element from the 128-bit integer vector of /// [2 x i64], using the immediate value parameter \a N as a selector. @@ -1132,14 +1097,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// long long _mm_extract_epi64(__m128i X, const int N); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPEXTRQ / PEXTRQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPEXTRQ / PEXTRQ </c> instruction. /// /// \param X /// A 128-bit integer vector. /// \param N -/// An immediate value. Bit [0] specifies which 64-bit vector element -/// from the argument \a X to return. \n +/// An immediate value. Bit [0] specifies which 64-bit vector element from +/// the argument \a X to return. \n /// 0: Bits [63:0] are returned. \n /// 1: Bits [127:64] are returned. \n /// \returns A 64-bit integer. @@ -1154,8 +1118,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param __M /// A 128-bit integer vector containing the bits to be tested. @@ -1173,8 +1136,7 @@ _mm_testz_si128(__m128i __M, __m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param __M /// A 128-bit integer vector containing the bits to be tested. @@ -1192,8 +1154,7 @@ _mm_testc_si128(__m128i __M, __m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param __M /// A 128-bit integer vector containing the bits to be tested. @@ -1216,8 +1177,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V) /// int _mm_test_all_ones(__m128i V); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param V /// A 128-bit integer vector containing the bits to be tested. @@ -1234,8 +1194,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V) /// int _mm_test_mix_ones_zeros(__m128i M, __m128i V); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param M /// A 128-bit integer vector containing the bits to be tested. @@ -1254,8 +1213,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V) /// int _mm_test_all_zeros(__m128i M, __m128i V); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction. /// /// \param M /// A 128-bit integer vector containing the bits to be tested. @@ -1270,8 +1228,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPCMPEQQ / PCMPEQQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPCMPEQQ / PCMPEQQ </c> instruction. /// /// \param __V1 /// A 128-bit integer vector. @@ -1292,8 +1249,7 @@ _mm_cmpeq_epi64(__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXBW / PMOVSXBW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXBW / PMOVSXBW </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are sign- @@ -1314,8 +1270,7 @@ _mm_cvtepi8_epi16(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXBD / PMOVSXBD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXBD / PMOVSXBD </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are sign- @@ -1336,8 +1291,7 @@ _mm_cvtepi8_epi32(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXBQ / PMOVSXBQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXBQ / PMOVSXBQ </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are sign- @@ -1358,8 +1312,7 @@ _mm_cvtepi8_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXWD / PMOVSXWD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXWD / PMOVSXWD </c> instruction. /// /// \param __V /// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are sign- @@ -1378,8 +1331,7 @@ _mm_cvtepi16_epi32(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXWQ / PMOVSXWQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXWQ / PMOVSXWQ </c> instruction. /// /// \param __V /// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are sign- @@ -1398,8 +1350,7 @@ _mm_cvtepi16_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVSXDQ / PMOVSXDQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVSXDQ / PMOVSXDQ </c> instruction. /// /// \param __V /// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are sign- @@ -1419,8 +1370,7 @@ _mm_cvtepi32_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXBW / PMOVZXBW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXBW / PMOVZXBW </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are zero- @@ -1439,8 +1389,7 @@ _mm_cvtepu8_epi16(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXBD / PMOVZXBD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXBD / PMOVZXBD </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are zero- @@ -1459,8 +1408,7 @@ _mm_cvtepu8_epi32(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXBQ / PMOVZXBQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXBQ / PMOVZXBQ </c> instruction. /// /// \param __V /// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are zero- @@ -1479,8 +1427,7 @@ _mm_cvtepu8_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXWD / PMOVZXWD </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXWD / PMOVZXWD </c> instruction. /// /// \param __V /// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are zero- @@ -1499,8 +1446,7 @@ _mm_cvtepu16_epi32(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXWQ / PMOVZXWQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXWQ / PMOVZXWQ </c> instruction. /// /// \param __V /// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are zero- @@ -1519,8 +1465,7 @@ _mm_cvtepu16_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPMOVZXDQ / PMOVZXDQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPMOVZXDQ / PMOVZXDQ </c> instruction. /// /// \param __V /// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are zero- @@ -1540,8 +1485,7 @@ _mm_cvtepu32_epi64(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPACKUSDW / PACKUSDW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPACKUSDW / PACKUSDW </c> instruction. /// /// \param __V1 /// A 128-bit vector of [4 x i32]. Each 32-bit element is treated as a @@ -1574,8 +1518,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2) /// __m128i _mm_mpsadbw_epu8(__m128i X, __m128i Y, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VMPSADBW / MPSADBW </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VMPSADBW / MPSADBW </c> instruction. /// /// \param X /// A 128-bit vector of [16 x i8]. @@ -1608,7 +1551,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPHMINPOSUW / PHMINPOSUW </i> </c> +/// This intrinsic corresponds to the <c> VPHMINPOSUW / PHMINPOSUW </c> /// instruction. /// /// \param __V @@ -1668,7 +1611,7 @@ _mm_minpos_epu16(__m128i __V) /// __m128i _mm_cmpistrm(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRM / PCMPISTRM </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRM / PCMPISTRM </c> /// instruction. /// /// \param A @@ -1724,7 +1667,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistri(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -1778,7 +1721,7 @@ _mm_minpos_epu16(__m128i __V) /// __m128i _mm_cmpestrm(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRM / PCMPESTRM </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRM / PCMPESTRM </c> /// instruction. /// /// \param A @@ -1839,7 +1782,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestri(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c> /// instruction. /// /// \param A @@ -1899,7 +1842,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistra(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -1949,7 +1892,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistrc(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -1997,7 +1940,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistro(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -2046,7 +1989,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistrs(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -2096,7 +2039,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpistrz(__m128i A, __m128i B, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c> /// instruction. /// /// \param A @@ -2146,7 +2089,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestra(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c> /// instruction. /// /// \param A @@ -2201,7 +2144,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestrc(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c> /// instruction. /// /// \param A @@ -2243,6 +2186,7 @@ _mm_minpos_epu16(__m128i __V) (int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \ (__v16qi)(__m128i)(B), (int)(LB), \ (int)(M)) + /// \brief Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands /// \a A and \a B. Returns bit 0 of the resulting bit mask. @@ -2253,7 +2197,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestro(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c> /// instruction. /// /// \param A @@ -2307,7 +2251,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestrs(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c> +/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c> /// instruction. /// /// \param A @@ -2362,7 +2306,7 @@ _mm_minpos_epu16(__m128i __V) /// int _mm_cmpestrz(__m128i A, int LA, __m128i B, int LB, const int M); /// \endcode /// -/// This intrinsic corresponds to the <c> <i> VPCMPESTRI </i> </c> instruction. +/// This intrinsic corresponds to the <c> VPCMPESTRI </c> instruction. /// /// \param A /// A 128-bit integer vector containing one of the source operands to be @@ -2412,8 +2356,7 @@ _mm_minpos_epu16(__m128i __V) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> VPCMPGTQ / PCMPGTQ </i> </c> -/// instruction. +/// This intrinsic corresponds to the <c> VPCMPGTQ / PCMPGTQ </c> instruction. /// /// \param __V1 /// A 128-bit integer vector. @@ -2432,7 +2375,7 @@ _mm_cmpgt_epi64(__m128i __V1, __m128i __V2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> CRC32B </i> </c> instruction. +/// This intrinsic corresponds to the <c> CRC32B </c> instruction. /// /// \param __C /// An unsigned integer operand to add to the CRC-32C checksum of operand @@ -2452,7 +2395,7 @@ _mm_crc32_u8(unsigned int __C, unsigned char __D) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> CRC32W </i> </c> instruction. +/// This intrinsic corresponds to the <c> CRC32W </c> instruction. /// /// \param __C /// An unsigned integer operand to add to the CRC-32C checksum of operand @@ -2472,7 +2415,7 @@ _mm_crc32_u16(unsigned int __C, unsigned short __D) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> CRC32L </i> </c> instruction. +/// This intrinsic corresponds to the <c> CRC32L </c> instruction. /// /// \param __C /// An unsigned integer operand to add to the CRC-32C checksum of operand @@ -2493,7 +2436,7 @@ _mm_crc32_u32(unsigned int __C, unsigned int __D) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the <c> <i> CRC32Q </i> </c> instruction. +/// This intrinsic corresponds to the <c> CRC32Q </c> instruction. /// /// \param __C /// An unsigned integer operand to add to the CRC-32C checksum of operand diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index bb8e29cd9052..5c312c08efb6 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -2540,7 +2540,7 @@ void _mm_setcsr(unsigned int __i); /// A 128-bit vector of [4 x float]. /// \param mask /// An immediate value containing an 8-bit value specifying which elements to -/// copy from \ a and \a b. \n +/// copy from \a a and \a b. \n /// Bits [3:0] specify the values copied from operand \a a. \n /// Bits [7:4] specify the values copied from operand \a b. \n /// The destinations within the 128-bit destination are assigned values as diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp index 08acc96c4efb..e568c838b7b0 100644 --- a/lib/Index/CommentToXML.cpp +++ b/lib/Index/CommentToXML.cpp @@ -592,12 +592,10 @@ void CommentASTToXMLConverter::formatTextOfDeclaration( unsigned Offset = 0; unsigned Length = Declaration.size(); - bool IncompleteFormat = false; format::FormatStyle Style = format::getLLVMStyle(); Style.FixNamespaceComments = false; tooling::Replacements Replaces = - reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd", - &IncompleteFormat); + reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd"); auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces); if (static_cast<bool>(FormattedStringDecl)) { Declaration = *FormattedStringDecl; diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index dae0cdc0d9c9..0e893505516f 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -495,8 +495,18 @@ public: ClassTemplateSpecializationDecl *D) { // FIXME: Notify subsequent callbacks if info comes from implicit // instantiation. - if (D->isThisDeclarationADefinition()) - IndexCtx.indexTagDecl(D); + if (D->isThisDeclarationADefinition()) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + Template = D->getSpecializedTemplateOrPartial(); + const Decl *SpecializationOf = + Template.is<ClassTemplateDecl *>() + ? (Decl *)Template.get<ClassTemplateDecl *>() + : Template.get<ClassTemplatePartialSpecializationDecl *>(); + IndexCtx.indexTagDecl( + D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), + SpecializationOf)); + } return true; } diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index fe3c17845daa..ea66b7017951 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -346,6 +346,7 @@ bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, APPLY_FOR_ROLE(RelationAccessorOf); APPLY_FOR_ROLE(RelationContainedBy); APPLY_FOR_ROLE(RelationIBTypeOf); + APPLY_FOR_ROLE(RelationSpecializationOf); #undef APPLY_FOR_ROLE @@ -386,6 +387,7 @@ void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; case SymbolRole::RelationContainedBy: OS << "RelCont"; break; case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break; + case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break; } }); } diff --git a/lib/Index/IndexTypeSourceInfo.cpp b/lib/Index/IndexTypeSourceInfo.cpp index 0645d5be5268..a3566a9f2ae8 100644 --- a/lib/Index/IndexTypeSourceInfo.cpp +++ b/lib/Index/IndexTypeSourceInfo.cpp @@ -208,11 +208,12 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, } } -void IndexingContext::indexTagDecl(const TagDecl *D) { +void IndexingContext::indexTagDecl(const TagDecl *D, + ArrayRef<SymbolRelation> Relations) { if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) return; - if (handleDecl(D)) { + if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) { if (D->isThisDeclarationADefinition()) { indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) { diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp index f393b11ab884..85574d0a314d 100644 --- a/lib/Index/IndexingContext.cpp +++ b/lib/Index/IndexingContext.cpp @@ -233,6 +233,7 @@ static bool shouldReportOccurrenceForSystemDeclOnlyMode( case SymbolRole::RelationReceivedBy: case SymbolRole::RelationCalledBy: case SymbolRole::RelationContainedBy: + case SymbolRole::RelationSpecializationOf: return true; } llvm_unreachable("Unsupported SymbolRole value!"); diff --git a/lib/Index/IndexingContext.h b/lib/Index/IndexingContext.h index 933b0a2cda07..1ebf6f9ce67a 100644 --- a/lib/Index/IndexingContext.h +++ b/lib/Index/IndexingContext.h @@ -80,7 +80,8 @@ public: bool indexDecl(const Decl *D); - void indexTagDecl(const TagDecl *D); + void indexTagDecl(const TagDecl *D, + ArrayRef<SymbolRelation> Relations = None); void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, const DeclContext *DC = nullptr, diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 4c051939471c..003c9b5eed1b 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1171,6 +1171,8 @@ const char *Lexer::SkipEscapedNewLines(const char *P) { // If not a trigraph for escape, bail out. if (P[1] != '?' || P[2] != '/') return P; + // FIXME: Take LangOpts into account; the language might not + // support trigraphs. AfterEscape = P+3; } else { return P; @@ -1282,12 +1284,6 @@ Slash: Size += EscapedNewLineSize; Ptr += EscapedNewLineSize; - // If the char that we finally got was a \n, then we must have had - // something like \<newline><newline>. We don't want to consume the - // second newline. - if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0') - return ' '; - // Use slow version to accumulate a correct size field. return getCharAndSizeSlow(Ptr, Size, Tok); } @@ -1338,12 +1334,6 @@ Slash: Size += EscapedNewLineSize; Ptr += EscapedNewLineSize; - // If the char that we finally got was a \n, then we must have had - // something like \<newline><newline>. We don't want to consume the - // second newline. - if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0') - return ' '; - // Use slow version to accumulate a correct size field. return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); } @@ -2070,8 +2060,11 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, // Scan over the body of the comment. The common case, when scanning, is that // the comment contains normal ascii characters with nothing interesting in // them. As such, optimize for this case with the inner loop. + // + // This loop terminates with CurPtr pointing at the newline (or end of buffer) + // character that ends the line comment. char C; - do { + while (true) { C = *CurPtr; // Skip over characters in the fast loop. while (C != 0 && // Potentially EOF. @@ -2088,10 +2081,12 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, HasSpace = true; } - if (*EscapePtr == '\\') // Escaped newline. + if (*EscapePtr == '\\') + // Escaped newline. CurPtr = EscapePtr; else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' && - EscapePtr[-2] == '?') // Trigraph-escaped newline. + EscapePtr[-2] == '?' && LangOpts.Trigraphs) + // Trigraph-escaped newline. CurPtr = EscapePtr-2; else break; // This is a newline, we're done. @@ -2140,9 +2135,9 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, } } - if (CurPtr == BufferEnd+1) { - --CurPtr; - break; + if (C == '\r' || C == '\n' || CurPtr == BufferEnd + 1) { + --CurPtr; + break; } if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) { @@ -2150,8 +2145,7 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, cutOffLexing(); return false; } - - } while (C != '\n' && C != '\r'); + } // Found but did not consume the newline. Notify comment handlers about the // comment unless we're in a #if 0 block. @@ -2722,6 +2716,37 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { return false; } +static const char *findPlaceholderEnd(const char *CurPtr, + const char *BufferEnd) { + if (CurPtr == BufferEnd) + return nullptr; + BufferEnd -= 1; // Scan until the second last character. + for (; CurPtr != BufferEnd; ++CurPtr) { + if (CurPtr[0] == '#' && CurPtr[1] == '>') + return CurPtr + 2; + } + return nullptr; +} + +bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) { + assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!"); + if (!PP || LexingRawMode) + return false; + const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd); + if (!End) + return false; + const char *Start = CurPtr - 1; + if (!LangOpts.AllowEditorPlaceholders) + Diag(Start, diag::err_placeholder_in_source); + Result.startToken(); + FormTokenWithChars(Result, End, tok::raw_identifier); + Result.setRawIdentifierData(Start); + PP->LookUpIdentifierInfo(Result); + Result.setFlag(Token::IsEditorPlaceholder); + BufferPtr = End; + return true; +} + bool Lexer::isCodeCompletionPoint(const char *CurPtr) const { if (PP && PP->isCodeCompletionEnabled()) { SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart); @@ -3479,6 +3504,8 @@ LexNextToken: } else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::l_brace; + } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) { + return true; } else { Kind = tok::less; } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 4f3db8dd6436..5b60ed3f812a 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -2002,9 +2002,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) { } if (!Dir) { - Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found) + Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found) << DirName; - HadError = true; return; } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 4db17c344b67..cf0c953b61f8 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -303,9 +303,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { if (const FileEntry *FE = CurPPLexer->getFileEntry()) { HeaderInfo.SetFileControllingMacro(FE, ControllingMacro); if (MacroInfo *MI = - getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) { - MI->UsedForHeaderGuard = true; - } + getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) + MI->setUsedForHeaderGuard(true); if (const IdentifierInfo *DefinedMacro = CurPPLexer->MIOpt.GetDefinedMacro()) { if (!isMacroDefined(ControllingMacro) && diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index c8de6b35f9ef..c34cd09a6238 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -183,6 +183,17 @@ private: Sema &Actions; }; +/// PragmaAttributeHandler - "\#pragma clang attribute ...". +struct PragmaAttributeHandler : public PragmaHandler { + PragmaAttributeHandler(AttributeFactory &AttrFactory) + : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; + + /// A pool of attributes that were parsed in \#pragma clang attribute. + ParsedAttributes AttributesForPragmaAttribute; +}; + } // end namespace void Parser::initializePragmaHandlers() { @@ -275,6 +286,9 @@ void Parser::initializePragmaHandlers() { FPHandler.reset(new PragmaFPHandler()); PP.AddPragmaHandler("clang", FPHandler.get()); + + AttributePragmaHandler.reset(new PragmaAttributeHandler(AttrFactory)); + PP.AddPragmaHandler("clang", AttributePragmaHandler.get()); } void Parser::resetPragmaHandlers() { @@ -356,6 +370,9 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler("clang", FPHandler.get()); FPHandler.reset(); + + PP.RemovePragmaHandler("clang", AttributePragmaHandler.get()); + AttributePragmaHandler.reset(); } /// \brief Handle the annotation token produced for #pragma unused(...) @@ -966,6 +983,422 @@ bool Parser::HandlePragmaLoopHint(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" + } + llvm_unreachable("Invalid attribute subject match rule"); + return false; +} + +static void diagnoseExpectedAttributeSubjectSubRule( + Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, + SourceLocation SubRuleLoc) { + auto Diagnostic = + PRef.Diag(SubRuleLoc, + diag::err_pragma_attribute_expected_subject_sub_identifier) + << PrimaryRuleName; + if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) + Diagnostic << /*SubRulesSupported=*/1 << SubRules; + else + Diagnostic << /*SubRulesSupported=*/0; +} + +static void diagnoseUnknownAttributeSubjectSubRule( + Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, + StringRef SubRuleName, SourceLocation SubRuleLoc) { + + auto Diagnostic = + PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule) + << SubRuleName << PrimaryRuleName; + if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) + Diagnostic << /*SubRulesSupported=*/1 << SubRules; + else + Diagnostic << /*SubRulesSupported=*/0; +} + +bool Parser::ParsePragmaAttributeSubjectMatchRuleSet( + attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc, + SourceLocation &LastMatchRuleEndLoc) { + bool IsAny = false; + BalancedDelimiterTracker AnyParens(*this, tok::l_paren); + if (getIdentifier(Tok) == "any") { + AnyLoc = ConsumeToken(); + IsAny = true; + if (AnyParens.expectAndConsume()) + return true; + } + + do { + // Parse the subject matcher rule. + StringRef Name = getIdentifier(Tok); + if (Name.empty()) { + Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier); + return true; + } + std::pair<Optional<attr::SubjectMatchRule>, + Optional<attr::SubjectMatchRule> (*)(StringRef, bool)> + Rule = isAttributeSubjectMatchRule(Name); + if (!Rule.first) { + Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name; + return true; + } + attr::SubjectMatchRule PrimaryRule = *Rule.first; + SourceLocation RuleLoc = ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (isAbstractAttrMatcherRule(PrimaryRule)) { + if (Parens.expectAndConsume()) + return true; + } else if (Parens.consumeOpen()) { + if (!SubjectMatchRules + .insert( + std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc))) + .second) + Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) + << Name + << FixItHint::CreateRemoval(SourceRange( + RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc)); + LastMatchRuleEndLoc = RuleLoc; + continue; + } + + // Parse the sub-rules. + StringRef SubRuleName = getIdentifier(Tok); + if (SubRuleName.empty()) { + diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, + Tok.getLocation()); + return true; + } + attr::SubjectMatchRule SubRule; + if (SubRuleName == "unless") { + SourceLocation SubRuleLoc = ConsumeToken(); + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume()) + return true; + SubRuleName = getIdentifier(Tok); + if (SubRuleName.empty()) { + diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, + SubRuleLoc); + return true; + } + auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true); + if (!SubRuleOrNone) { + std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")"; + diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, + SubRuleUnlessName, SubRuleLoc); + return true; + } + SubRule = *SubRuleOrNone; + ConsumeToken(); + if (Parens.consumeClose()) + return true; + } else { + auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false); + if (!SubRuleOrNone) { + diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, + SubRuleName, Tok.getLocation()); + return true; + } + SubRule = *SubRuleOrNone; + ConsumeToken(); + } + SourceLocation RuleEndLoc = Tok.getLocation(); + LastMatchRuleEndLoc = RuleEndLoc; + if (Parens.consumeClose()) + return true; + if (!SubjectMatchRules + .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc))) + .second) { + Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) + << attr::getSubjectMatchRuleSpelling(SubRule) + << FixItHint::CreateRemoval(SourceRange( + RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc)); + continue; + } + } while (IsAny && TryConsumeToken(tok::comma)); + + if (IsAny) + if (AnyParens.consumeClose()) + return true; + + return false; +} + +namespace { + +/// Describes the stage at which attribute subject rule parsing was interruped. +enum class MissingAttributeSubjectRulesRecoveryPoint { + Comma, + ApplyTo, + Equals, + Any, + None, +}; + +MissingAttributeSubjectRulesRecoveryPoint +getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) { + if (const auto *II = Tok.getIdentifierInfo()) { + if (II->isStr("apply_to")) + return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo; + if (II->isStr("any")) + return MissingAttributeSubjectRulesRecoveryPoint::Any; + } + if (Tok.is(tok::equal)) + return MissingAttributeSubjectRulesRecoveryPoint::Equals; + return MissingAttributeSubjectRulesRecoveryPoint::None; +} + +/// Creates a diagnostic for the attribute subject rule parsing diagnostic that +/// suggests the possible attribute subject rules in a fix-it together with +/// any other missing tokens. +DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic( + unsigned DiagID, AttributeList &Attribute, + MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) { + SourceLocation Loc = PRef.getEndOfPreviousToken(); + if (Loc.isInvalid()) + Loc = PRef.getCurToken().getLocation(); + auto Diagnostic = PRef.Diag(Loc, DiagID); + std::string FixIt; + MissingAttributeSubjectRulesRecoveryPoint EndPoint = + getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken()); + if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma) + FixIt = ", "; + if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo && + EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo) + FixIt += "apply_to"; + if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals && + EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals) + FixIt += " = "; + SourceRange FixItRange(Loc); + if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) { + // Gather the subject match rules that are supported by the attribute. + SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet; + Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet); + if (SubjectMatchRuleSet.empty()) { + // FIXME: We can emit a "fix-it" with a subject list placeholder when + // placeholders will be supported by the fix-its. + return Diagnostic; + } + FixIt += "any("; + bool NeedsComma = false; + for (const auto &I : SubjectMatchRuleSet) { + // Ensure that the missing rule is reported in the fix-it only when it's + // supported in the current language mode. + if (!I.second) + continue; + if (NeedsComma) + FixIt += ", "; + else + NeedsComma = true; + FixIt += attr::getSubjectMatchRuleSpelling(I.first); + } + FixIt += ")"; + // Check if we need to remove the range + PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch); + FixItRange.setEnd(PRef.getCurToken().getLocation()); + } + if (FixItRange.getBegin() == FixItRange.getEnd()) + Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt); + else + Diagnostic << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(FixItRange), FixIt); + return Diagnostic; +} + +} // end anonymous namespace + +void Parser::HandlePragmaAttribute() { + assert(Tok.is(tok::annot_pragma_attribute) && + "Expected #pragma attribute annotation token"); + SourceLocation PragmaLoc = Tok.getLocation(); + auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue()); + if (Info->Action == PragmaAttributeInfo::Pop) { + ConsumeToken(); + Actions.ActOnPragmaAttributePop(PragmaLoc); + return; + } + // Parse the actual attribute with its arguments. + assert(Info->Action == PragmaAttributeInfo::Push && + "Unexpected #pragma attribute command"); + PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false); + ConsumeToken(); + + ParsedAttributes &Attrs = Info->Attributes; + Attrs.clearListOnly(); + + auto SkipToEnd = [this]() { + SkipUntil(tok::eof, StopBeforeMatch); + ConsumeToken(); + }; + + if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { + // Parse the CXX11 style attribute. + ParseCXX11AttributeSpecifier(Attrs); + } else if (Tok.is(tok::kw___attribute)) { + ConsumeToken(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "attribute")) + return SkipToEnd(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) + return SkipToEnd(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_pragma_attribute_expected_attribute_name); + SkipToEnd(); + return; + } + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_GNU); + else + ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr, + /*ScopeName=*/nullptr, + /*ScopeLoc=*/SourceLocation(), + AttributeList::AS_GNU, + /*Declarator=*/nullptr); + + if (ExpectAndConsume(tok::r_paren)) + return SkipToEnd(); + if (ExpectAndConsume(tok::r_paren)) + return SkipToEnd(); + } else if (Tok.is(tok::kw___declspec)) { + ParseMicrosoftDeclSpecs(Attrs); + } else { + Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax); + if (Tok.getIdentifierInfo()) { + // If we suspect that this is an attribute suggest the use of + // '__attribute__'. + if (AttributeList::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr, + AttributeList::AS_GNU) != + AttributeList::UnknownAttribute) { + SourceLocation InsertStartLoc = Tok.getLocation(); + ConsumeToken(); + if (Tok.is(tok::l_paren)) { + ConsumeAnyToken(); + SkipUntil(tok::r_paren, StopBeforeMatch); + if (Tok.isNot(tok::r_paren)) + return SkipToEnd(); + } + Diag(Tok, diag::note_pragma_attribute_use_attribute_kw) + << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((") + << FixItHint::CreateInsertion(Tok.getEndLoc(), "))"); + } + } + SkipToEnd(); + return; + } + + if (!Attrs.getList() || Attrs.getList()->isInvalid()) { + SkipToEnd(); + return; + } + + // Ensure that we don't have more than one attribute. + if (Attrs.getList()->getNext()) { + SourceLocation Loc = Attrs.getList()->getNext()->getLoc(); + Diag(Loc, diag::err_pragma_attribute_multiple_attributes); + SkipToEnd(); + return; + } + + if (!Attrs.getList()->isSupportedByPragmaAttribute()) { + Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute) + << Attrs.getList()->getName(); + SkipToEnd(); + return; + } + AttributeList &Attribute = *Attrs.getList(); + + // Parse the subject-list. + if (!TryConsumeToken(tok::comma)) { + createExpectedAttributeSubjectRulesTokenDiagnostic( + diag::err_expected, Attribute, + MissingAttributeSubjectRulesRecoveryPoint::Comma, *this) + << tok::comma; + SkipToEnd(); + return; + } + + if (Tok.isNot(tok::identifier)) { + createExpectedAttributeSubjectRulesTokenDiagnostic( + diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute, + MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); + SkipToEnd(); + return; + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->isStr("apply_to")) { + createExpectedAttributeSubjectRulesTokenDiagnostic( + diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute, + MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); + SkipToEnd(); + return; + } + ConsumeToken(); + + if (!TryConsumeToken(tok::equal)) { + createExpectedAttributeSubjectRulesTokenDiagnostic( + diag::err_expected, Attribute, + MissingAttributeSubjectRulesRecoveryPoint::Equals, *this) + << tok::equal; + SkipToEnd(); + return; + } + + attr::ParsedSubjectMatchRuleSet SubjectMatchRules; + SourceLocation AnyLoc, LastMatchRuleEndLoc; + if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc, + LastMatchRuleEndLoc)) { + SkipToEnd(); + return; + } + + // Tokens following an ill-formed attribute will remain in the token stream + // and must be removed. + if (Tok.isNot(tok::eof)) { + Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute); + SkipToEnd(); + return; + } + + // Consume the eof terminator token. + ConsumeToken(); + + Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc, + std::move(SubjectMatchRules)); +} + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -2395,3 +2828,104 @@ void PragmaForceCUDAHostDeviceHandler::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); +} diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index eaff9fe8eedf..7d78046d0684 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index aa8ed91d382f..edbfc636bc46 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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) @@ -847,6 +851,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, default: dont_know: + if (Tok.isEditorPlaceholder()) { + ConsumeToken(); + return nullptr; + } // We can't tell whether this is a function-definition or declaration yet. return ParseDeclarationOrFunctionDefinition(attrs, DS); } @@ -1675,6 +1683,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() { return false; } } + if (Tok.isEditorPlaceholder()) + return true; Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return true; diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 55e9601bf5e5..724db456785f 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -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); } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 899d3fa83cc3..865aea9e2284 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -287,6 +287,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); break; + case Stmt::ObjCForCollectionStmtClass: { + auto *CS = cast<ObjCForCollectionStmt>(S); + unsigned Diag = diag::note_protected_by_objc_fast_enumeration; + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getLocStart())); + BuildScopeInformation(CS->getBody(), NewParentScope); + return; + } + case Stmt::IndirectGotoStmtClass: // "goto *&&lbl;" is a special case which we treat as equivalent // to a normal goto. In addition, we don't calculate scope in the diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 294b56059b33..950f04088822 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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 diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index c6e3cc886316..76ca65373dda 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -368,6 +368,219 @@ 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<int, std::pair<int, SourceRange>, 2> + RulesToFirstSpecifiedNegatedSubRule; + for (const auto &Rule : Rules) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + Optional<attr::SubjectMatchRule> ParentRule = + getParentAttrMatcherRule(MatchRule); + 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(MatchRule) + << 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(MatchRule)) + RulesToFirstSpecifiedNegatedSubRule.insert( + std::make_pair(*ParentRule, Rule)); + } + bool IgnoreNegatedSubRules = false; + for (const auto &Rule : Rules) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + Optional<attr::SubjectMatchRule> ParentRule = + getParentAttrMatcherRule(MatchRule); + 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( + attr::SubjectMatchRule(It->second.first)) + << attr::getSubjectMatchRuleSpelling(MatchRule) << 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(attr::SubjectMatchRule(Rule.first)); + } else { + for (const auto &Rule : Rules) { + if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first))) + SubjectMatchRules.push_back(attr::SubjectMatchRule(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(attr::SubjectMatchRule(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(); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 57471de78d3e..6da4d2a26191 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -480,6 +480,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool ErrorRecoveryLookup, bool *IsCorrectedToColon, bool OnlyNamespace) { + if (IdInfo.Identifier->isEditorPlaceholder()) + return true; LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, OnlyNamespace ? LookupNamespaceName : LookupNestedNameSpecifierName); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 81db0d3d00a7..45523b30ef22 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1391,8 +1391,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, } bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - llvm::APSInt Result; - if (BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || @@ -1439,8 +1437,6 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - llvm::APSInt Result; - if (BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index 4a55e51495a8..c709a1a723d0 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -454,7 +454,7 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, /*IsImplicit*/ true); Suspend = S.ActOnFinishFullExpr(Suspend.get()); if (Suspend.isInvalid()) { - S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required) << ((Name == "initial_suspend") ? 0 : 1); S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword; return StmtError(); @@ -660,6 +660,39 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E, return Res; } +/// Look up the std::nothrow object. +static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) { + NamespaceDecl *Std = S.getStdNamespace(); + assert(Std && "Should already be diagnosed"); + + LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc, + Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) { + // FIXME: <experimental/coroutine> should have been included already. + // If we require it to include <new> then this diagnostic is no longer + // needed. + S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found); + return nullptr; + } + + // FIXME: Mark the variable as ODR used. This currently does not work + // likely due to the scope at in which this function is called. + auto *VD = Result.getAsSingle<VarDecl>(); + if (!VD) { + Result.suppressDiagnostics(); + // We found something weird. Complain about the first thing we found. + NamedDecl *Found = *Result.begin(); + S.Diag(Found->getLocation(), diag::err_malformed_std_nothrow); + return nullptr; + } + + ExprResult DR = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, Loc); + if (DR.isInvalid()) + return nullptr; + + return DR.get(); +} + // Find an appropriate delete for the promise. static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType) { @@ -847,23 +880,53 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type)) return false; - // FIXME: Add nothrow_t placement arg for global alloc - // if ReturnStmtOnAllocFailure != nullptr. + const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr; + // FIXME: Add support for stateful allocators. FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; FunctionDecl *UnusedResult = nullptr; bool PassAlignment = false; + SmallVector<Expr *, 1> PlacementArgs; S.FindAllocationFunctions(Loc, SourceRange(), /*UseGlobal*/ false, PromiseType, - /*isArray*/ false, PassAlignment, - /*PlacementArgs*/ None, OperatorNew, UnusedResult); + /*isArray*/ false, PassAlignment, PlacementArgs, + OperatorNew, UnusedResult); - OperatorDelete = findDeleteForPromise(S, Loc, PromiseType); + bool IsGlobalOverload = + OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext()); + // If we didn't find a class-local new declaration and non-throwing new + // was is required then we need to lookup the non-throwing global operator + // instead. + if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) { + auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc); + if (!StdNoThrow) + return false; + PlacementArgs = {StdNoThrow}; + OperatorNew = nullptr; + S.FindAllocationFunctions(Loc, SourceRange(), + /*UseGlobal*/ true, PromiseType, + /*isArray*/ false, PassAlignment, PlacementArgs, + OperatorNew, UnusedResult); + } - if (!OperatorDelete || !OperatorNew) + assert(OperatorNew && "expected definition of operator new to be found"); + + if (RequiresNoThrowAlloc) { + const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>(); + if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) { + S.Diag(OperatorNew->getLocation(), + diag::err_coroutine_promise_new_requires_nothrow) + << OperatorNew; + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << OperatorNew; + return false; + } + } + + if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr) return false; Expr *FramePtr = @@ -879,8 +942,13 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { if (NewRef.isInvalid()) return false; + SmallVector<Expr *, 2> NewArgs(1, FrameSize); + for (auto Arg : PlacementArgs) + NewArgs.push_back(Arg); + ExprResult NewExpr = - S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc); + S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc); + NewExpr = S.ActOnFinishFullExpr(NewExpr.get()); if (NewExpr.isInvalid()) return false; @@ -906,6 +974,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { ExprResult DeleteExpr = S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc); + DeleteExpr = S.ActOnFinishFullExpr(DeleteExpr.get()); if (DeleteExpr.isInvalid()) return false; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c6a0b0101d37..f3ffcf5d696c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -628,6 +628,9 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, CXXScopeSpec *SS, ParsedType &SuggestedType, bool AllowClassTemplates) { + // Don't report typename errors for editor placeholders. + if (II->isEditorPlaceholder()) + return; // We don't have anything to suggest (yet). SuggestedType = nullptr; @@ -13674,6 +13677,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 +15189,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()); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index a1ba9de368db..027b3fe0e782 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2398,10 +2398,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, << Platform->Ident; NamedDecl *ND = dyn_cast<NamedDecl>(D); - if (!ND) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + if (!ND) // We warned about this already, so just return. return; - } AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); @@ -2511,12 +2509,6 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, assert(checkAttributeAtMostNumArgs(S, Attr, 3) && "Invalid number of arguments in an external_source_symbol attribute"); - if (!isa<NamedDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedNamedDecl; - return; - } - StringRef Language; if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) Language = SE->getString(); @@ -5765,18 +5757,21 @@ static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { // Several attributes carry different semantics than the parsing requires, so - // those are opted out of the common handling. + // those are opted out of the common argument checks. // // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. - if (Attr.hasCustomParsing() || - Attr.getKind() == AttributeList::UnknownAttribute) + if (Attr.getKind() == AttributeList::UnknownAttribute) return false; - // Check whether the attribute requires specific language extensions to be // enabled. if (!Attr.diagnoseLangOpts(S)) return true; + // Check whether the attribute appertains to the given subject. + if (!Attr.diagnoseAppertainsTo(S, D)) + return true; + if (Attr.hasCustomParsing()) + return false; if (Attr.getMinArgs() == Attr.getMaxArgs()) { // If there are no optional arguments, then checking for the argument count @@ -5793,10 +5788,6 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, return true; } - // Check whether the attribute appertains to the given subject. - if (!Attr.diagnoseAppertainsTo(S, D)) - return true; - return false; } @@ -6676,6 +6667,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? diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fd3f266c9a08..b543a731641f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index e50f8b206779..4f51cd399c0c 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index bb174521c72c..5a56f7093777 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2129,6 +2129,12 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, IdentifierInfo *II = Name.getAsIdentifierInfo(); SourceLocation NameLoc = NameInfo.getLoc(); + if (II && II->isEditorPlaceholder()) { + // FIXME: When typed placeholders are supported we can create a typed + // placeholder expression node. + return ExprError(); + } + // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // -- an identifier that was declared with a dependent type, diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 616ab05eaec8..d7a6d2e5885e 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -4068,7 +4068,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); // Build variables passed into runtime, necessary for worksharing directives. - ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB; + ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. @@ -4116,8 +4116,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // enclosing region. E.g. in 'distribute parallel for' the bounds obtained // by scheduling 'distribute' have to be passed to the schedule of 'for'. if (isOpenMPLoopBoundSharingDirective(DKind)) { - auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); + // Lower bound variable, initialized with zero. + VarDecl *CombLBDecl = + buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb"); + CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc); + SemaRef.AddInitializerToDecl( + CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), + /*DirectInit*/ false); + + // Upper bound variable, initialized with last iteration number. + VarDecl *CombUBDecl = + buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub"); + CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc); + SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(), + /*DirectInit*/ false); + + ExprResult CombIsUBGreater = SemaRef.BuildBinOp( + CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get()); + ExprResult CombCondOp = + SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(), + LastIteration.get(), CombUB.get()); + CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(), + CombCondOp.get()); + CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get()); + + auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); // We expect to have at least 2 more parameters than the 'parallel' // directive does - the lower and upper bounds of the previous schedule. assert(CD->getNumParams() >= 4 && @@ -4139,7 +4163,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build the iteration variable and its initialization before loop. ExprResult IV; - ExprResult Init; + ExprResult Init, CombInit; { VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); @@ -4150,6 +4174,18 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); Init = SemaRef.ActOnFinishFullExpr(Init.get()); + + if (isOpenMPLoopBoundSharingDirective(DKind)) { + Expr *CombRHS = + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)) + ? CombLB.get() + : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); + CombInit = + SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS); + CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get()); + } } // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. @@ -4160,7 +4196,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); - + ExprResult CombCond; + if (isOpenMPLoopBoundSharingDirective(DKind)) { + CombCond = + SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get()); + } // Loop increment (IV = IV + 1) SourceLocation IncLoc; ExprResult Inc = @@ -4175,7 +4215,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). // Used for directives with static scheduling. - ExprResult NextLB, NextUB; + // In combined construct, add combined version that use CombLB and CombUB + // base variables for the update + ExprResult NextLB, NextUB, CombNextLB, CombNextUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // LB + ST @@ -4198,9 +4240,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get()); if (!NextUB.isUsable()) return 0; + if (isOpenMPLoopBoundSharingDirective(DKind)) { + CombNextLB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get()); + if (!NextLB.isUsable()) + return 0; + // LB = LB + ST + CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(), + CombNextLB.get()); + CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get()); + if (!CombNextLB.isUsable()) + return 0; + // UB + ST + CombNextUB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get()); + if (!CombNextUB.isUsable()) + return 0; + // UB = UB + ST + CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(), + CombNextUB.get()); + CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get()); + if (!CombNextUB.isUsable()) + return 0; + } } - // Create: increment expression for distribute loop when combined in a same + // Create increment expression for distribute loop when combined in a same // directive with for as IV = IV + ST; ensure upper bound expression based // on PrevUB instead of NumIterations - used to implement 'for' when found // in combination with 'distribute', like in 'distribute parallel for' @@ -4346,6 +4411,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.PrevUB = PrevUB.get(); Built.DistInc = DistInc.get(); Built.PrevEUB = PrevEUB.get(); + Built.DistCombinedFields.LB = CombLB.get(); + Built.DistCombinedFields.UB = CombUB.get(); + Built.DistCombinedFields.EUB = CombEUB.get(); + Built.DistCombinedFields.Init = CombInit.get(); + Built.DistCombinedFields.Cond = CombCond.get(); + Built.DistCombinedFields.NLB = CombNextLB.get(); + Built.DistCombinedFields.NUB = CombNextUB.get(); Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get(); // Fill data for doacross depend clauses. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9be1c56f0622..9ffc23b5adba 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1783,6 +1783,7 @@ StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc) { + getCurFunction()->setHasBranchProtectedScope(); ExprResult CollectionExprResult = CheckObjCForCollectionOperand(ForLoc, collection); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f522e76b0673..61b4df40964c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1636,11 +1636,22 @@ private: transformFunctionTypeParam(ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args) { TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); - TypeSourceInfo *NewDI = - Args.getNumLevels() - ? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(), - OldParam->getDeclName()) - : OldDI; + TypeSourceInfo *NewDI; + if (!Args.getNumLevels()) + NewDI = OldDI; + else if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { + // Expand out the one and only element in each inner pack. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0); + NewDI = + SemaRef.SubstType(PackTL.getPatternLoc(), Args, + OldParam->getLocation(), OldParam->getDeclName()); + if (!NewDI) return nullptr; + NewDI = + SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(), + PackTL.getTypePtr()->getNumExpansions()); + } else + NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(), + OldParam->getDeclName()); if (!NewDI) return nullptr; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index edd6edfce9dc..2d44489023ef 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2605,10 +2605,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, == TSK_ExplicitSpecialization) continue; - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && TSK == TSK_ExplicitInstantiationDeclaration) { - // In MSVC mode, explicit instantiation decl of the outer class doesn't - // affect the inner class. + // In MSVC and Windows Itanium mode, explicit instantiation decl of the + // outer class doesn't affect the inner class. continue; } diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index a12fb8cf95a0..3d314a85ff17 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -2578,6 +2578,13 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { D->setPrevUpperBoundVariable(Record.readSubExpr()); D->setDistInc(Record.readSubExpr()); D->setPrevEnsureUpperBound(Record.readSubExpr()); + D->setCombinedLowerBoundVariable(Record.readSubExpr()); + D->setCombinedUpperBoundVariable(Record.readSubExpr()); + D->setCombinedEnsureUpperBound(Record.readSubExpr()); + D->setCombinedInit(Record.readSubExpr()); + D->setCombinedCond(Record.readSubExpr()); + D->setCombinedNextLowerBound(Record.readSubExpr()); + D->setCombinedNextUpperBound(Record.readSubExpr()); } SmallVector<Expr *, 4> Sub; unsigned CollapsedNum = D->getCollapsedNumber(); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 1a2edac65886..90a732e575e2 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -2248,6 +2248,13 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { Record.AddStmt(D->getPrevUpperBoundVariable()); Record.AddStmt(D->getDistInc()); Record.AddStmt(D->getPrevEnsureUpperBound()); + Record.AddStmt(D->getCombinedLowerBoundVariable()); + Record.AddStmt(D->getCombinedUpperBoundVariable()); + Record.AddStmt(D->getCombinedEnsureUpperBound()); + Record.AddStmt(D->getCombinedInit()); + Record.AddStmt(D->getCombinedCond()); + Record.AddStmt(D->getCombinedNextLowerBound()); + Record.AddStmt(D->getCombinedNextUpperBound()); } for (auto I : D->counters()) { Record.AddStmt(I); diff --git a/test/CodeGen/debug-info-vla.c b/test/CodeGen/debug-info-vla.c index 371d1060228e..3b69773207b2 100644 --- a/test/CodeGen/debug-info-vla.c +++ b/test/CodeGen/debug-info-vla.c @@ -4,8 +4,8 @@ void testVLAwithSize(int s) { // CHECK: dbg.declare // CHECK: dbg.declare({{.*}}, metadata ![[VAR:.*]], metadata ![[EXPR:.*]]) -// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+2]] -// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref) +// CHECK: ![[EXPR]] = !DIExpression() +// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+1]] int vla[s]; int i; for (i = 0; i < s; i++) { diff --git a/test/CodeGen/fp-contract-on-asm.c b/test/CodeGen/fp-contract-on-asm.c new file mode 100644 index 000000000000..01a1bd14a062 --- /dev/null +++ b/test/CodeGen/fp-contract-on-asm.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -O3 -triple=aarch64-apple-ios -S -o - %s | FileCheck %s +// REQUIRES: aarch64-registered-target + +float fma_test1(float a, float b, float c) { +#pragma STDC FP_CONTRACT ON +// CHECK-LABEL: fma_test1: +// CHECK: fmadd + float x = a * b + c; + return x; +} + +float fma_test2(float a, float b, float c) { +// CHECK-LABEL: fma_test2: +// CHECK: fmul +// CHECK: fadd + float x = a * b + c; + return x; +} diff --git a/test/CodeGen/thinlto-backend-option.ll b/test/CodeGen/thinlto-backend-option.ll new file mode 100644 index 000000000000..4c7c0ea3efcd --- /dev/null +++ b/test/CodeGen/thinlto-backend-option.ll @@ -0,0 +1,13 @@ +; Test to ensure -backend-options work when invoking the ThinLTO backend path. + +; This test uses a non-existent backend option to test that backend options are +; being parsed. While it's more important that the existing options are parsed +; than that this error is produced, this provides a reliable way to test this +; scenario independent of any particular backend options that may exist now or +; in the future. + +; RUN: %clang -flto=thin -c -o %t.o %s +; RUN: llvm-lto -thinlto -o %t %t.o +; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s + +; CHECK: clang: Unknown command line argument '-nonexistent' diff --git a/test/CodeGenCXX/cxx1z-class-deduction.cpp b/test/CodeGenCXX/cxx1z-class-deduction.cpp new file mode 100644 index 000000000000..0761f2129b51 --- /dev/null +++ b/test/CodeGenCXX/cxx1z-class-deduction.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +template<typename T> struct A { + A(T = 0); + A(void*); +}; + +template<typename T> A(T*) -> A<long>; +A() -> A<int>; + +// CHECK-LABEL: @_Z1fPi( +void f(int *p) { + // CHECK: @_ZN1AIiEC + A a{}; + + // CHECK: @_ZN1AIlEC + A b = p; + + // CHECK: @_ZN1AIxEC + A c = 123LL; +} diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp index 9575a5129e3d..2b86150b52b5 100644 --- a/test/CodeGenCXX/debug-info.cpp +++ b/test/CodeGenCXX/debug-info.cpp @@ -21,6 +21,7 @@ // CHECK: ![[INCTYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "incomplete" // CHECK-SAME: DIFlagFwdDecl +// CHECK: ![[EXPR]] = !DIExpression() template<typename T> struct Identity { typedef T Type; @@ -117,7 +118,6 @@ struct foo { // For some reason function arguments ended up down here // CHECK: ![[F]] = !DILocalVariable(name: "f", arg: 1, scope: ![[FUNC]] // CHECK-SAME: type: ![[FOO]] -// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref) foo func(foo f) { return f; // reference 'f' for now because otherwise we hit another bug } diff --git a/test/CodeGenCXX/ubsan-suppress-checks.cpp b/test/CodeGenCXX/ubsan-suppress-checks.cpp index 8ec94556c136..d0e7b32ef96c 100644 --- a/test/CodeGenCXX/ubsan-suppress-checks.cpp +++ b/test/CodeGenCXX/ubsan-suppress-checks.cpp @@ -2,6 +2,20 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s --check-prefixes=CHECK,NULL // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment,null -DCHECK_LAMBDA | FileCheck %s --check-prefixes=LAMBDA +// CHECK-LABEL: define void @_Z22load_non_null_pointersv +void load_non_null_pointers() { + int var; + var = *&var; + + int arr[1]; + arr[0] = arr[0]; + + char c = "foo"[0]; + + // CHECK-NOT: icmp ne {{.*}}, null, !nosanitize + // CHECK: ret void +} + struct A { int foo; @@ -29,8 +43,7 @@ struct A { }; f(); - // LAMBDA: icmp ne %class.anon* %[[FUNCVAR:.*]], null, !nosanitize - // LAMBDA: %[[LAMBDAINT:[0-9]+]] = ptrtoint %class.anon* %[[FUNCVAR]] to i64, !nosanitize + // LAMBDA: %[[LAMBDAINT:[0-9]+]] = ptrtoint %class.anon* %[[FUNCVAR:.*]] to i64, !nosanitize // LAMBDA: and i64 %[[LAMBDAINT]], 7, !nosanitize // LAMBDA: call void @__ubsan_handle_type_mismatch @@ -127,8 +140,8 @@ struct A { struct B { operator A*() const { return nullptr; } - // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv - static int load_member() { + // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEPS_ + static int load_member(B *bp) { // Check &b before converting it to an A*. // CHECK: call void @__ubsan_handle_type_mismatch // @@ -136,8 +149,7 @@ struct B { // NULL: call void @__ubsan_handle_type_mismatch // // CHECK-NOT: call void @__ubsan_handle_type_mismatch - B b; - return static_cast<A *>(b)->load_member(); + return static_cast<A *>(*bp)->load_member(); // CHECK: ret i32 } }; @@ -210,7 +222,7 @@ void force_irgen() { A::call_through_reference(*a); A::call_through_pointer(a); - B::load_member(); + B::load_member(nullptr); Base *b = new Derived; b->load_member_1(); @@ -218,4 +230,6 @@ void force_irgen() { Derived *d; d->load_member_2(); d->load_member_3(); + + load_non_null_pointers(); } diff --git a/test/CodeGenCXX/unaligned-duplicated-mangle-name.cpp b/test/CodeGenCXX/unaligned-duplicated-mangle-name.cpp new file mode 100644 index 000000000000..a23e6a47ab05 --- /dev/null +++ b/test/CodeGenCXX/unaligned-duplicated-mangle-name.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -fms-extensions -emit-llvm-only %s -verify + +struct A +{ + int x; + void foo() __unaligned; + void foo(); +}; + +void A::foo() __unaligned +{ + this->x++; +} + +void A::foo() // expected-error {{definition with same mangled name as another definition}} + // expected-note@-6 {{previous definition is here}} +{ + this->x++; +} + diff --git a/test/CodeGenCXX/windows-itanium-dllexport.cpp b/test/CodeGenCXX/windows-itanium-dllexport.cpp index 92cca2444287..ff780c777822 100644 --- a/test/CodeGenCXX/windows-itanium-dllexport.cpp +++ b/test/CodeGenCXX/windows-itanium-dllexport.cpp @@ -1,5 +1,10 @@ // RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s +#define JOIN2(x, y) x##y +#define JOIN(x, y) JOIN2(x, y) +#define UNIQ(name) JOIN(name, __LINE__) +#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; } + struct __declspec(dllexport) s { void f() {} }; @@ -28,3 +33,23 @@ template class __declspec(dllexport) c<double>; // CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_ // CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv + +template <class T> +struct outer { + void f() {} + struct inner { + void f() {} + }; +}; + +template class __declspec(dllexport) outer<int>; + +// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv +// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv + +extern template class __declspec(dllimport) outer<char>; +USEMEMFUNC(outer<char>, f) +USEMEMFUNC(outer<char>::inner, f) + +// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv +// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv diff --git a/test/CodeGenCoroutines/coro-alloc.cpp b/test/CodeGenCoroutines/coro-alloc.cpp index f0a600eabe9a..3a65736f6c03 100644 --- a/test/CodeGenCoroutines/coro-alloc.cpp +++ b/test/CodeGenCoroutines/coro-alloc.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \ +// RUN: -Wno-coroutine-missing-unhandled-exception -emit-llvm %s -o - -disable-llvm-passes \ +// RUN: | FileCheck %s namespace std { namespace experimental { @@ -19,8 +21,19 @@ struct coroutine_handle<void> { coroutine_handle(coroutine_handle<PromiseType>) {} }; -} -} +} // end namespace experimental + +struct nothrow_t {}; +constexpr nothrow_t nothrow = {}; + +} // end namespace std + +// Required when get_return_object_on_allocation_failure() is defined by +// the promise. +using SizeT = decltype(sizeof(int)); +void* operator new(SizeT __sz, const std::nothrow_t&) noexcept; +void operator delete(void* __p, const std::nothrow_t&) noexcept; + struct suspend_always { bool await_ready() { return false; } @@ -133,7 +146,7 @@ struct promise_on_alloc_failure_tag {}; template<> struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> { struct promise_type { - int get_return_object() {} + int get_return_object() { return 0; } suspend_always initial_suspend() { return {}; } suspend_always final_suspend() { return {}; } void return_void() {} @@ -145,7 +158,7 @@ struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> { extern "C" int f4(promise_on_alloc_failure_tag) { // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16 // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() - // CHECK: %[[MEM:.+]] = call i8* @_Znwm(i64 %[[SIZE]]) + // CHECK: %[[MEM:.+]] = call i8* @_ZnwmRKSt9nothrow_t(i64 %[[SIZE]], %"struct.std::nothrow_t"* dereferenceable(1) @_ZStL7nothrow) // CHECK: %[[OK:.+]] = icmp ne i8* %[[MEM]], null // CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]] diff --git a/test/CodeGenObjC/empty-collection-literals.m b/test/CodeGenObjC/empty-collection-literals.m index 0f9715f521f3..4b1d7f6ebe46 100644 --- a/test/CodeGenObjC/empty-collection-literals.m +++ b/test/CodeGenObjC/empty-collection-literals.m @@ -41,7 +41,7 @@ void test_empty_dictionary() { // CHECK-WITH-EMPTY-COLLECTIONS-LABEL: define void @test_empty_dictionary // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void - // CHECK-WITH-EMPTY-COLLECTIONS: load {{.*}} @__NSDictionary0__ + // CHECK-WITH-EMPTY-COLLECTIONS: load {{.*}} @__NSDictionary0__{{.*}}!invariant.load // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void // CHECK-WITH-EMPTY-COLLECTIONS: {{call.*objc_retain\(}} // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl index b02ad46224b0..a962d3c75aaf 100644 --- a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl +++ b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl @@ -1,6 +1,5 @@ // RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa -mcpu=fiji -o - %s | FileCheck %s -// CHECK-DAG: ![[NONE:[0-9]+]] = !DIExpression() // CHECK-DAG: ![[LOCAL:[0-9]+]] = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef) // CHECK-DAG: ![[PRIVATE:[0-9]+]] = !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef) @@ -82,7 +81,7 @@ kernel void kernel1( int *FuncVar4 = Tmp1; // CHECK-DAG: ![[FUNCVAR5:[0-9]+]] = !DILocalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}) - // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR5]], metadata ![[NONE]]), !dbg !{{[0-9]+}} + // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR5]], metadata ![[NONE:[0-9]+]]), !dbg !{{[0-9]+}} global int *constant FuncVar5 = KernelArg0; // CHECK-DAG: ![[FUNCVAR6:[0-9]+]] = !DILocalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}) // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR6]], metadata ![[NONE]]), !dbg !{{[0-9]+}} diff --git a/test/CodeGenOpenCL/byval.cl b/test/CodeGenOpenCL/byval.cl new file mode 100644 index 000000000000..1a8105c5207f --- /dev/null +++ b/test/CodeGenOpenCL/byval.cl @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn---amdgizcl %s | FileCheck %s -check-prefix=AMDGIZ + +struct A { + int x[100]; +}; + +int f(struct A a); + +int g() { + struct A a; + // CHECK: call i32 @f(%struct.A* byval{{.*}}%a) + // AMDGIZ: call i32 @f(%struct.A addrspace(5)* byval{{.*}}%a) + return f(a); +} + +// CHECK: declare i32 @f(%struct.A* byval{{.*}}) +// AMDGIZ: declare i32 @f(%struct.A addrspace(5)* byval{{.*}}) diff --git a/test/CodeGenOpenCL/lifetime.cl b/test/CodeGenOpenCL/lifetime.cl new file mode 100644 index 000000000000..430e0582aeda --- /dev/null +++ b/test/CodeGenOpenCL/lifetime.cl @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn---amdgizcl %s | FileCheck %s -check-prefix=AMDGIZ + +void use(char *a); + +__attribute__((always_inline)) void helper_no_markers() { + char a; + use(&a); +} + +void lifetime_test() { +// CHECK: @llvm.lifetime.start.p0i +// AMDGIZ: @llvm.lifetime.start.p5i + helper_no_markers(); +} diff --git a/test/CoverageMapping/pr32679.cpp b/test/CoverageMapping/pr32679.cpp new file mode 100644 index 000000000000..eac3afb6efb6 --- /dev/null +++ b/test/CoverageMapping/pr32679.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -cc1 -triple i686-pc-windows-msvc19.0.0 -emit-obj -fprofile-instrument=clang -std=c++14 -fdelayed-template-parsing -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name pr32679.cpp -o - %s | FileCheck %s -check-prefix=MSABI -implicit-check-not=f2 +// RUN: %clang_cc1 -cc1 -triple %itanium_abi_triple -emit-obj -fprofile-instrument=clang -std=c++14 -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name pr32679.cpp -o - %s | FileCheck %s -check-prefix=ITANIUM -implicit-check-not=f2 + +template <typename T, int S1> +struct CreateSpecialization; + +template <typename T> +struct CreateSpecialization<T, 0> { + static constexpr T f1() { return 0; } + static constexpr T f2() { return 0; } +}; + +int main() { + CreateSpecialization<int, 0>::f1(); + + // Don't emit coverage mapping info for functions in dependent contexts. + // + // E.g we never fully instantiate CreateSpecialization<T, 0>::f2(), so there + // should be no mapping for it. + + return 0; +} + +// MSABI: main: +// MSABI-NEXT: File 0, [[@LINE-12]]:12 -> [[@LINE-3]]:2 = #0 +// MSABI-NEXT: ?f1@?$CreateSpecialization@H$0A@@@SAHXZ: +// MSABI-NEXT: File 0, [[@LINE-18]]:27 -> [[@LINE-18]]:40 = #0 + +// ITANIUM: main: +// ITANIUM-NEXT: File 0, [[@LINE-17]]:12 -> [[@LINE-8]]:2 = #0 +// ITANIUM-NEXT: _ZN20CreateSpecializationIiLi0EE2f1Ev: +// ITANIUM-NEXT: File 0, [[@LINE-23]]:27 -> [[@LINE-23]]:40 = #0 diff --git a/test/Driver/arm-default-build-attributes.s b/test/Driver/arm-default-build-attributes.s new file mode 100644 index 000000000000..b651fbb6c9f8 --- /dev/null +++ b/test/Driver/arm-default-build-attributes.s @@ -0,0 +1,20 @@ +// Enabled by default for assembly +// RUN: %clang -target armv7--none-eabi -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-ENABLED + +// Can be forced on or off for assembly. +// RUN: %clang -target armv7--none-eabi -### %s 2>&1 -mno-default-build-attributes \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED +// RUN: %clang -target armv7--none-eabi -### %s 2>&1 -mdefault-build-attributes \ +// RUN: | FileCheck %s -check-prefix CHECK-ENABLED + +// Option ignored C/C++ (since we always emit hardware and ABI build attributes +// during codegen). +// RUN: %clang -target armv7--none-eabi -### -x c %s -mdefault-build-attributes -verify 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED +// RUN: %clang -target armv7--none-eabi -### -x c++ %s -mdefault-build-attributes -verify 2>&1 \ +// RUN: | FileCheck %s -check-prefix CHECK-DISABLED + +// CHECK-DISABLED-NOT: "-arm-add-build-attributes" +// CHECK-ENABLED: "-arm-add-build-attributes" +// expected-warning {{argument unused during compilation: '-mno-default-build-attributes'}} diff --git a/test/Driver/avr-mmcu.c b/test/Driver/avr-mmcu.c new file mode 100644 index 000000000000..0d92ceb875fe --- /dev/null +++ b/test/Driver/avr-mmcu.c @@ -0,0 +1,5 @@ +// A test for the propagation of the -mmcu option to -cc1 and -cc1as + +// RUN: %clang -### -target avr -no-canonical-prefixes -mmcu=atmega328p -save-temps %s 2>&1 | FileCheck %s +// CHECK: clang{{.*}} "-cc1" {{.*}} "-target-cpu" "atmega328p" +// CHECK: clang{{.*}} "-cc1as" {{.*}} "-target-cpu" "atmega328p" diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index c425e21dd7fb..ddfb3cbdc4ac 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -296,11 +296,14 @@ // NOSTRICT: "-relaxed-aliasing" // We recognize -f[no-]delayed-template-parsing. +// /Zc:twoPhase[-] has the opposite meaning. // RUN: %clang_cl -c -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDDEFAULT %s // DELAYEDDEFAULT: "-fdelayed-template-parsing" // RUN: %clang_cl -c -fdelayed-template-parsing -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDON %s +// RUN: %clang_cl -c /Zc:twoPhase- -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDON %s // DELAYEDON: "-fdelayed-template-parsing" // RUN: %clang_cl -c -fno-delayed-template-parsing -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDOFF %s +// RUN: %clang_cl -c /Zc:twoPhase -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDOFF %s // DELAYEDOFF-NOT: "-fdelayed-template-parsing" // For some warning ids, we can map from MSVC warning to Clang warning. diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index 15c1eacb9617..c54c618df112 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -494,3 +494,8 @@ // RUN: %clang -### -S -fdebug-info-for-profiling -fno-debug-info-for-profiling %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-DEBUG %s // CHECK-PROFILE-DEBUG: -fdebug-info-for-profiling // CHECK-NO-PROFILE-DEBUG-NOT: -fdebug-info-for-profiling + +// RUN: %clang -### -S -fallow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-ALLOW-PLACEHOLDERS %s +// RUN: %clang -### -S -fno-allow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-NO-ALLOW-PLACEHOLDERS %s +// CHECK-ALLOW-PLACEHOLDERS: -fallow-editor-placeholders +// CHECK-NO-ALLOW-PLACEHOLDERS-NOT: -fallow-editor-placeholders diff --git a/test/Driver/fopenmp.c b/test/Driver/fopenmp.c index ea4284ef6e1b..ac0f1b44cba3 100644 --- a/test/Driver/fopenmp.c +++ b/test/Driver/fopenmp.c @@ -18,7 +18,7 @@ // CHECK-CC1-NO-OPENMP-NOT: "-fopenmp" // // RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP -// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-RT // RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 // // RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP @@ -26,21 +26,25 @@ // RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 // // RUN: %clang -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP -// RUN: %clang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP +// RUN: %clang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT // RUN: %clang -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 // // RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP // RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP // RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 // -// RUN: %clang -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP -// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP -// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 +// RUN: %clang -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP +// RUN: %clang -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT +// RUN: %clang -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 // // RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP // RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP // RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 // +// RUN: %clang -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP +// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT +// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 +// // RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP // RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP // RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 @@ -50,6 +54,8 @@ // // CHECK-LD-GOMP: "{{.*}}ld{{(.exe)?}}" // CHECK-LD-GOMP: "-lgomp" +// CHECK-LD-GOMP-RT: "-lrt" +// CHECK-LD-GOMP-NO-RT-NOT: "-lrt" // // CHECK-LD-IOMP5: "{{.*}}ld{{(.exe)?}}" // CHECK-LD-IOMP5: "-liomp5" diff --git a/test/Driver/fsanitize-coverage.c b/test/Driver/fsanitize-coverage.c index b04e71e90c92..6fa1daa4a63e 100644 --- a/test/Driver/fsanitize-coverage.c +++ b/test/Driver/fsanitize-coverage.c @@ -23,14 +23,7 @@ // CHECK-SANITIZE-COVERAGE-FUNC_INDIR: fsanitize-coverage-indirect-calls // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1 -// CHECK-SANITIZE-COVERAGE-1: warning: argument '-fsanitize-coverage=1' is deprecated, use '-fsanitize-coverage=func' instead -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=2 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-2 -// CHECK-SANITIZE-COVERAGE-2: warning: argument '-fsanitize-coverage=2' is deprecated, use '-fsanitize-coverage=bb' instead -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=3 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-3 -// CHECK-SANITIZE-COVERAGE-3: warning: argument '-fsanitize-coverage=3' is deprecated, use '-fsanitize-coverage=edge' instead -// -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-5 -// CHECK-SANITIZE-COVERAGE-5: error: unsupported argument '5' to option 'fsanitize-coverage=' +// CHECK-SANITIZE-COVERAGE-1: warning: argument '-fsanitize-coverage=1' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead // RUN: %clang -target x86_64-linux-gnu -fsanitize=thread -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-UNUSED // RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC @@ -40,17 +33,15 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-SAN-DISABLED // CHECK-SANITIZE-COVERAGE-SAN-DISABLED-NOT: argument unused -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-bb,trace-pc,trace-cmp,8bit-counters,trace-div,trace-gep %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc,trace-cmp,trace-div,trace-gep %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-type=3 // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-indirect-calls -// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-bb // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-cmp // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-div // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-gep -// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-8bit-counters // CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-pc -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-bb,trace-cmp -fno-sanitize-coverage=edge,indirect-calls,trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-cmp -fno-sanitize-coverage=edge,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK // CHECK-MASK: -fsanitize-coverage-type=1 // CHECK-MASK: -fsanitize-coverage-trace-cmp // CHECK-MASK-NOT: -fsanitize-coverage- @@ -61,8 +52,10 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func -fsanitize-coverage=edge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INCOMPATIBLE // CHECK-INCOMPATIBLE: error: invalid argument '-fsanitize-coverage=func' not allowed with '-fsanitize-coverage=edge' -// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-TYPE -// CHECK-MISSING-TYPE: error: invalid argument '-fsanitize-coverage=8bit-counters' only allowed with '-fsanitize-coverage=(func|bb|edge)' +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-8BIT +// CHECK-8BIT: warning: argument '-fsanitize-coverage=8bit-counters' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE-BB +// CHECK-TRACE-BB: warning: argument '-fsanitize-coverage=trace-bb' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead // RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE // RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=edge,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE diff --git a/test/Driver/linux-as.c b/test/Driver/linux-as.c index a07abc17e52f..c5cb1cd600b0 100644 --- a/test/Driver/linux-as.c +++ b/test/Driver/linux-as.c @@ -100,6 +100,33 @@ // RUN: | FileCheck -check-prefix=CHECK-ARM-HARDFP %s // CHECK-ARM-HARDFP: as{{(.exe)?}}" "-mfloat-abi=hard" // +// RUN: %clang -target aarch64-linux-gnu -mcpu=cortex-a53 -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-MCPU %s +// CHECK-ARM64-MCPU: as{{(.exe)?}}" "-mcpu=cortex-a53" +// +// RUN: %clang -target aarch64-linux-gnu -march=armv8-a -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-MARCH %s +// CHECK-ARM64-MARCH: as{{(.exe)?}}" "-march=armv8-a" +// +// RUN: %clang -target aarch64-linux-gnu -mcpu=cortex-a53 -march=armv8-a -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-ALL %s +// CHECK-ARM64-ALL: as{{(.exe)?}}" "-march=armv8-a" "-mcpu=cortex-a53" +// +// RUN: %clang -target aarch64_be-linux-gnu -mcpu=cortex-a53 -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-MCPU %s +// +// RUN: %clang -target aarch64_be-linux-gnu -march=armv8-a -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-MARCH %s +// +// RUN: %clang -target aarch64_be-linux-gnu -mcpu=cortex-a53 -march=armv8-a -### \ +// RUN: -no-integrated-as -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ARM64-ALL %s +// // RUN: %clang -target ppc-linux -mcpu=invalid-cpu -### \ // RUN: -no-integrated-as -c %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-PPC-NO-MCPU %s diff --git a/test/Driver/modules-ts.cpp b/test/Driver/modules-ts.cpp index 0fdc61b6f9ce..fd3391479eea 100644 --- a/test/Driver/modules-ts.cpp +++ b/test/Driver/modules-ts.cpp @@ -4,7 +4,7 @@ // // CHECK-PRECOMPILE: -cc1 {{.*}} -emit-module-interface // CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm -// CHECK-PRECOMPILE-SAME: -x c++-module +// CHECK-PRECOMPILE-SAME: -x c++ // CHECK-PRECOMPILE-SAME: modules-ts.cpp // Check compiling a .pcm file to a .o file. diff --git a/test/FixIt/fixit-pragma-attribute.c b/test/FixIt/fixit-pragma-attribute.c new file mode 100644 index 000000000000..f166eb2978e3 --- /dev/null +++ b/test/FixIt/fixit-pragma-attribute.c @@ -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)" diff --git a/test/FixIt/fixit-pragma-attribute.cpp b/test/FixIt/fixit-pragma-attribute.cpp new file mode 100644 index 000000000000..8e3f6d9392f0 --- /dev/null +++ b/test/FixIt/fixit-pragma-attribute.cpp @@ -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 diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp index 356d4a08de3a..5d4a1be45683 100644 --- a/test/Index/Core/index-source.cpp +++ b/test/Index/Core/index-source.cpp @@ -50,6 +50,12 @@ public: // CHECK-NEXT: RelChild | TemplCls | c:@ST>1#T@TemplCls }; +template<> +class TemplCls<double> { +// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | TemplCls | c:@S@TemplCls>#d | <no-cgname> | Def,RelSpecialization | rel: 1 +// CHECK: RelSpecialization | TemplCls | c:@ST>1#T@TemplCls +}; + TemplCls<int> gtv(0); // CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | TemplCls | c:@ST>1#T@TemplCls | <no-cgname> | Ref,RelCont | rel: 1 @@ -91,3 +97,17 @@ int gvi = tmplVar<int>; // CHECK: [[@LINE+2]]:5 | variable/C | gvf | c:@gvf | _gvf | Def | rel: 0 // CHECK: [[@LINE+1]]:11 | variable(Gen)/C++ | tmplVar | c:index-source.cpp@VT>1#T@tmplVar | __ZL7tmplVar | Ref,Read,RelCont | rel: 1 int gvf = tmplVar<float>; + +template<typename A, typename B> +class PartialSpecilizationClass { }; +// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass | <no-cgname> | Def | rel: 0 + +template<typename B> +class PartialSpecilizationClass<int, B *> { }; +// CHECK: [[@LINE-1]]:7 | class(Gen,TPS)/C++ | PartialSpecilizationClass | c:@SP>1#T@PartialSpecilizationClass>#I#*t0.0 | <no-cgname> | Def,RelSpecialization | rel: 1 +// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass + +template<> +class PartialSpecilizationClass<int, int> { }; +// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#I#I | <no-cgname> | Def,RelSpecialization | rel: 1 +// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass diff --git a/test/Lexer/cxx1z-trigraphs.cpp b/test/Lexer/cxx1z-trigraphs.cpp index 0ea2adbe1e03..08c45e51f833 100644 --- a/test/Lexer/cxx1z-trigraphs.cpp +++ b/test/Lexer/cxx1z-trigraphs.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -std=c++1z %s -verify -// RUN: %clang_cc1 -std=c++1z %s -ftrigraphs -fsyntax-only +// RUN: %clang_cc1 -std=c++1z %s -ftrigraphs -fsyntax-only 2>&1 | FileCheck --check-prefix=TRIGRAPHS %s ??= define foo ; // expected-error {{}} expected-warning {{trigraph ignored}} @@ -7,3 +7,8 @@ static_assert("??="[0] == '#', ""); // expected-error {{failed}} expected-warnin // ??/ error here; // expected-error {{}} + +// Note, there is intentionally trailing whitespace two lines below. +// TRIGRAPHS: :[[@LINE+1]]:{{.*}} backslash and newline separated by space +// ??/ +error here; // expected-error {{}} diff --git a/test/Lexer/newline-nul.c b/test/Lexer/newline-nul.c new file mode 100644 index 0000000000000000000000000000000000000000..dd1b4199d422c97c0e146d3e288b216a8527be25 GIT binary patch literal 332 zcmY+9F>Av>423)US3EEoU6ZwY*A9i!B@nJ>*%4eNqdVI*!T-H-(o(vdB=o(fcWsN; zx0fdzVhS>xV?3gH#v!Ab$+%yus%`O3m@;)JifAEUz&!#I3n8i$mMIig!4fihO-UDr zKUQaCO5PO0!sWt(u-lDBqiLj^Sq5}$6bsMvSk=4n5vS^*_9p8m?V{mKDHB{sU!$Yc zHA^trwb!d3NQjqU!50P|M2)&_`(w#WZ6~#OpgAP=Y%IZ6=tvfd+O}2o9lO0gNXPw8 S`FHr&>`vT%rBi{&b&qcfRdb{O literal 0 HcmV?d00001 diff --git a/test/Misc/ast-print-out-of-line-func.cpp b/test/Misc/ast-print-out-of-line-func.cpp index 7c4f7ae7f813..7d42f1f4037f 100644 --- a/test/Misc/ast-print-out-of-line-func.cpp +++ b/test/Misc/ast-print-out-of-line-func.cpp @@ -52,3 +52,44 @@ void Wrapper::Inner::staticMember() { } // CHECK: void Wrapper::Inner::staticMember() } + +template<int x, typename T> +class TemplateRecord { + void function(); + template<typename U> void functionTemplate(T, U); +}; + +template<int x, typename T> +void TemplateRecord<x, T>::function() { } +// CHECK: template <int x, typename T> void TemplateRecord<x, T>::function() + +template<int x, typename T> +template<typename U> +void TemplateRecord<x, T>::functionTemplate(T, U) { } +// CHECK: template <int x, typename T> template <typename U> void TemplateRecord<x, T>::functionTemplate(T, U) + +template<> +class TemplateRecord<0, int> { + void function(); + template<typename U> void functionTemplate(int, U); +}; + +void TemplateRecord<0, int>::function() { } +// CHECK: void TemplateRecord<0, int>::function() + +template<typename U> +void TemplateRecord<0, int>::functionTemplate(int, U) { } +// CHECK: template <typename U> void TemplateRecord<0, int>::functionTemplate(int, U) + +template<typename T> +struct OuterTemplateRecord { + template<typename U> + struct Inner { + void function(); + }; +}; + +template<typename T> +template<typename U> +void OuterTemplateRecord<T>::Inner<U>::function() { } +// CHECK: template <typename T> template <typename U> void OuterTemplateRecord<T>::Inner<U>::function() diff --git a/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp new file mode 100644 index 000000000000..b7741343ad45 --- /dev/null +++ b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp @@ -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 diff --git a/test/Misc/pragma-attribute-cxx.cpp b/test/Misc/pragma-attribute-cxx.cpp new file mode 100644 index 000000000000..c241c4e4bdba --- /dev/null +++ b/test/Misc/pragma-attribute-cxx.cpp @@ -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 diff --git a/test/Misc/pragma-attribute-objc-subject-match-rules.m b/test/Misc/pragma-attribute-objc-subject-match-rules.m new file mode 100644 index 000000000000..09ab5e1f33a0 --- /dev/null +++ b/test/Misc/pragma-attribute-objc-subject-match-rules.m @@ -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 diff --git a/test/Misc/pragma-attribute-objc.m b/test/Misc/pragma-attribute-objc.m new file mode 100644 index 000000000000..541cfa9ad3bc --- /dev/null +++ b/test/Misc/pragma-attribute-objc.m @@ -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 diff --git a/test/Misc/pragma-attribute-strict-subjects.c b/test/Misc/pragma-attribute-strict-subjects.c new file mode 100644 index 000000000000..ecd551bee6c7 --- /dev/null +++ b/test/Misc/pragma-attribute-strict-subjects.c @@ -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 diff --git a/test/Misc/pragma-attribute-supported-attributes-list.test b/test/Misc/pragma-attribute-supported-attributes-list.test new file mode 100644 index 000000000000..f6a7ce2869ac --- /dev/null +++ b/test/Misc/pragma-attribute-supported-attributes-list.test @@ -0,0 +1,64 @@ +// 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 59 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: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) +// 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: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) +// 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) diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 75436706200c..2ec8005ce509 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -526,138 +526,51 @@ S3 s3; // Interesting cases that should not cause errors. struct S should not error // while struct T should error at the access specifier mismatch at the end. namespace AllDecls { +#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \ + typedef int INT; \ + struct NAME { \ + public: \ + private: \ + protected: \ + static_assert(1 == 1, "Message"); \ + static_assert(2 == 2); \ + \ + int x; \ + double y; \ + \ + INT z; \ + \ + unsigned a : 1; \ + unsigned b : 2 * 2 + 5 / 2; \ + \ + mutable int c = sizeof(x + y); \ + \ + void method() {} \ + static void static_method() {} \ + virtual void virtual_method() {} \ + virtual void pure_virtual_method() = 0; \ + inline void inline_method() {} \ + void volatile_method() volatile {} \ + void const_method() const {} \ + \ + typedef int typedef_int; \ + using using_int = int; \ + \ + ACCESS: \ + }; + #if defined(FIRST) -typedef int INT; -struct S { - public: - private: - protected: - - static_assert(1 == 1, "Message"); - static_assert(2 == 2); - - int x; - double y; - - INT z; - - unsigned a : 1; - unsigned b : 2*2 + 5/2; - - mutable int c = sizeof(x + y); - - void method() {} - static void static_method() {} - virtual void virtual_method() {} - virtual void pure_virtual_method() = 0; - inline void inline_method() {} - void volatile_method() volatile {} - void const_method() const {} - - typedef int typedef_int; - using using_int = int; -}; +CREATE_ALL_DECL_STRUCT(S, public) #elif defined(SECOND) -typedef int INT; -struct S { - public: - private: - protected: - - static_assert(1 == 1, "Message"); - static_assert(2 == 2); - - int x; - double y; - - INT z; - - unsigned a : 1; - unsigned b : 2 * 2 + 5 / 2; - - mutable int c = sizeof(x + y); - - void method() {} - static void static_method() {} - virtual void virtual_method() {} - virtual void pure_virtual_method() = 0; - inline void inline_method() {} - void volatile_method() volatile {} - void const_method() const {} - - typedef int typedef_int; - using using_int = int; -}; +CREATE_ALL_DECL_STRUCT(S, public) #else S *s; #endif #if defined(FIRST) -typedef int INT; -struct T { - public: - private: - protected: - - static_assert(1 == 1, "Message"); - static_assert(2 == 2); - - int x; - double y; - - INT z; - - unsigned a : 1; - unsigned b : 2 * 2 + 5 / 2; - - mutable int c = sizeof(x + y); - - void method() {} - static void static_method() {} - virtual void virtual_method() {} - virtual void pure_virtual_method() = 0; - inline void inline_method() {} - void volatile_method() volatile {} - void const_method() const {} - - typedef int typedef_int; - using using_int = int; - - private: -}; +CREATE_ALL_DECL_STRUCT(T, private) #elif defined(SECOND) -typedef int INT; -struct T { - public: - private: - protected: - - static_assert(1 == 1, "Message"); - static_assert(2 == 2); - - int x; - double y; - - INT z; - - unsigned a : 1; - unsigned b : 2 * 2 + 5 / 2; - - mutable int c = sizeof(x + y); - - void method() {} - static void static_method() {} - virtual void virtual_method() {} - virtual void pure_virtual_method() = 0; - inline void inline_method() {} - void volatile_method() volatile {} - void const_method() const {} - - typedef int typedef_int; - using using_int = int; - - public: -}; +CREATE_ALL_DECL_STRUCT(T, public) #else T *t; // expected-error@second.h:* {{'AllDecls::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}} @@ -944,6 +857,36 @@ T t; #endif } // namespace StructWithForwardDeclarationNoDefinition +namespace LateParsedDefaultArgument { +#if defined(FIRST) +template <typename T> +struct S { + struct R { + void foo(T x = 0) {} + }; +}; +#elif defined(SECOND) +#else +void run() { + S<int>::R().foo(); +} +#endif +} + +namespace LateParsedDefaultArgument { +#if defined(FIRST) +template <typename alpha> struct Bravo { + void charlie(bool delta = false) {} +}; +typedef Bravo<char> echo; +echo foxtrot; + +Bravo<char> golf; +#elif defined(SECOND) +#else +#endif +} + // Keep macros contained to one file. #ifdef FIRST #undef FIRST diff --git a/test/Modules/umbrella-header-include-builtin.mm b/test/Modules/umbrella-header-include-builtin.mm index 75b9c905ff00..da21779683cf 100644 --- a/test/Modules/umbrella-header-include-builtin.mm +++ b/test/Modules/umbrella-header-include-builtin.mm @@ -4,3 +4,11 @@ // RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -F%S/Inputs/libc-libcxx/sysroot/Frameworks -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s #include <A/A.h> + +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "module NonExistent1 { umbrella \"NonExistent\" }" > %t/modules.modulemap +// RUN: echo "" > %t/A.h +// RUN: echo "#include \"A.h\" int i;" > %t/T.cxx +// RUN: %clang -I %t -fmodules -fsyntax-only %t/T.cxx +// expected-warning {{ umbrella directory }} diff --git a/test/OpenMP/distribute_parallel_for_ast_print.cpp b/test/OpenMP/distribute_parallel_for_ast_print.cpp index 874345b67327..54a3649e578b 100644 --- a/test/OpenMP/distribute_parallel_for_ast_print.cpp +++ b/test/OpenMP/distribute_parallel_for_ast_print.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -verify -std=c++11 -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s // RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s // expected-no-diagnostics @@ -109,6 +109,41 @@ T tmain(T argc) { return T(); } +void foo(int argc, char **argv) { + int b, c, d, e, f, h; + static int a; +// CHECK: static int a; + static float g; +#pragma omp threadprivate(g) + [&]() { +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) + // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) + for (int i = 0; i < 2; ++i) +// CHECK: for (int i = 0; i < 2; ++i) + [&]() { + a = 2; + // CHECK: a = 2; + }(); + + }(); + [&]() { +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) + [&]() { + a++; + }(); + // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b) + // CHECK-NEXT: for (int i = 0; i < 10; ++i) + // CHECK-NEXT: for (int j = 0; j < 10; ++j) + // CHECK: a++; + }(); +} + int main(int argc, char **argv) { int b = argc, c, d, e, f, h; static int a; diff --git a/test/OpenMP/distribute_parallel_for_messages.cpp b/test/OpenMP/distribute_parallel_for_messages.cpp new file mode 100644 index 000000000000..35a61df39e40 --- /dev/null +++ b/test/OpenMP/distribute_parallel_for_messages.cpp @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +#pragma omp distribute parallel for // expected-error {{unexpected OpenMP directive '#pragma omp distribute parallel for'}} + +int main(int argc, char **argv) { +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for { // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for ( // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for[ // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for] // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for) // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for } // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for unknown() // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + for (int i = 0; i < argc; ++i) + foo(); +L1: + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) { + goto L1; // expected-error {{use of undeclared label 'L1'}} + argc++; + } + + for (int i = 0; i < 10; ++i) { + switch (argc) { + case (0): +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) { + foo(); + break; // expected-error {{'break' statement cannot be used in OpenMP for loop}} + continue; + } + default: + break; + } + } +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for default(none) + for (int i = 0; i < 10; ++i) + ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}} + + goto L2; // expected-error {{use of undeclared label 'L2'}} +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) + L2: + foo(); +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int i = 0; i < argc; ++i) { + return 1; // expected-error {{cannot return from OpenMP region}} + } + + [[]] // expected-error {{an attribute list cannot appear here}} +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for + for (int n = 0; n < 100; ++n) { + } + + return 0; +} + +void test_ordered() { +#pragma omp target +#pragma omp teams +#pragma omp distribute parallel for collapse(2) collapse(3) // expected-error {{directive '#pragma omp distribute parallel for' cannot contain more than one 'collapse' clause}} + for (int i = 0; i < 16; ++i) + for (int j = 0; j < 16; ++j) + ; +} + diff --git a/test/Parser/editor-placeholder-recovery.cpp b/test/Parser/editor-placeholder-recovery.cpp new file mode 100644 index 000000000000..48c290ee9a14 --- /dev/null +++ b/test/Parser/editor-placeholder-recovery.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fallow-editor-placeholders -DSUPPRESS -verify %s + +struct Struct { +public: + void method(Struct &x); +}; + +struct <#struct name#> { + int <#field-name#>; +#ifndef SUPPRESS + // expected-error@-3 {{editor placeholder in source file}} + // expected-error@-3 {{editor placeholder in source file}} +#endif +}; + +typename <#typename#>::<#name#>; +decltype(<#expression#>) foobar; +typedef <#type#> <#name#>; +#ifndef SUPPRESS + // expected-error@-4 2 {{editor placeholder in source file}} + // expected-error@-4 {{editor placeholder in source file}} + // expected-error@-4 2 {{editor placeholder in source file}} +#endif + +namespace <#identifier#> { + <#declarations#> +#ifndef SUPPRESS + // expected-error@-3 {{editor placeholder in source file}} + // expected-error@-3 {{editor placeholder in source file}} +#endif + +} + +using <#qualifier#>::<#name#>; +#ifndef SUPPRESS + // expected-error@-2 2 {{editor placeholder in source file}} +#endif + +void avoidPlaceholderErrors(Struct &obj) { + static_cast< <#type#> >(<#expression#>); + while (<#condition#>) { + <#statements#> + } + obj.method(<#Struct &x#>); +#ifndef SUPPRESS + // expected-error@-6 2 {{editor placeholder in source file}} + // expected-error@-6 {{editor placeholder in source file}} + // expected-error@-6 {{editor placeholder in source file}} + // expected-error@-5 {{editor placeholder in source file}} +#endif + switch (<#expression#>) { + case <#constant#>: + <#statements#> +#ifndef SUPPRESS + // expected-error@-4 {{editor placeholder in source file}} + // expected-error@-4 {{editor placeholder in source file}} + // expected-error@-4 {{editor placeholder in source file}} +#endif + break; + + default: + break; + } +} + +void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}} +#ifndef SUPPRESS + // expected-error@-2 {{editor placeholder in source file}} +#endif +} diff --git a/test/Parser/placeholder-recovery.m b/test/Parser/placeholder-recovery.m index b43b0e4a57cb..4f22ea770da9 100644 --- a/test/Parser/placeholder-recovery.m +++ b/test/Parser/placeholder-recovery.m @@ -1,11 +1,14 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +@protocol NSObject +@end + +@protocol <#protocol name#> <NSObject> // expected-error {{editor placeholder in source file}} +// expected-note@-1 {{protocol started here}} + // FIXME: We could do much better with this, if we recognized // placeholders somehow. However, we're content with not generating // bogus 'archaic' warnings with bad location info. -@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \ -// expected-error 2{{expected identifier}} \ -// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}} -<#methods#> +<#methods#> // expected-error {{editor placeholder in source file}} -@end +@end // expected-error {{prefix attribute must be followed by an interface or protocol}} expected-error {{missing '@end'}} diff --git a/test/Parser/pragma-attribute-declspec.cpp b/test/Parser/pragma-attribute-declspec.cpp new file mode 100644 index 000000000000..28785ba90063 --- /dev/null +++ b/test/Parser/pragma-attribute-declspec.cpp @@ -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 diff --git a/test/Parser/pragma-attribute.cpp b/test/Parser/pragma-attribute.cpp new file mode 100644 index 000000000000..f0ebca2c5313 --- /dev/null +++ b/test/Parser/pragma-attribute.cpp @@ -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__((objc_bridge_related)), apply_to=function) +// expected-error@-1 {{attribute 'objc_bridge_related' is not supported by '#pragma clang attribute'}} +#pragma clang attribute push (__attribute__((objc_bridge_related(1))), apply_to=function) // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}} + +#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}} diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index d48d476d7009..7548fbaae2eb 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -2378,6 +2378,9 @@ // ARM-NETBSD:#define __arm__ 1 // RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-eabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s // ARM-NONE-EABI: #define __ELF__ 1 // No MachO targets use the full EABI, even if AAPCS is used. diff --git a/test/Sema/alloc-align-attr.c b/test/Sema/alloc-align-attr.c index bf8591625dab..ae514343aff4 100644 --- a/test/Sema/alloc-align-attr.c +++ b/test/Sema/alloc-align-attr.c @@ -13,7 +13,7 @@ void *test_incorrect_param_type(float a) __attribute__((alloc_align(1))); // exp void *test_bad_param_type(void) __attribute((alloc_align(1.1))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}} // argument count -void *test_no_fn_proto() __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}} -void *test_no_fn_proto() __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}} -void *test_no_fn_proto() __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}} +void *test_no_fn_proto(int x, int y) __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}} +void *test_no_fn_proto(int x, int y) __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}} +void *test_no_fn_proto(int x, int y) __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}} diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c index a4b40ff9e0c3..c4133e3b9bc6 100644 --- a/test/Sema/attr-availability.c +++ b/test/Sema/attr-availability.c @@ -74,7 +74,7 @@ extern int x; void f8() { int (^b)(int); - b = ^ (int i) __attribute__((availability(macosx,introduced=10.2))) { return 1; }; // expected-warning {{'availability' attribute ignored}} + b = ^ (int i) __attribute__((availability(macosx,introduced=10.2))) { return 1; }; // expected-warning {{'availability' attribute only applies to named declarations}} } extern int x2 __attribute__((availability(macosx,introduced=10.2))); // expected-note {{previous attribute is here}} diff --git a/test/Sema/attr-selectany.c b/test/Sema/attr-selectany.c index 01cca7d7cfa5..9fa2fcade539 100644 --- a/test/Sema/attr-selectany.c +++ b/test/Sema/attr-selectany.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fms-compatibility -fms-extensions -verify %s +// RUN: %clang_cc1 -triple x86_64-win32 -fdeclspec -verify %s +// RUN: %clang_cc1 -triple x86_64-mingw32 -verify %s extern __declspec(selectany) const int x1 = 1; // no warning, const means we need extern in C++ diff --git a/test/Sema/pragma-attribute-strict-subjects.c b/test/Sema/pragma-attribute-strict-subjects.c new file mode 100644 index 000000000000..a84e2bde38d5 --- /dev/null +++ b/test/Sema/pragma-attribute-strict-subjects.c @@ -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 diff --git a/test/Sema/pragma-attribute.c b/test/Sema/pragma-attribute.c new file mode 100644 index 000000000000..d321f2ce4be7 --- /dev/null +++ b/test/Sema/pragma-attribute.c @@ -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(); diff --git a/test/SemaCXX/attr-selectany.cpp b/test/SemaCXX/attr-selectany.cpp index 9dc14b3c3818..62fca09ab364 100644 --- a/test/SemaCXX/attr-selectany.cpp +++ b/test/SemaCXX/attr-selectany.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64-win32 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s // MSVC produces similar diagnostics. __declspec(selectany) void foo() { } // expected-error{{'selectany' can only be applied to data items with external linkage}} diff --git a/test/SemaCXX/coroutine-unhandled_exception-warning.cpp b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp index f98e00d1a709..d7f6066109a5 100644 --- a/test/SemaCXX/coroutine-unhandled_exception-warning.cpp +++ b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp @@ -1,4 +1,11 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wno-unreachable-code -Wno-unused-value +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \ +// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \ +// RUN: -fblocks -Wno-unreachable-code -Wno-unused-value + +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \ +// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \ +// RUN: -fblocks -Wno-unreachable-code -Wno-unused-value \ +// RUN: -DDISABLE_WARNING -Wno-coroutine-missing-unhandled-exception #if __has_feature(cxx_exceptions) #error This test requires exceptions be disabled @@ -19,6 +26,12 @@ struct promise_void { template <typename... T> struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise_void; }; +#ifndef DISABLE_WARNING void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}} co_return; } +#else +void test0() { // expected-no-diagnostics + co_return; +} +#endif diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index e6eaedef4cce..856110333d37 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -654,6 +654,18 @@ float badly_specialized_coro_handle() { // expected-error {{std::experimental::c co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } +namespace std { + struct nothrow_t {}; + constexpr nothrow_t nothrow = {}; +} + +using SizeT = decltype(sizeof(int)); + +void* operator new(SizeT __sz, const std::nothrow_t&) noexcept; +void operator delete(void* __p, const std::nothrow_t&) noexcept; + + + struct promise_on_alloc_failure_tag {}; template<> @@ -694,3 +706,43 @@ coro<T> dependent_private_alloc_failure_handler(T) { } template coro<bad_promise_11> dependent_private_alloc_failure_handler(bad_promise_11); // expected-note@-1 {{requested here}} + +struct bad_promise_12 { + coro<bad_promise_12> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void unhandled_exception(); + void return_void(); + static coro<bad_promise_12> get_return_object_on_allocation_failure(); + + static void* operator new(SizeT); + // expected-error@-1 2 {{'operator new' is required to have a non-throwing noexcept specification when the promise type declares 'get_return_object_on_allocation_failure()'}} +}; +coro<bad_promise_12> throwing_in_class_new() { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} + co_return; +} + +template <class T> +coro<T> dependent_throwing_in_class_new(T) { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} + co_return; +} +template coro<bad_promise_12> dependent_throwing_in_class_new(bad_promise_12); // expected-note {{requested here}} + + +struct good_promise_13 { + coro<good_promise_13> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void unhandled_exception(); + void return_void(); + static coro<good_promise_13> get_return_object_on_allocation_failure(); +}; +coro<good_promise_13> uses_nothrow_new() { + co_return; +} + +template <class T> +coro<T> dependent_uses_nothrow_new(T) { + co_return; +} +template coro<good_promise_13> dependent_uses_nothrow_new(good_promise_13); diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index d6374e4ce907..5de228ad2857 100644 --- a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -213,3 +213,38 @@ namespace transform_params { }; D d(Y<0, 1, 2>{}); } + +namespace variadic { + int arr3[3], arr4[4]; + + // PR32673 + template<typename T> struct A { + template<typename ...U> A(T, U...); + }; + A a(1, 2, 3); + + template<typename T> struct B { + template<int ...N> B(T, int (&...r)[N]); + }; + B b(1, arr3, arr4); + + template<typename T> struct C { + template<template<typename> typename ...U> C(T, U<int>...); + }; + C c(1, a, b); + + template<typename ...U> struct X { + template<typename T> X(T, U...); + }; + X x(1, 2, 3); + + template<int ...N> struct Y { + template<typename T> Y(T, int (&...r)[N]); + }; + Y y(1, arr3, arr4); + + template<template<typename> typename ...U> struct Z { + template<typename T> Z(T, U<int>...); + }; + Z z(1, a, b); +} diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp index 01bc457ec206..88f5ab1e85c0 100644 --- a/test/SemaCXX/warn-unused-result.cpp +++ b/test/SemaCXX/warn-unused-result.cpp @@ -160,3 +160,49 @@ void g() { (void)noexcept(f(), false); // Should not warn. } } + +namespace { +// C++ Methods should warn even in their own class. +struct [[clang::warn_unused_result]] S { + S DoThing() { return {}; }; + S operator++(int) { return {}; }; + S operator--(int) { return {}; }; + // Improperly written prefix. + S operator++() { return {}; }; + S operator--() { return {}; }; +}; + +struct [[clang::warn_unused_result]] P { + P DoThing() { return {}; }; +}; + +P operator++(const P &, int) { return {}; }; +P operator--(const P &, int) { return {}; }; +// Improperly written prefix. +P operator++(const P &) { return {}; }; +P operator--(const P &) { return {}; }; + +void f() { + S s; + P p; + s.DoThing(); // expected-warning {{ignoring return value}} + p.DoThing(); // expected-warning {{ignoring return value}} + // Only postfix is expected to warn when written correctly. + s++; // expected-warning {{ignoring return value}} + s--; // expected-warning {{ignoring return value}} + p++; // expected-warning {{ignoring return value}} + p--; // expected-warning {{ignoring return value}} + // Improperly written prefix operators should still warn. + ++s; // expected-warning {{ignoring return value}} + --s; // expected-warning {{ignoring return value}} + ++p; // expected-warning {{ignoring return value}} + --p; // expected-warning {{ignoring return value}} + + // Silencing the warning by cast to void still works. + (void)s.DoThing(); + (void)s++; + (void)p++; + (void)++s; + (void)++p; +} +} // namespace diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m index 91ea2ec4e0d4..477c4fc38363 100644 --- a/test/SemaObjC/foreach.m +++ b/test/SemaObjC/foreach.m @@ -55,3 +55,27 @@ void test2(NSObject<NSFastEnumeration> *collection) { for (obj.prop in collection) { /* expected-error {{selector element is not a valid lvalue}} */ } } + +int cond(); + +void test3(NSObject<NSFastEnumeration> *a0, NSObject<NSFastEnumeration> *a1) { + for (id i in a0) { /* expected-note 2 {{jump enters Objective-C fast enumeration loop}} */ + for (id j in a1) { /* expected-note 2 {{jump enters Objective-C fast enumeration loop}} */ + (void)i, (void)j; +label0: + if (cond()) + goto label1; + } +label1: + if (cond()) + goto label0; /* expected-error {{cannot jump from this goto statement to its label}} */ + if (cond()) + goto label2; + } + +label2: + if (cond()) + goto label0; /* expected-error {{cannot jump from this goto statement to its label}} */ + if (cond()) + goto label1; /* expected-error{{cannot jump from this goto statement to its label}} */ +} diff --git a/test/lit.cfg b/test/lit.cfg index e4a13054ba81..a5e8b9de994b 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -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'. ***""") ) diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 8fdfbfc4842e..63d713987482 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -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@" diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 2fa8edb81ae4..33d957658cf0 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -506,12 +506,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // FIXME: Remove this, one day. if (!Asm.LLVMArgs.empty()) { unsigned NumArgs = Asm.LLVMArgs.size(); - const char **Args = new const char*[NumArgs + 2]; + auto Args = llvm::make_unique<const char*[]>(NumArgs + 2); Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Asm.LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args); + llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); } // Execute the invocation, unless there were parsing errors. diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp index f7ba3eeab21b..83aae553a335 100644 --- a/unittests/Driver/ToolChainTest.cpp +++ b/unittests/Driver/ToolChainTest.cpp @@ -142,4 +142,4 @@ TEST(ToolChainTest, DefaultDriverMode) { EXPECT_TRUE(CLDriver.IsCLMode()); } -} // end anonymous namespace +} // end anonymous namespace. diff --git a/unittests/Format/FormatTestComments.cpp b/unittests/Format/FormatTestComments.cpp index df24abe26125..e6310158e91e 100644 --- a/unittests/Format/FormatTestComments.cpp +++ b/unittests/Format/FormatTestComments.cpp @@ -2018,7 +2018,7 @@ TEST_F(FormatTestComments, AlignTrailingComments) { format("#define MACRO(V)\\\n" "V(Rt2) /* one more char */ \\\n" "V(Rs) /* than here */ \\\n" - "/* comment 3 */ \\\n", + "/* comment 3 */\n", getLLVMStyleWithColumns(40))); EXPECT_EQ("int i = f(abc, // line 1\n" " d, // line 2\n" diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 8aaa28beaac2..981445675343 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -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,408 @@ 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; + + class RuleOrAggregateRuleSet { + std::vector<AttributeSubjectMatchRule> Rules; + bool IsRule; + RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules, + bool IsRule) + : Rules(Rules), IsRule(IsRule) {} + + public: + bool isRule() const { return IsRule; } + + const AttributeSubjectMatchRule &getRule() const { + assert(IsRule && "not a rule!"); + return Rules[0]; + } + + ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const { + return Rules; + } + + static RuleOrAggregateRuleSet + getRule(const AttributeSubjectMatchRule &Rule) { + return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true); + } + static RuleOrAggregateRuleSet + getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) { + return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false); + } + }; + llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> 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 + +static bool doesDeclDeriveFrom(const Record *D, const Record *Base) { + const Record *CurrentBase = D->getValueAsDef("Base"); + if (!CurrentBase) + return false; + if (CurrentBase == Base) + return true; + return doesDeclDeriveFrom(CurrentBase, Base); +} + +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, RuleOrAggregateRuleSet::getRule( + AttributeSubjectMatchRule(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); + } + + std::vector<Record *> Aggregates = + Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule"); + std::vector<Record *> DeclNodes = Records.getAllDerivedDefinitions("DDecl"); + for (const auto *Aggregate : Aggregates) { + Record *SubjectDecl = Aggregate->getValueAsDef("Subject"); + + // Gather sub-classes of the aggregate subject that act as attribute + // subject rules. + std::vector<AttributeSubjectMatchRule> Rules; + for (const auto *D : DeclNodes) { + if (doesDeclDeriveFrom(D, SubjectDecl)) { + auto It = SubjectsToRules.find(D); + if (It == SubjectsToRules.end()) + continue; + if (!It->second.isRule() || It->second.getRule().isSubRule()) + continue; // Assume that the rule will be included as well. + Rules.push_back(It->second.getRule()); + } + } + + bool Inserted = + SubjectsToRules + .try_emplace(SubjectDecl, + RuleOrAggregateRuleSet::getAggregateRuleSet(Rules)) + .second; + if (!Inserted) { + PrintFatalError("Attribute subject match rules should not represent" + "same attribute subjects."); + } + } +} + +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"); + for (const auto &Rule : It->getSecond().getAggregateRuleSet()) { + // The rule might be language specific, so only subtract it from the given + // rules if the specific language options are specified. + std::vector<Record *> LangOpts = Rule.getLangOpts(); + SS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() + << ", /*IsSupported=*/"; + if (!LangOpts.empty()) { + for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { + std::string Part = (*I)->getValueAsString("Name"); + if ((*I)->getValueAsBit("Negated")) + SS << "!"; + SS << "LangOpts." + Part; + if (I + 1 != E) + SS << " || "; + } + } else + SS << "true"; + SS << "));\n"; + } + } + SS << "}\n\n"; + OS << SS.str(); + return FnName; +} + +void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { + // Generate routines that check the names of sub-rules. + OS << "Optional<attr::SubjectMatchRule> " + "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n"; + OS << " return None;\n"; + OS << "}\n\n"; + + std::map<const Record *, std::vector<AttributeSubjectMatchRule>> + SubMatchRules; + for (const auto &Rule : Rules) { + if (!Rule.isSubRule()) + continue; + SubMatchRules[Rule.MetaSubject].push_back(Rule); + } + + for (const auto &SubMatchRule : SubMatchRules) { + OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_" + << SubMatchRule.first->getValueAsString("Name") + << "(StringRef Name, bool IsUnless) {\n"; + OS << " if (IsUnless)\n"; + OS << " return " + "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; + for (const auto &Rule : SubMatchRule.second) { + if (Rule.isNegatedSubRule()) + OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() + << ").\n"; + } + OS << " Default(None);\n"; + OS << " return " + "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n"; + for (const auto &Rule : SubMatchRule.second) { + if (!Rule.isNegatedSubRule()) + OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue() + << ").\n"; + } + OS << " Default(None);\n"; + OS << "}\n\n"; + } + + // Generate the function that checks for the top-level rules. + OS << "std::pair<Optional<attr::SubjectMatchRule>, " + "Optional<attr::SubjectMatchRule> (*)(StringRef, " + "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n"; + OS << " return " + "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, " + "Optional<attr::SubjectMatchRule> (*) (StringRef, " + "bool)>>(Name).\n"; + for (const auto &Rule : Rules) { + if (Rule.isSubRule()) + continue; + std::string SubRuleFunction; + if (SubMatchRules.count(Rule.MetaSubject)) + SubRuleFunction = "isAttributeSubjectMatchSubRuleFor_" + Rule.getName(); + else + SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor"; + OS << " Case(\"" << Rule.getName() << "\", std::make_pair(" + << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n"; + } + OS << " Default(std::make_pair(None, " + "defaultIsAttributeSubjectMatchSubRuleFor));\n"; + OS << "}\n\n"; + + // Generate the function that checks for the submatch rules. + OS << "const char *validAttributeSubjectMatchSubRules(" + << AttributeSubjectMatchRule::EnumName << " Rule) {\n"; + OS << " switch (Rule) {\n"; + for (const auto &SubMatchRule : SubMatchRules) { + OS << " case " + << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue() + << ":\n"; + OS << " return \"'"; + bool IsFirst = true; + for (const auto &Rule : SubMatchRule.second) { + if (!IsFirst) + OS << ", '"; + IsFirst = false; + if (Rule.isNegatedSubRule()) + OS << "unless("; + OS << Rule.getName(); + if (Rule.isNegatedSubRule()) + OS << ')'; + OS << "'"; + } + OS << "\";\n"; + } + OS << " default: return nullptr;\n"; + OS << " }\n"; + OS << "}\n\n"; +} + template <typename Fn> static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr); @@ -2109,6 +2513,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); @@ -2596,7 +3011,8 @@ static std::string CalculateDiagnostic(const Record &S) { Field = 1U << 12, CXXMethod = 1U << 13, ObjCProtocol = 1U << 14, - Enum = 1U << 15 + Enum = 1U << 15, + Named = 1U << 16, }; uint32_t SubMask = 0; @@ -2631,6 +3047,7 @@ static std::string CalculateDiagnostic(const Record &S) { .Case("Field", Field) .Case("CXXMethod", CXXMethod) .Case("Enum", Enum) + .Case("Named", Named) .Default(0); if (!V) { // Something wasn't in our mapping, so be helpful and let the developer @@ -2689,6 +3106,9 @@ static std::string CalculateDiagnostic(const Record &S) { case ObjCProtocol | ObjCInterface: return "ExpectedObjectiveCInterfaceOrProtocol"; case Field | Var: return "ExpectedFieldOrGlobalVar"; + + case Named: + return "ExpectedNamedDecl"; } PrintFatalError(S.getLoc(), @@ -2704,9 +3124,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 +3215,42 @@ 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"; + OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n"; + OS << "}\n\n"; +} + static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { OS << "static bool defaultDiagnoseLangOpts(Sema &, "; OS << "const AttributeList &) {\n"; @@ -2949,6 +3409,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 +3445,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 +3463,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 +3605,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 +3641,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 +3724,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 +3735,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 +3804,50 @@ 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 << ", "; + PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet = + Support.SubjectsToRules.find(Subject.value())->getSecond(); + if (RuleSet.isRule()) { + OS << RuleSet.getRule().getEnumValueName(); + continue; + } + OS << "("; + for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) { + if (Rule.index()) + OS << ", "; + OS << Rule.value().getEnumValueName(); + } + OS << ")"; + } + OS << ")\n"; } } diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index fd7999be3877..781518ddbc31 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -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; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 033cb78f36f3..e1b7d0ec63be 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -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