Merge commit '35aeed5957506ea23ebbc276d37b7b7423cc9139' into stable
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bbc8751..bb61943 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,6 +101,7 @@
include(AddLLVM)
include(TableGen)
include(HandleLLVMOptions)
+ include(VersionFromVCS)
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
@@ -196,7 +197,7 @@
set(DEFAULT_SYSROOT "" CACHE PATH
"Default <path> to all compiler invocations for --sysroot=<path>." )
-set(CLANG_DEFAULT_OPENMP_RUNTIME "libgomp" CACHE STRING
+set(CLANG_DEFAULT_OPENMP_RUNTIME "libomp" CACHE STRING
"Default OpenMP runtime used by -fopenmp.")
set(CLANG_VENDOR "" CACHE STRING
@@ -213,6 +214,19 @@
add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
endif()
+option(CLANG_APPEND_VC_REV
+ "Append the version control system revision id to clang version spew" OFF)
+if(CLANG_APPEND_VC_REV)
+ if(NOT SVN_REVISION)
+ # This macro will set SVN_REVISION in the parent scope
+ add_version_info_from_vcs(VERSION_VAR)
+ endif()
+
+ if(SVN_REVISION)
+ add_definitions(-DSVN_REVISION="${SVN_REVISION}")
+ endif()
+endif()
+
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
"Vendor-specific uti.")
@@ -430,6 +444,21 @@
set_clang_windows_version_resource_properties(${name})
endmacro(add_clang_executable)
+macro(add_clang_tool name)
+ add_clang_executable(${name} ${ARGN})
+ install(TARGETS ${name}
+ RUNTIME DESTINATION bin
+ COMPONENT ${name})
+
+ if(NOT CMAKE_CONFIGURATION_TYPES)
+ add_custom_target(install-${name}
+ DEPENDS ${name}
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=${name}
+ -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+ endif()
+endmacro()
+
macro(add_clang_symlink name dest)
add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE)
# Always generate install targets
@@ -462,28 +491,6 @@
)
endif()
-if(INTERNAL_INSTALL_PREFIX)
- set(LIBCLANG_HEADERS_INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/include")
-else()
- set(LIBCLANG_HEADERS_INSTALL_DESTINATION include)
-endif()
-
-install(DIRECTORY include/clang-c
- COMPONENT libclang-headers
- DESTINATION "${LIBCLANG_HEADERS_INSTALL_DESTINATION}"
- FILES_MATCHING
- PATTERN "*.h"
- PATTERN ".svn" EXCLUDE
- )
-
-if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's.
- add_custom_target(install-libclang-headers
- DEPENDS
- COMMAND "${CMAKE_COMMAND}"
- -DCMAKE_INSTALL_COMPONENT=libclang-headers
- -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
-endif()
-
add_definitions( -D_GNU_SOURCE )
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
@@ -570,6 +577,7 @@
ARGS ${LLVM_LIT_EXTRA_ARGS}
)
endif()
+ add_subdirectory(utils/perf-training)
endif()
option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
@@ -578,9 +586,19 @@
add_subdirectory(docs)
endif()
-set(CLANG_ORDER_FILE "" CACHE FILEPATH
+# this line is needed as a cleanup to ensure that any CMakeCaches with the old
+# default value get updated to the new default.
+if(CLANG_ORDER_FILE STREQUAL "")
+ unset(CLANG_ORDER_FILE CACHE)
+endif()
+
+set(CLANG_ORDER_FILE ${CMAKE_CURRENT_BINARY_DIR}/clang.order CACHE FILEPATH
"Order file to use when compiling clang in order to improve startup time.")
+if(NOT EXISTS ${CLANG_ORDER_FILE})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${CLANG_ORDER_FILE})
+endif()
+
if (CLANG_BUILT_STANDALONE OR CMAKE_VERSION VERSION_EQUAL 3 OR
CMAKE_VERSION VERSION_GREATER 3)
# Generate a list of CMake library targets so that other CMake projects can
@@ -622,9 +640,32 @@
)
set(cmake_3_4_USES_TERMINAL USES_TERMINAL 1)
endif()
+
+ if(NOT CLANG_STAGE)
+ set(CLANG_STAGE stage1)
+ message(STATUS "Setting current clang stage to: ${CLANG_STAGE}")
+ endif()
+
+ string(REGEX MATCH "stage([0-9]*)" MATCHED_STAGE "${CLANG_STAGE}")
+ if(MATCHED_STAGE)
+ if(NOT LLVM_BUILD_INSTRUMENTED)
+ math(EXPR STAGE_NUM "${CMAKE_MATCH_1} + 1")
+ set(NEXT_CLANG_STAGE stage${STAGE_NUM})
+ else()
+ set(NEXT_CLANG_STAGE stage${CMAKE_MATCH_1})
+ endif()
+ else()
+ set(NEXT_CLANG_STAGE bootstrap)
+ endif()
+
+ if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
+ set(NEXT_CLANG_STAGE ${NEXT_CLANG_STAGE}-instrumented)
+ endif()
+ message(STATUS "Setting next clang stage to: ${NEXT_CLANG_STAGE}")
- set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-stamps/)
- set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-bins/)
+
+ set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
+ set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
# If on Darwin we need to make bootstrap depend on LTO and pass
# DARWIN_LTO_LIBRARY so that -flto will work using the just-built compiler
@@ -635,26 +676,80 @@
set(LTO_RANLIB -DCMAKE_RANLIB=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib)
endif()
- add_custom_target(bootstrap-clear
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-cleared
+ add_custom_target(${NEXT_CLANG_STAGE}-clear
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bootstrap-cleared
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
DEPENDS clang ${LTO_DEP}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${STAMP_DIR}
- COMMENT "Clobberring bootstrap build and stamp directories"
+ COMMENT "Clobberring ${NEXT_CLANG_STAGE} build and stamp directories"
)
if(CMAKE_VERBOSE_MAKEFILE)
set(verbose -DCMAKE_VERBOSE_MAKEFILE=On)
endif()
- ExternalProject_Add(bootstrap
- DEPENDS clang ${LTO_DEP}
- PREFIX bootstrap
+ set(BOOTSTRAP_DEFAULT_PASSTHROUGH
+ PACKAGE_VERSION
+ LLVM_VERSION_MAJOR
+ LLVM_VERSION_MINOR
+ LLVM_VERSION_PATCH
+ LLVM_VERSION_SUFFIX
+ CLANG_REPOSITORY_STRING
+ CMAKE_MAKE_PROGRAM)
+
+ if(TARGET compiler-rt)
+ set(RUNTIME_DEP compiler-rt)
+ endif()
+
+ set(COMPILER_OPTIONS
+ -DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
+ -DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
+ -DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
+
+ if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
+ set(PGO_DEP llvm-profdata)
+ set(PGO_OPT -DLLVM_PROFDATA=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-profdata)
+ endif()
+
+ if(LLVM_BUILD_INSTRUMENTED)
+ set(PGO_DEP generate-profdata)
+ set(PGO_OPT -DLLVM_PROFDATA_FILE=${CMAKE_CURRENT_BINARY_DIR}/utils/perf-training/clang.profdata)
+ set(COMPILER_OPTIONS
+ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
+ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
+ -DCMAKE_ASM_COMPILER=${CMAKE_ASM_COMPILER})
+ set(RUNTIME_DEP) # Don't set runtime dependencies
+ endif()
+
+ # Find all variables that start with BOOTSTRAP_ and populate a variable with
+ # them.
+ get_cmake_property(variableNames VARIABLES)
+ foreach(variableName ${variableNames})
+ if(variableName MATCHES "^BOOTSTRAP_")
+ string(SUBSTRING ${variableName} 10 -1 varName)
+ string(REPLACE ";" "\;" value "${${variableName}}")
+ list(APPEND PASSTHROUGH_VARIABLES
+ -D${varName}=${value})
+ endif()
+ endforeach()
+
+ # Populate the passthrough variables
+ foreach(variableName ${CLANG_BOOTSTRAP_PASSTHROUGH} ${BOOTSTRAP_DEFAULT_PASSTHROUGH})
+ if(${variableName})
+ string(REPLACE ";" "\;" value ${${variableName}})
+ list(APPEND PASSTHROUGH_VARIABLES
+ -D${variableName}=${value})
+ endif()
+ endforeach()
+
+ ExternalProject_Add(${NEXT_CLANG_STAGE}
+ DEPENDS clang ${LTO_DEP} ${RUNTIME_DEP} ${PGO_DEP}
+ PREFIX ${NEXT_CLANG_STAGE}
SOURCE_DIR ${CMAKE_SOURCE_DIR}
STAMP_DIR ${STAMP_DIR}
BINARY_DIR ${BINARY_DIR}
@@ -664,38 +759,44 @@
# seem to work, so instead I'm passing this through
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
${CLANG_BOOTSTRAP_CMAKE_ARGS}
- -DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
- -DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
- -DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
- ${LTO_LIBRARY} ${LTO_AR} ${LTO_RANLIB} ${verbose}
+ ${PASSTHROUGH_VARIABLES}
+ -DCLANG_STAGE=${NEXT_CLANG_STAGE}
+ ${COMPILER_OPTIONS}
+ ${LTO_LIBRARY} ${LTO_AR} ${LTO_RANLIB} ${verbose} ${PGO_OPT}
INSTALL_COMMAND ""
STEP_TARGETS configure build
${cmake_3_4_USES_TERMINAL_OPTIONS}
)
# exclude really-install from main target
- set_target_properties(bootstrap PROPERTIES _EP_really-install_EXCLUDE_FROM_MAIN On)
- ExternalProject_Add_Step(bootstrap really-install
+ set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_really-install_EXCLUDE_FROM_MAIN On)
+ ExternalProject_Add_Step(${NEXT_CLANG_STAGE} really-install
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target install
- COMMENT "Performing install step for 'bootstrap'"
+ COMMENT "Performing install step for '${NEXT_CLANG_STAGE}'"
DEPENDEES build
${cmake_3_4_USES_TERMINAL}
)
- ExternalProject_Add_StepTargets(bootstrap really-install)
- add_custom_target(bootstrap-install DEPENDS bootstrap-really-install)
+ ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} really-install)
+ add_custom_target(${NEXT_CLANG_STAGE}-install DEPENDS ${NEXT_CLANG_STAGE}-really-install)
-
- set(ADDITIONAL_TARGETS_TO_ADD check-llvm check-clang check-all)
- foreach(target ${ADDITIONAL_TARGETS_TO_ADD})
+ if(NOT CLANG_BOOTSTRAP_TARGETS)
+ set(CLANG_BOOTSTRAP_TARGETS check-llvm check-clang check-all)
+ endif()
+ foreach(target ${CLANG_BOOTSTRAP_TARGETS})
# exclude from main target
- set_target_properties(bootstrap PROPERTIES _EP_${target}_EXCLUDE_FROM_MAIN On)
+ set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_${target}_EXCLUDE_FROM_MAIN On)
- ExternalProject_Add_Step(bootstrap ${target}
+ ExternalProject_Add_Step(${NEXT_CLANG_STAGE} ${target}
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target ${target}
- COMMENT "Performing ${target} for 'bootstrap'"
+ COMMENT "Performing ${target} for '${NEXT_CLANG_STAGE}'"
DEPENDEES configure
${cmake_3_4_USES_TERMINAL}
)
- ExternalProject_Add_StepTargets(bootstrap ${target})
+
+ if(target MATCHES "^stage[0-9]*")
+ add_custom_target(${target} DEPENDS ${NEXT_CLANG_STAGE}-${target})
+ endif()
+
+ ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} ${target})
endforeach()
endif()
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index 9fbc5c7..971fe9b 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -27,7 +27,7 @@
N: Doug Gregor
E: dgregor@apple.com
-D: Emeritus owner, Swift language-specific changes
+D: Emeritus owner
N: Reid Kleckner
E: rnk@google.com
@@ -41,8 +41,8 @@
E: anton@korobeynikov.info
D: Exception handling, Windows codegen, ARM EABI
-N: Ted Kremenek
-E: kremenek@apple.com
+N: Anna Zaks
+E: ganna@apple.com
D: Clang Static Analyzer
N: John McCall
diff --git a/INSTALL.txt b/INSTALL.txt
index a1652b2..fc9bd46 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -45,5 +45,4 @@
configured.
The Clang compiler is available as 'clang' and 'clang++'. It supports a gcc like
-command line interface. See the man page for clang (installed into
-$prefix/share/man/man1) for more information.
+command line interface. See the man page for clang for more information.
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 49b2fd8..e4b3876 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -1102,6 +1102,9 @@
CursorKind.VISIBILITY_ATTR = CursorKind(417)
+CursorKind.DLLEXPORT_ATTR = CursorKind(418)
+CursorKind.DLLIMPORT_ATTR = CursorKind(419)
+
###
# Preprocessing
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
@@ -1114,7 +1117,8 @@
# A module import declaration.
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
-
+# A type alias template declaration
+CursorKind.TYPE_ALIAS_TEMPLATE_DECL = CursorKind(601)
### Template Argument Kinds ###
class TemplateArgumentKind(BaseEnumeration):
@@ -1699,6 +1703,7 @@
TypeKind.VARIABLEARRAY = TypeKind(115)
TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
TypeKind.MEMBERPOINTER = TypeKind(117)
+TypeKind.AUTO = TypeKind(118)
class RefQualifierKind(BaseEnumeration):
"""Describes a specific ref-qualifier of a type."""
diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py
index 8cabc51..5bac289 100644
--- a/bindings/python/tests/cindex/test_cursor_kind.py
+++ b/bindings/python/tests/cindex/test_cursor_kind.py
@@ -13,6 +13,7 @@
assert CursorKind.OBJ_SELF_EXPR in kinds
assert CursorKind.MS_ASM_STMT in kinds
assert CursorKind.MODULE_IMPORT_DECL in kinds
+ assert CursorKind.TYPE_ALIAS_TEMPLATE_DECL in kinds
def test_kind_groups():
"""Check that every kind classifies to exactly one group."""
diff --git a/cmake/caches/PGO-stage2-instrumented.cmake b/cmake/caches/PGO-stage2-instrumented.cmake
new file mode 100644
index 0000000..fe5e83d
--- /dev/null
+++ b/cmake/caches/PGO-stage2-instrumented.cmake
@@ -0,0 +1,9 @@
+set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
+set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
+set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
+
+set(CLANG_BOOTSTRAP_TARGETS check-all check-llvm check-clang test-suite CACHE STRING "")
+
+set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ -C ${CMAKE_CURRENT_LIST_DIR}/PGO-stage2.cmake
+ CACHE STRING "")
diff --git a/cmake/caches/PGO-stage2.cmake b/cmake/caches/PGO-stage2.cmake
new file mode 100644
index 0000000..2080cd4
--- /dev/null
+++ b/cmake/caches/PGO-stage2.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
+set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
diff --git a/cmake/caches/PGO.cmake b/cmake/caches/PGO.cmake
new file mode 100644
index 0000000..dc11173
--- /dev/null
+++ b/cmake/caches/PGO.cmake
@@ -0,0 +1,17 @@
+set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
+set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
+set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
+
+set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
+set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED ON CACHE BOOL "")
+set(CLANG_BOOTSTRAP_TARGETS
+ generate-profdata
+ stage2
+ stage2-check-all
+ stage2-check-llvm
+ stage2-check-clang
+ stage2-test-suite CACHE STRING "")
+
+set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ -C ${CMAKE_CURRENT_LIST_DIR}/PGO-stage2-instrumented.cmake
+ CACHE STRING "")
diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst
index 06e7da7..93f6314 100644
--- a/docs/AddressSanitizer.rst
+++ b/docs/AddressSanitizer.rst
@@ -267,5 +267,4 @@
More Information
================
-`http://code.google.com/p/address-sanitizer <http://code.google.com/p/address-sanitizer/>`_
-
+`<https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index 9b4ffe3..bfabd59 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -254,7 +254,8 @@
single line.
**AlwaysBreakAfterDefinitionReturnType** (``DefinitionReturnTypeBreakingStyle``)
- The function definition return type breaking style to use.
+ The function definition return type breaking style to use. This
+ option is deprecated and is retained for backwards compatibility.
Possible values:
@@ -264,7 +265,25 @@
* ``DRTBS_All`` (in configuration: ``All``)
Always break after the return type.
* ``DRTBS_TopLevel`` (in configuration: ``TopLevel``)
- Always break after the return types of top level functions.
+ Always break after the return types of top-level functions.
+
+
+**AlwaysBreakAfterReturnType** (``ReturnTypeBreakingStyle``)
+ The function declaration return type breaking style to use.
+
+ Possible values:
+
+ * ``RTBS_None`` (in configuration: ``None``)
+ Break after return type automatically.
+ ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
+ * ``RTBS_All`` (in configuration: ``All``)
+ Always break after the return type.
+ * ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
+ Always break after the return types of top-level functions.
+ * ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
+ Always break after the return type of function definitions.
+ * ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
+ Always break after the return type of top-level definitions.
**AlwaysBreakBeforeMultilineStrings** (``bool``)
diff --git a/docs/CommandGuide/clang.rst b/docs/CommandGuide/clang.rst
index 9f6d6f5..2b45695 100644
--- a/docs/CommandGuide/clang.rst
+++ b/docs/CommandGuide/clang.rst
@@ -262,7 +262,12 @@
Generate debug information that contains external references to
types defined in clang modules or precompiled headers instead of
emitting redundant debug type information into every object file.
- This option implies `-fmodule-format=obj`.
+ This option implies :option:`-fmodule-format=obj`.
+
+ This option should not be used when building static libraries for
+ distribution to other machines because the debug info will contain
+ references to the module cache on the machine the object files in
+ the library were built on.
.. option:: -fstandalone-debug -fno-standalone-debug
diff --git a/docs/ControlFlowIntegrity.rst b/docs/ControlFlowIntegrity.rst
index b583fc0..780ff88 100644
--- a/docs/ControlFlowIntegrity.rst
+++ b/docs/ControlFlowIntegrity.rst
@@ -20,22 +20,72 @@
allowing developers to enable them in release builds.
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
-As currently implemented, all of Clang's CFI schemes (``cfi-vcall``,
-``cfi-derived-cast``, ``cfi-unrelated-cast``, ``cfi-nvcall``, ``cfi-icall``)
-rely on link-time optimization (LTO); so it is required to specify
-``-flto``, and the linker used must support LTO, for example via the `gold
-plugin`_. To allow the checks to be implemented efficiently, the program must
-be structured such that certain object files are compiled with CFI enabled,
-and are statically linked into the program. This may preclude the use of
-shared libraries in some cases.
+You can also enable a subset of available :ref:`schemes <cfi-schemes>`.
+As currently implemented, all schemes rely on link-time optimization (LTO);
+so it is required to specify ``-flto``, and the linker used must support LTO,
+for example via the `gold plugin`_.
-Clang currently implements forward-edge CFI for member function calls and
-bad cast checking. More schemes are under development.
+To allow the checks to be implemented efficiently, the program must be
+structured such that certain object files are compiled with CFI
+enabled, and are statically linked into the program. This may preclude
+the use of shared libraries in some cases. Experimental support for
+:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
+does not have these requirements. This cross-DSO support has unstable
+ABI at this time.
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
+.. _cfi-schemes:
+
+Available schemes
+=================
+
+Available schemes are:
+
+ - ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
+ <cfi-strictness>`.
+ - ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
+ dynamic type.
+ - ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
+ unrelated type to the wrong dynamic type.
+ - ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
+ the wrong dynamic type.
+ - ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
+ wrong dynamic type.
+ - ``-fsanitize=cfi-icall``: Indirect call of a function with wrong dynamic
+ type.
+
+You can use ``-fsanitize=cfi`` to enable all the schemes and use
+``-fno-sanitize`` flag to narrow down the set of schemes as desired.
+For example, you can build your program with
+``-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall``
+to use all schemes except for non-virtual member function call and indirect call
+checking.
+
+Remember that you have to provide ``-flto`` if at least one CFI scheme is
+enabled.
+
+Trapping and Diagnostics
+========================
+
+By default, CFI will abort the program immediately upon detecting a control
+flow integrity violation. You can use the :ref:`-fno-sanitize-trap=
+<controlling-code-generation>` flag to cause CFI to print a diagnostic
+similar to the one below before the program aborts.
+
+.. code-block:: console
+
+ bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
+ 0x000000425a50: note: vtable is of type 'A'
+ 00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
+ ^
+
+If diagnostics are enabled, you can also configure CFI to continue program
+execution instead of aborting by using the :ref:`-fsanitize-recover=
+<controlling-code-generation>` flag.
+
Forward-Edge CFI for Virtual Calls
-----------------------------------
+==================================
This scheme checks that virtual calls take place using a vptr of the correct
dynamic type; that is, the dynamic type of the called object must be a
@@ -48,7 +98,7 @@
``-fsanitize=cfi-vcall`` enabled and be statically linked into the program.
Performance
-~~~~~~~~~~~
+-----------
A performance overhead of less than 1% has been measured by running the
Dromaeo benchmark suite against an instrumented version of the Chromium
@@ -59,7 +109,7 @@
of up to 15% has been observed for Chromium.
Bad Cast Checking
------------------
+=================
This scheme checks that pointer casts are made to an object of the correct
dynamic type; that is, the dynamic type of the object must be a derived class
@@ -94,7 +144,7 @@
and be statically linked into the program.
Non-Virtual Member Function Call Checking
------------------------------------------
+=========================================
This scheme checks that non-virtual calls take place using an object of
the correct dynamic type; that is, the dynamic type of the called object
@@ -111,7 +161,7 @@
.. _cfi-strictness:
Strictness
-~~~~~~~~~~
+----------
If a class has a single non-virtual base and does not introduce or override
virtual member functions or fields other than an implicitly defined virtual
@@ -126,7 +176,7 @@
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
Indirect Function Call Checking
--------------------------------
+===============================
This scheme checks that function calls take place using a function of the
correct dynamic type; that is, the dynamic type of the function must match
@@ -153,7 +203,7 @@
This scheme is currently only supported on the x86 and x86_64 architectures.
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------------------------------------------------
This tool is similar to ``-fsanitize=function`` in that both tools check
the types of function calls. However, the two tools occupy different points
@@ -176,7 +226,7 @@
.. _cfi-blacklist:
Blacklist
----------
+=========
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
@@ -199,13 +249,23 @@
# Ignore all types with a uuid attribute.
type:attr:uuid
+.. _cfi-cross-dso:
+
+Shared library support
+======================
+
+Use **-f[no-]sanitize-cfi-cross-dso** to enable the cross-DSO control
+flow integrity mode, which allows all CFI schemes listed above to
+apply across DSO boundaries. As in the regular CFI, each DSO must be
+built with ``-flto``.
+
Design
-------
+======
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
Publications
-------------
+============
`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
diff --git a/docs/ControlFlowIntegrityDesign.rst b/docs/ControlFlowIntegrityDesign.rst
index af37445..b4aacd3 100644
--- a/docs/ControlFlowIntegrityDesign.rst
+++ b/docs/ControlFlowIntegrityDesign.rst
@@ -277,7 +277,223 @@
Forward-Edge CFI for Indirect Function Calls
============================================
-Sorry, no documentation yet, but see the comments at the top of
-``LowerBitSets::buildBitSetsFromFunctions`` in `LowerBitSets.cpp`_.
+Under forward-edge CFI for indirect function calls, each unique function
+type has its own bit vector, and at each call site we need to check that the
+function pointer is a member of the function type's bit vector. This scheme
+works in a similar way to forward-edge CFI for virtual calls, the distinction
+being that we need to build bit vectors of function entry points rather than
+of virtual tables.
-.. _LowerBitSets.cpp: http://llvm.org/klaus/llvm/blob/master/lib/Transforms/IPO/LowerBitSets.cpp
+Unlike when re-arranging global variables, we cannot re-arrange functions
+in a particular order and base our calculations on the layout of the
+functions' entry points, as we have no idea how large a particular function
+will end up being (the function sizes could even depend on how we arrange
+the functions). Instead, we build a jump table, which is a block of code
+consisting of one branch instruction for each of the functions in the bit
+set that branches to the target function, and redirect any taken function
+addresses to the corresponding jump table entry. In this way, the distance
+between function entry points is predictable and controllable. In the object
+file's symbol table, the symbols for the target functions also refer to the
+jump table entries, so that addresses taken outside the module will pass
+any verification done inside the module.
+
+In more concrete terms, suppose we have three functions ``f``, ``g``, ``h``
+which are members of a single bitset, and a function foo that returns their
+addresses:
+
+.. code-block:: none
+
+ f:
+ mov 0, %eax
+ ret
+
+ g:
+ mov 1, %eax
+ ret
+
+ h:
+ mov 2, %eax
+ ret
+
+ foo:
+ mov f, %eax
+ mov g, %edx
+ mov h, %ecx
+ ret
+
+Our jump table will (conceptually) look like this:
+
+.. code-block:: none
+
+ f:
+ jmp .Ltmp0 ; 5 bytes
+ int3 ; 1 byte
+ int3 ; 1 byte
+ int3 ; 1 byte
+
+ g:
+ jmp .Ltmp1 ; 5 bytes
+ int3 ; 1 byte
+ int3 ; 1 byte
+ int3 ; 1 byte
+
+ h:
+ jmp .Ltmp2 ; 5 bytes
+ int3 ; 1 byte
+ int3 ; 1 byte
+ int3 ; 1 byte
+
+ .Ltmp0:
+ mov 0, %eax
+ ret
+
+ .Ltmp1:
+ mov 1, %eax
+ ret
+
+ .Ltmp2:
+ mov 2, %eax
+ ret
+
+ foo:
+ mov f, %eax
+ mov g, %edx
+ mov h, %ecx
+ ret
+
+Because the addresses of ``f``, ``g``, ``h`` are evenly spaced at a power of
+2, and function types do not overlap (unlike class types with base classes),
+we can normally apply the `Alignment`_ and `Eliminating Bit Vector Checks
+for All-Ones Bit Vectors`_ optimizations thus simplifying the check at each
+call site to a range and alignment check.
+
+Shared library support
+======================
+
+**EXPERIMENTAL**
+
+The basic CFI mode described above assumes that the application is a
+monolithic binary; at least that all possible virtual/indirect call
+targets and the entire class hierarchy are known at link time. The
+cross-DSO mode, enabled with **-f[no-]sanitize-cfi-cross-dso** relaxes
+this requirement by allowing virtual and indirect calls to cross the
+DSO boundary.
+
+Assuming the following setup: the binary consists of several
+instrumented and several uninstrumented DSOs. Some of them may be
+dlopen-ed/dlclose-d periodically, even frequently.
+
+ - Calls made from uninstrumented DSOs are not checked and just work.
+ - Calls inside any instrumented DSO are fully protected.
+ - Calls between different instrumented DSOs are also protected, with
+ a performance penalty (in addition to the monolithic CFI
+ overhead).
+ - Calls from an instrumented DSO to an uninstrumented one are
+ unchecked and just work, with performance penalty.
+ - Calls from an instrumented DSO outside of any known DSO are
+ detected as CFI violations.
+
+In the monolithic scheme a call site is instrumented as
+
+.. code-block:: none
+
+ if (!InlinedFastCheck(f))
+ abort();
+ call *f
+
+In the cross-DSO scheme it becomes
+
+.. code-block:: none
+
+ if (!InlinedFastCheck(f))
+ __cfi_slowpath(CallSiteTypeId, f);
+ call *f
+
+CallSiteTypeId
+--------------
+
+``CallSiteTypeId`` is a stable process-wide identifier of the
+call-site type. For a virtual call site, the type in question is the class
+type; for an indirect function call it is the function signature. The
+mapping from a type to an identifier is an ABI detail. In the current,
+experimental, implementation the identifier of type T is calculated as
+follows:
+
+ - Obtain the mangled name for "typeinfo name for T".
+ - Calculate MD5 hash of the name as a string.
+ - Reinterpret the first 8 bytes of the hash as a little-endian
+ 64-bit integer.
+
+It is possible, but unlikely, that collisions in the
+``CallSiteTypeId`` hashing will result in weaker CFI checks that would
+still be conservatively correct.
+
+CFI_Check
+---------
+
+In the general case, only the target DSO knows whether the call to
+function ``f`` with type ``CallSiteTypeId`` is valid or not. To
+export this information, every DSO implements
+
+.. code-block:: none
+
+ void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
+
+This function provides external modules with access to CFI checks for
+the targets inside this DSO. For each known ``CallSiteTypeId``, this
+functions performs an ``llvm.bitset.test`` with the corresponding bit
+set. It aborts if the type is unknown, or if the check fails.
+
+The basic implementation is a large switch statement over all values
+of CallSiteTypeId supported by this DSO, and each case is similar to
+the InlinedFastCheck() in the basic CFI mode.
+
+CFI Shadow
+----------
+
+To route CFI checks to the target DSO's __cfi_check function, a
+mapping from possible virtual / indirect call targets to
+the corresponding __cfi_check functions is maintained. This mapping is
+implemented as a sparse array of 2 bytes for every possible page (4096
+bytes) of memory. The table is kept readonly (FIXME: not yet) most of
+the time.
+
+There are 3 types of shadow values:
+
+ - Address in a CFI-instrumented DSO.
+ - Unchecked address (a “trusted” non-instrumented DSO). Encoded as
+ value 0xFFFF.
+ - Invalid address (everything else). Encoded as value 0.
+
+For a CFI-instrumented DSO, a shadow value encodes the address of the
+__cfi_check function for all call targets in the corresponding memory
+page. If Addr is the target address, and V is the shadow value, then
+the address of __cfi_check is calculated as
+
+.. code-block:: none
+
+ __cfi_check = AlignUpTo(Addr, 4096) - (V + 1) * 4096
+
+This works as long as __cfi_check is aligned by 4096 bytes and located
+below any call targets in its DSO, but not more than 256MB apart from
+them.
+
+CFI_SlowPath
+------------
+
+The slow path check is implemented in compiler-rt library as
+
+.. code-block:: none
+
+ void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr)
+
+This functions loads a shadow value for ``TargetAddr``, finds the
+address of __cfi_check as described above and calls that.
+
+Position-independent executable requirement
+-------------------------------------------
+
+Cross-DSO CFI mode requires that the main executable is built as PIE.
+In non-PIE executables the address of an external function (taken from
+the main executable) is the address of that function’s PLT record in
+the main executable. This would break the CFI checks.
diff --git a/docs/InternalsManual.rst b/docs/InternalsManual.rst
index 7959179..c4af5b1 100644
--- a/docs/InternalsManual.rst
+++ b/docs/InternalsManual.rst
@@ -1995,7 +1995,7 @@
* Make sure that ``children()`` visits all of the subexpressions. This is
important for a number of features (e.g., IDE support, C++ variadic
templates). If you have sub-types, you'll also need to visit those
- sub-types in ``RecursiveASTVisitor`` and ``DataRecursiveASTVisitor``.
+ sub-types in ``RecursiveASTVisitor``.
* Add printing support (``StmtPrinter.cpp``) for your expression.
* Add profiling support (``StmtProfile.cpp``) for your AST node, noting the
distinguishing (non-source location) characteristics of an instance of
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 07b9c99..333dee6 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -1017,8 +1017,8 @@
``argtypes...`` such that no non-trivial functions are called as part of
that initialization. This trait is required to implement the C++11 standard
library.
-* ``__is_destructible`` (MSVC 2013): partially implemented
-* ``__is_nothrow_destructible`` (MSVC 2013): partially implemented
+* ``__is_destructible`` (MSVC 2013)
+* ``__is_nothrow_destructible`` (MSVC 2013)
* ``__is_nothrow_assignable`` (MSVC 2013, clang)
* ``__is_constructible`` (MSVC 2013, clang)
* ``__is_nothrow_constructible`` (MSVC 2013, clang)
diff --git a/docs/LeakSanitizer.rst b/docs/LeakSanitizer.rst
index d4b4fa0..8591808 100644
--- a/docs/LeakSanitizer.rst
+++ b/docs/LeakSanitizer.rst
@@ -28,6 +28,4 @@
More Information
================
-`https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer
-<https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer>`_
-
+`<https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer>`_
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 1f681e7..7f21262 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -1,4754 +1,4925 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>AST Matcher Reference</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
-<style type="text/css">
-td {
- padding: .33em;
-}
-td.doc {
- display: none;
- border-bottom: 1px solid black;
-}
-td.name:hover {
- color: blue;
- cursor: pointer;
-}
-</style>
-<script type="text/javascript">
-function toggle(id) {
- if (!id) return;
- row = document.getElementById(id);
- if (row.style.display != 'table-cell')
- row.style.display = 'table-cell';
- else
- row.style.display = 'none';
-}
-</script>
-</head>
-<body onLoad="toggle(location.hash.substring(1, location.hash.length - 6))">
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>AST Matcher Reference</h1>
-
-<p>This document shows all currently implemented matchers. The matchers are grouped
-by category and node type they match. You can click on matcher names to show the
-matcher's source documentation.</p>
-
-<p>There are three different basic categories of matchers:
-<ul>
-<li><a href="#decl-matchers">Node Matchers:</a> Matchers that match a specific type of AST node.</li>
-<li><a href="#narrowing-matchers">Narrowing Matchers:</a> Matchers that match attributes on AST nodes.</li>
-<li><a href="#traversal-matchers">Traversal Matchers:</a> Matchers that allow traversal between AST nodes.</li>
-</ul>
-</p>
-
-<p>Within each category the matchers are ordered by node type they match on.
-Note that if a matcher can match multiple node types, it will it will appear
-multiple times. This means that by searching for Matcher<Stmt> you can
-find all matchers that can be used to match on Stmt nodes.</p>
-
-<p>The exception to that rule are matchers that can match on any node. Those
-are marked with a * and are listed in the beginning of each category.</p>
-
-<p>Note that the categorization of matchers is a great help when you combine
-them into matcher expressions. You will usually want to form matcher expressions
-that read like english sentences by alternating between node matchers and
-narrowing or traversal matchers, like this:
-<pre>
-recordDecl(hasDescendant(
- ifStmt(hasTrueExpression(
- expr(hasDescendant(
- ifStmt()))))))
-</pre>
-</p>
-
-<!-- ======================================================================= -->
-<h2 id="decl-matchers">Node Matchers</h2>
-<!-- ======================================================================= -->
-
-<p>Node matchers are at the core of matcher expressions - they specify the type
-of node that is expected. Every match expression starts with a node matcher,
-which can then be further refined with a narrowing or traversal matcher. All
-traversal matchers take node matchers as their arguments.</p>
-
-<p>For convenience, all node matchers take an arbitrary number of arguments
-and implicitly act as allOf matchers.</p>
-
-<p>Node matchers are the only matchers that support the bind("id") call to
-bind the matched node to the given string, to be later retrieved from the
-match callback.</p>
-
-<p>It is important to remember that the arguments to node matchers are
-predicates on the same node, just with additional information about the type.
-This is often useful to make matcher expression more readable by inlining bind
-calls into redundant node matchers inside another node matcher:
-<pre>
-// This binds the CXXRecordDecl to "id", as the decl() matcher will stay on
-// the same node.
-recordDecl(decl().bind("id"), hasName("::MyClass"))
-</pre>
-</p>
-
-<table>
-<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
-<!-- START_DECL_MATCHERS -->
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers.
-
-Examples matches i(42).
- class C {
- C() : i(42) {}
- int i;
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html">AccessSpecDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="accessSpecDecl0"><pre>Matches C++ access specifier declarations.
-
-Given
- class C {
- public:
- int a;
- };
-accessSpecDecl()
- matches 'public:'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('classTemplateDecl0')"><a name="classTemplateDecl0Anchor">classTemplateDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="classTemplateDecl0"><pre>Matches C++ class template declarations.
-
-Example matches Z
- template<class T> class Z {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('classTemplateSpecializationDecl0')"><a name="classTemplateSpecializationDecl0Anchor">classTemplateSpecializationDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="classTemplateSpecializationDecl0"><pre>Matches C++ class template specializations.
-
-Given
- template<typename T> class A {};
- template<> class A<double> {};
- A<int> a;
-classTemplateSpecializationDecl()
- matches the specializations A<int> and A<double>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxConstructorDecl0')"><a name="cxxConstructorDecl0Anchor">cxxConstructorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxConstructorDecl0"><pre>Matches C++ constructor declarations.
-
-Example matches Foo::Foo() and Foo::Foo(int)
- class Foo {
- public:
- Foo();
- Foo(int);
- int DoSomething();
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxConversionDecl0')"><a name="cxxConversionDecl0Anchor">cxxConversionDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxConversionDecl0"><pre>Matches conversion operator declarations.
-
-Example matches the operator.
- class X { operator int() const; };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxDestructorDecl0')"><a name="cxxDestructorDecl0Anchor">cxxDestructorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDestructorDecl.html">CXXDestructorDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxDestructorDecl0"><pre>Matches explicit C++ destructor declarations.
-
-Example matches Foo::~Foo()
- class Foo {
- public:
- virtual ~Foo();
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxMethodDecl0')"><a name="cxxMethodDecl0Anchor">cxxMethodDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxMethodDecl0"><pre>Matches method declarations.
-
-Example matches y
- class X { void y(); };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxRecordDecl0')"><a name="cxxRecordDecl0Anchor">cxxRecordDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxRecordDecl0"><pre>Matches C++ class declarations.
-
-Example matches X, Z
- class X;
- template<class T> class Z {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('decl0')"><a name="decl0Anchor">decl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="decl0"><pre>Matches declarations.
-
-Examples matches X, C, and the friend declaration inside C;
- void X();
- class C {
- friend X;
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('declaratorDecl0')"><a name="declaratorDecl0Anchor">declaratorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="declaratorDecl0"><pre>Matches declarator declarations (field, variable, function
-and non-type template parameter declarations).
-
-Given
- class X { int y; };
-declaratorDecl()
- matches int y.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('enumConstantDecl0')"><a name="enumConstantDecl0Anchor">enumConstantDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumConstantDecl.html">EnumConstantDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="enumConstantDecl0"><pre>Matches enum constants.
-
-Example matches A, B, C
- enum X {
- A, B, C
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('enumDecl0')"><a name="enumDecl0Anchor">enumDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumDecl.html">EnumDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="enumDecl0"><pre>Matches enum declarations.
-
-Example matches X
- enum X {
- A, B, C
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('fieldDecl0')"><a name="fieldDecl0Anchor">fieldDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.
-
-Given
- class X { int m; };
-fieldDecl()
- matches 'm'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('friendDecl0')"><a name="friendDecl0Anchor">friendDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="friendDecl0"><pre>Matches friend declarations.
-
-Given
- class X { friend void foo(); };
-friendDecl()
- matches 'friend void foo()'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('functionDecl0')"><a name="functionDecl0Anchor">functionDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="functionDecl0"><pre>Matches function declarations.
-
-Example matches f
- void f();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('functionTemplateDecl0')"><a name="functionTemplateDecl0Anchor">functionTemplateDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTemplateDecl.html">FunctionTemplateDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="functionTemplateDecl0"><pre>Matches C++ function template declarations.
-
-Example matches f
- template<class T> void f(T t) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('linkageSpecDecl0')"><a name="linkageSpecDecl0Anchor">linkageSpecDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LinkageSpecDecl.html">LinkageSpecDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="linkageSpecDecl0"><pre>Matches a declaration of a linkage specification.
-
-Given
- extern "C" {}
-linkageSpecDecl()
- matches "extern "C" {}"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namedDecl0')"><a name="namedDecl0Anchor">namedDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="namedDecl0"><pre>Matches a declaration of anything that could have a name.
-
-Example matches X, S, the anonymous union type, i, and U;
- typedef int X;
- struct S {
- union {
- int i;
- } U;
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namespaceAliasDecl0')"><a name="namespaceAliasDecl0Anchor">namespaceAliasDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceAliasDecl.html">NamespaceAliasDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="namespaceAliasDecl0"><pre>Matches a declaration of a namespace alias.
-
-Given
- namespace test {}
- namespace alias = ::test;
-namespaceAliasDecl()
- matches "namespace alias" but not "namespace test"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namespaceDecl0')"><a name="namespaceDecl0Anchor">namespaceDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="namespaceDecl0"><pre>Matches a declaration of a namespace.
-
-Given
- namespace {}
- namespace test {}
-namespaceDecl()
- matches "namespace {}" and "namespace test {}"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('nonTypeTemplateParmDecl0')"><a name="nonTypeTemplateParmDecl0Anchor">nonTypeTemplateParmDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NonTypeTemplateParmDecl.html">NonTypeTemplateParmDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="nonTypeTemplateParmDecl0"><pre>Matches non-type template parameter declarations.
-
-Given
- template <typename T, int N> struct C {};
-nonTypeTemplateParmDecl()
- matches 'N', but not 'T'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcInterfaceDecl0')"><a name="objcInterfaceDecl0Anchor">objcInterfaceDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="objcInterfaceDecl0"><pre>Matches Objective-C interface declarations.
-
-Example matches Foo
- @interface Foo
- @end
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('parmVarDecl0')"><a name="parmVarDecl0Anchor">parmVarDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="parmVarDecl0"><pre>Matches parameter variable declarations.
-
-Given
- void f(int x);
-parmVarDecl()
- matches int x.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('recordDecl0')"><a name="recordDecl0Anchor">recordDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="recordDecl0"><pre>Matches class, struct, and union declarations.
-
-Example matches X, Z, U, and S
- class X;
- template<class T> class Z {};
- struct S {};
- union U {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('staticAssertDecl0')"><a name="staticAssertDecl0Anchor">staticAssertDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1StaticAssertDecl.html">StaticAssertDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="staticAssertDecl0"><pre>Matches a C++ static_assert declaration.
-
-Example:
- staticAssertExpr()
-matches
- static_assert(sizeof(S) == sizeof(int))
-in
- struct S {
- int x;
- };
- static_assert(sizeof(S) == sizeof(int));
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('templateTypeParmDecl0')"><a name="templateTypeParmDecl0Anchor">templateTypeParmDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmDecl.html">TemplateTypeParmDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="templateTypeParmDecl0"><pre>Matches template type parameter declarations.
-
-Given
- template <typename T, int N> struct C {};
-templateTypeParmDecl()
- matches 'T', but not 'N'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('translationUnitDecl0')"><a name="translationUnitDecl0Anchor">translationUnitDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">TranslationUnitDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="translationUnitDecl0"><pre>Matches the top declaration context.
-
-Given
- int X;
- namespace NS {
- int Y;
- } namespace NS
-decl(hasDeclContext(translationUnitDecl()))
- matches "int X", but not "int Y".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
-
-Given
- typedef int X;
-typedefDecl()
- matches "typedef int X"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('unresolvedUsingTypenameDecl0')"><a name="unresolvedUsingTypenameDecl0Anchor">unresolvedUsingTypenameDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingTypenameDecl.html">UnresolvedUsingTypenameDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="unresolvedUsingTypenameDecl0"><pre>Matches unresolved using value declarations that involve the
-typename.
-
-Given
- template <typename T>
- struct Base { typedef T Foo; };
-
- template<typename T>
- struct S : private Base<T> {
- using typename Base<T>::Foo;
- };
-unresolvedUsingTypenameDecl()
- matches using Base<T>::Foo </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('unresolvedUsingValueDecl0')"><a name="unresolvedUsingValueDecl0Anchor">unresolvedUsingValueDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingValueDecl.html">UnresolvedUsingValueDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="unresolvedUsingValueDecl0"><pre>Matches unresolved using value declarations.
-
-Given
- template<typename X>
- class C : private X {
- using X::x;
- };
-unresolvedUsingValueDecl()
- matches using X::x </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingDecl0')"><a name="usingDecl0Anchor">usingDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="usingDecl0"><pre>Matches using declarations.
-
-Given
- namespace X { int x; }
- using X::x;
-usingDecl()
- matches using X::x </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingDirectiveDecl0')"><a name="usingDirectiveDecl0Anchor">usingDirectiveDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDirectiveDecl.html">UsingDirectiveDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="usingDirectiveDecl0"><pre>Matches using namespace declarations.
-
-Given
- namespace X { int x; }
- using namespace X;
-usingDirectiveDecl()
- matches using namespace X </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('valueDecl0')"><a name="valueDecl0Anchor">valueDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="valueDecl0"><pre>Matches any value declaration.
-
-Example matches A, B, C and F
- enum X { A, B, C };
- void F();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('varDecl0')"><a name="varDecl0Anchor">varDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
-
-Note: this does not match declarations of member variables, which are
-"field" declarations in Clang parlance.
-
-Example matches a
- int a;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('nestedNameSpecifierLoc0')"><a name="nestedNameSpecifierLoc0Anchor">nestedNameSpecifierLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="nestedNameSpecifierLoc0"><pre>Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('nestedNameSpecifier0')"><a name="nestedNameSpecifier0Anchor">nestedNameSpecifier</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="nestedNameSpecifier0"><pre>Matches nested name specifiers.
-
-Given
- namespace ns {
- struct A { static void f(); };
- void A::f() {}
- void g() { A::f(); }
- }
- ns::A a;
-nestedNameSpecifier()
- matches "ns::" and both "A::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="qualType0"><pre>Matches QualTypes in the clang AST.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
-
-Given
- int i = a[1];
-arraySubscriptExpr()
- matches "a[1]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('asmStmt0')"><a name="asmStmt0Anchor">asmStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AsmStmt.html">AsmStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="asmStmt0"><pre>Matches asm statements.
-
- int i = 100;
- __asm("mov al, 2");
-asmStmt()
- matches '__asm("mov al, 2")'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
-
-Example matches a || b
- !(a || b)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('breakStmt0')"><a name="breakStmt0Anchor">breakStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BreakStmt.html">BreakStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="breakStmt0"><pre>Matches break statements.
-
-Given
- while (true) { break; }
-breakStmt()
- matches 'break'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cStyleCastExpr0')"><a name="cStyleCastExpr0Anchor">cStyleCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CStyleCastExpr.html">CStyleCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cStyleCastExpr0"><pre>Matches a C-style cast expression.
-
-Example: Matches (int*) 2.2f in
- int i = (int) 2.2f;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('callExpr0')"><a name="callExpr0Anchor">callExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
-
-Example matches x.y() and y()
- X x;
- x.y();
- y();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('caseStmt0')"><a name="caseStmt0Anchor">caseStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="caseStmt0"><pre>Matches case statements inside switch statements.
-
-Given
- switch(a) { case 42: break; default: break; }
-caseStmt()
- matches 'case 42: break;'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
-
-Example: castExpr() matches each of the following:
- (int) 3;
- const_cast<Expr *>(SubExpr);
- char c = 0;
-but does not match
- int i = (0);
- int k = 0;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('characterLiteral0')"><a name="characterLiteral0Anchor">characterLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="characterLiteral0"><pre>Matches character literals (also matches wchar_t).
-
-Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
-though.
-
-Example matches 'a', L'a'
- char ch = 'a'; wchar_t chw = L'a';
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundLiteralExpr0')"><a name="compoundLiteralExpr0Anchor">compoundLiteralExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals
-
-Example match: {1}, (1, 2)
- int array[4] = {1}; vector int myvec = (vector int)(1, 2);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundStmt0')"><a name="compoundStmt0Anchor">compoundStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="compoundStmt0"><pre>Matches compound statements.
-
-Example matches '{}' and '{{}}'in 'for (;;) {{}}'
- for (;;) {{}}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('conditionalOperator0')"><a name="conditionalOperator0Anchor">conditionalOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="conditionalOperator0"><pre>Matches conditional operator expressions.
-
-Example matches a ? b : c
- (a ? b : c) + 42
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('continueStmt0')"><a name="continueStmt0Anchor">continueStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ContinueStmt.html">ContinueStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="continueStmt0"><pre>Matches continue statements.
-
-Given
- while (true) { continue; }
-continueStmt()
- matches 'continue'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cudaKernelCallExpr0')"><a name="cudaKernelCallExpr0Anchor">cudaKernelCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CUDAKernelCallExpr.html">CUDAKernelCallExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cudaKernelCallExpr0"><pre>Matches CUDA kernel call expression.
-
-Example matches,
- kernel<<<i,j>>>();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxBindTemporaryExpr0')"><a name="cxxBindTemporaryExpr0Anchor">cxxBindTemporaryExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxBindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
-
-Example matches FunctionTakesString(GetStringByValue())
- (matcher = cxxBindTemporaryExpr())
- FunctionTakesString(GetStringByValue());
- FunctionTakesStringByPointer(GetStringPointer());
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxBoolLiteral0')"><a name="cxxBoolLiteral0Anchor">cxxBoolLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxBoolLiteral0"><pre>Matches bool literals.
-
-Example matches true
- true
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxCatchStmt0')"><a name="cxxCatchStmt0Anchor">cxxCatchStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxCatchStmt0"><pre>Matches catch statements.
-
- try {} catch(int i) {}
-cxxCatchStmt()
- matches 'catch(int i)'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstCastExpr0')"><a name="cxxConstCastExpr0Anchor">cxxConstCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxConstCastExpr0"><pre>Matches a const_cast expression.
-
-Example: Matches const_cast<int*>(&r) in
- int n = 42;
- const int &r(n);
- int* p = const_cast<int*>(&r);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstructExpr0')"><a name="cxxConstructExpr0Anchor">cxxConstructExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxConstructExpr0"><pre>Matches constructor call expressions (including implicit ones).
-
-Example matches string(ptr, n) and ptr within arguments of f
- (matcher = cxxConstructExpr())
- void f(const string &a, const string &b);
- char *ptr;
- int n;
- f(string(ptr, n), ptr);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDefaultArgExpr0')"><a name="cxxDefaultArgExpr0Anchor">cxxDefaultArgExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDefaultArgExpr.html">CXXDefaultArgExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxDefaultArgExpr0"><pre>Matches the value of a default argument at the call site.
-
-Example matches the CXXDefaultArgExpr placeholder inserted for the
- default value of the second parameter in the call expression f(42)
- (matcher = cxxDefaultArgExpr())
- void f(int x, int y = 0);
- f(42);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDeleteExpr0')"><a name="cxxDeleteExpr0Anchor">cxxDeleteExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDeleteExpr.html">CXXDeleteExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxDeleteExpr0"><pre>Matches delete expressions.
-
-Given
- delete X;
-cxxDeleteExpr()
- matches 'delete X'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDynamicCastExpr0')"><a name="cxxDynamicCastExpr0Anchor">cxxDynamicCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxDynamicCastExpr0"><pre>Matches a dynamic_cast expression.
-
-Example:
- cxxDynamicCastExpr()
-matches
- dynamic_cast<D*>(&b);
-in
- struct B { virtual ~B() {} }; struct D : B {};
- B b;
- D* p = dynamic_cast<D*>(&b);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxForRangeStmt0')"><a name="cxxForRangeStmt0Anchor">cxxForRangeStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxForRangeStmt0"><pre>Matches range-based for statements.
-
-cxxForRangeStmt() matches 'for (auto a : i)'
- int i[] = {1, 2, 3}; for (auto a : i);
- for(int j = 0; j < 5; ++j);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxFunctionalCastExpr0')"><a name="cxxFunctionalCastExpr0Anchor">cxxFunctionalCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxFunctionalCastExpr0"><pre>Matches functional cast expressions
-
-Example: Matches Foo(bar);
- Foo f = bar;
- Foo g = (Foo) bar;
- Foo h = Foo(bar);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxMemberCallExpr0')"><a name="cxxMemberCallExpr0Anchor">cxxMemberCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxMemberCallExpr0"><pre>Matches member call expressions.
-
-Example matches x.y()
- X x;
- x.y();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxNewExpr0')"><a name="cxxNewExpr0Anchor">cxxNewExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxNewExpr0"><pre>Matches new expressions.
-
-Given
- new X;
-cxxNewExpr()
- matches 'new X'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxNullPtrLiteralExpr0')"><a name="cxxNullPtrLiteralExpr0Anchor">cxxNullPtrLiteralExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNullPtrLiteralExpr.html">CXXNullPtrLiteralExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxNullPtrLiteralExpr0"><pre>Matches nullptr literal.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxOperatorCallExpr0')"><a name="cxxOperatorCallExpr0Anchor">cxxOperatorCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxOperatorCallExpr0"><pre>Matches overloaded operator calls.
-
-Note that if an operator isn't overloaded, it won't match. Instead, use
-binaryOperator matcher.
-Currently it does not match operators such as new delete.
-FIXME: figure out why these do not match?
-
-Example matches both operator<<((o << b), c) and operator<<(o, b)
- (matcher = cxxOperatorCallExpr())
- ostream &operator<< (ostream &out, int i) { };
- ostream &o; int b = 1, c = 1;
- o << b << c;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxReinterpretCastExpr0')"><a name="cxxReinterpretCastExpr0Anchor">cxxReinterpretCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxReinterpretCastExpr0"><pre>Matches a reinterpret_cast expression.
-
-Either the source expression or the destination type can be matched
-using has(), but hasDestinationType() is more specific and can be
-more readable.
-
-Example matches reinterpret_cast<char*>(&p) in
- void* p = reinterpret_cast<char*>(&p);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStaticCastExpr0')"><a name="cxxStaticCastExpr0Anchor">cxxStaticCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxStaticCastExpr0"><pre>Matches a C++ static_cast expression.
-
-hasDestinationType
-reinterpretCast
-
-Example:
- cxxStaticCastExpr()
-matches
- static_cast<long>(8)
-in
- long eight(static_cast<long>(8));
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
-
-Example: Matches Foo(bar, bar)
- Foo h = Foo(bar, bar);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThisExpr0')"><a name="cxxThisExpr0Anchor">cxxThisExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxThisExpr0"><pre>Matches implicit and explicit this expressions.
-
-Example matches the implicit this expression in "return i".
- (matcher = cxxThisExpr())
-struct foo {
- int i;
- int f() { return i; }
-};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThrowExpr0')"><a name="cxxThrowExpr0Anchor">cxxThrowExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThrowExpr.html">CXXThrowExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxThrowExpr0"><pre>Matches throw expressions.
-
- try { throw 5; } catch(int i) {}
-cxxThrowExpr()
- matches 'throw 5'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTryStmt0')"><a name="cxxTryStmt0Anchor">cxxTryStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTryStmt.html">CXXTryStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxTryStmt0"><pre>Matches try statements.
-
- try {} catch(int i) {}
-cxxTryStmt()
- matches 'try {}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxUnresolvedConstructExpr0')"><a name="cxxUnresolvedConstructExpr0Anchor">cxxUnresolvedConstructExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="cxxUnresolvedConstructExpr0"><pre>Matches unresolved constructor call expressions.
-
-Example matches T(t) in return statement of f
- (matcher = cxxUnresolvedConstructExpr())
- template <typename T>
- void f(const T& t) { return T(t); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('declRefExpr0')"><a name="declRefExpr0Anchor">declRefExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="declRefExpr0"><pre>Matches expressions that refer to declarations.
-
-Example matches x in if (x)
- bool x;
- if (x) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('declStmt0')"><a name="declStmt0Anchor">declStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="declStmt0"><pre>Matches declaration statements.
-
-Given
- int a;
-declStmt()
- matches 'int a'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('defaultStmt0')"><a name="defaultStmt0Anchor">defaultStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DefaultStmt.html">DefaultStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="defaultStmt0"><pre>Matches default statements inside switch statements.
-
-Given
- switch(a) { case 42: break; default: break; }
-defaultStmt()
- matches 'default: break;'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('doStmt0')"><a name="doStmt0Anchor">doStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="doStmt0"><pre>Matches do statements.
-
-Given
- do {} while (true);
-doStmt()
- matches 'do {} while(true)'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('explicitCastExpr0')"><a name="explicitCastExpr0Anchor">explicitCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="explicitCastExpr0"><pre>Matches explicit cast expressions.
-
-Matches any cast expression written in user code, whether it be a
-C-style cast, a functional-style cast, or a keyword cast.
-
-Does not match implicit conversions.
-
-Note: the name "explicitCast" is chosen to match Clang's terminology, as
-Clang uses the term "cast" to apply to implicit conversions as well as to
-actual cast expressions.
-
-hasDestinationType.
-
-Example: matches all five of the casts in
- int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
-but does not match the implicit conversion in
- long ell = 42;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('expr0')"><a name="expr0Anchor">expr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="expr0"><pre>Matches expressions.
-
-Example matches x()
- void f() { x(); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('exprWithCleanups0')"><a name="exprWithCleanups0Anchor">exprWithCleanups</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExprWithCleanups.html">ExprWithCleanups</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="exprWithCleanups0"><pre>Matches expressions that introduce cleanups to be run at the end
-of the sub-expression's evaluation.
-
-Example matches std::string()
- const std::string str = std::string();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('floatLiteral0')"><a name="floatLiteral0Anchor">floatLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes encodings, e.g.
-1.0, 1.0f, 1.0L and 1e10.
-
-Does not match implicit conversions such as
- float a = 10;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forStmt0')"><a name="forStmt0Anchor">forStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="forStmt0"><pre>Matches for statements.
-
-Example matches 'for (;;) {}'
- for (;;) {}
- int i[] = {1, 2, 3}; for (auto a : i);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('gnuNullExpr0')"><a name="gnuNullExpr0Anchor">gnuNullExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1GNUNullExpr.html">GNUNullExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="gnuNullExpr0"><pre>Matches GNU __null expression.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('gotoStmt0')"><a name="gotoStmt0Anchor">gotoStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1GotoStmt.html">GotoStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="gotoStmt0"><pre>Matches goto statements.
-
-Given
- goto FOO;
- FOO: bar();
-gotoStmt()
- matches 'goto FOO'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('ifStmt0')"><a name="ifStmt0Anchor">ifStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="ifStmt0"><pre>Matches if statements.
-
-Example matches 'if (x) {}'
- if (x) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('implicitCastExpr0')"><a name="implicitCastExpr0Anchor">implicitCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="implicitCastExpr0"><pre>Matches the implicit cast nodes of Clang's AST.
-
-This matches many different places, including function call return value
-eliding, as well as any type conversions.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('initListExpr0')"><a name="initListExpr0Anchor">initListExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="initListExpr0"><pre>Matches init list expressions.
-
-Given
- int a[] = { 1, 2 };
- struct B { int x, y; };
- B b = { 5, 6 };
-initListExpr()
- matches "{ 1, 2 }" and "{ 5, 6 }"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('integerLiteral0')"><a name="integerLiteral0Anchor">integerLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings, e.g.
-1, 1L, 0x1 and 1U.
-
-Does not match character-encoded integers such as L'a'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('labelStmt0')"><a name="labelStmt0Anchor">labelStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="labelStmt0"><pre>Matches label statements.
-
-Given
- goto FOO;
- FOO: bar();
-labelStmt()
- matches 'FOO:'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('lambdaExpr0')"><a name="lambdaExpr0Anchor">lambdaExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="lambdaExpr0"><pre>Matches lambda expressions.
-
-Example matches [&](){return 5;}
- [&](){return 5;}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('materializeTemporaryExpr0')"><a name="materializeTemporaryExpr0Anchor">materializeTemporaryExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MaterializeTemporaryExpr.html">MaterializeTemporaryExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
-
-Example: Given
- struct T {void func()};
- T f();
- void g(T);
-materializeTemporaryExpr() matches 'f()' in these statements
- T u(f());
- g(f());
-but does not match
- f();
- f().func();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('memberExpr0')"><a name="memberExpr0Anchor">memberExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="memberExpr0"><pre>Matches member expressions.
-
-Given
- class Y {
- void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
- int a; static int b;
- };
-memberExpr()
- matches this->x, x, y.x, a, this->b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('nullStmt0')"><a name="nullStmt0Anchor">nullStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NullStmt.html">NullStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="nullStmt0"><pre>Matches null statements.
-
- foo();;
-nullStmt()
- matches the second ';'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcMessageExpr0')"><a name="objcMessageExpr0Anchor">objcMessageExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="objcMessageExpr0"><pre>Matches ObjectiveC Message invocation expressions.
-
-The innermost message send invokes the "alloc" class method on the
-NSString class, while the outermost message send invokes the
-"initWithString" instance method on the object returned from
-NSString's "alloc". This matcher should match both message sends.
- [[NSString alloc] initWithString:@"Hello"]
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('returnStmt0')"><a name="returnStmt0Anchor">returnStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html">ReturnStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="returnStmt0"><pre>Matches return statements.
-
-Given
- return 1;
-returnStmt()
- matches 'return 1'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stmt0')"><a name="stmt0Anchor">stmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
-
-Given
- { ++a; }
-stmt()
- matches both the compound statement '{ ++a; }' and '++a'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
-
-Example matches "abcd", L"abcd"
- char *s = "abcd"; wchar_t *ws = L"abcd"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('substNonTypeTemplateParmExpr0')"><a name="substNonTypeTemplateParmExpr0Anchor">substNonTypeTemplateParmExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstNonTypeTemplateParmExpr.html">SubstNonTypeTemplateParmExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="substNonTypeTemplateParmExpr0"><pre>Matches substitutions of non-type template parameters.
-
-Given
- template <int N>
- struct A { static const int n = N; };
- struct B : public A<42> {};
-substNonTypeTemplateParmExpr()
- matches "N" in the right-hand side of "static const int n = N;"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
-
-Given
- switch(a) { case 42: break; default: break; }
-switchCase()
- matches 'case 42: break;' and 'default: break;'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('switchStmt0')"><a name="switchStmt0Anchor">switchStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="switchStmt0"><pre>Matches switch statements.
-
-Given
- switch(a) { case 42: break; default: break; }
-switchStmt()
- matches 'switch(a)'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('unaryExprOrTypeTraitExpr0')"><a name="unaryExprOrTypeTraitExpr0Anchor">unaryExprOrTypeTraitExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="unaryExprOrTypeTraitExpr0"><pre>Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
-
-Given
- Foo x = bar;
- int y = sizeof(x) + alignof(x);
-unaryExprOrTypeTraitExpr()
- matches sizeof(x) and alignof(x)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('unaryOperator0')"><a name="unaryOperator0Anchor">unaryOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="unaryOperator0"><pre>Matches unary operator expressions.
-
-Example matches !a
- !a || b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('userDefinedLiteral0')"><a name="userDefinedLiteral0Anchor">userDefinedLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UserDefinedLiteral.html">UserDefinedLiteral</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="userDefinedLiteral0"><pre>Matches user defined literal operator call.
-
-Example match: "foo"_suffix
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('whileStmt0')"><a name="whileStmt0Anchor">whileStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="whileStmt0"><pre>Matches while statements.
-
-Given
- while (true) {}
-whileStmt()
- matches 'while (true) {}'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="templateArgument0"><pre>Matches template arguments.
-
-Given
- template <typename T> struct C {};
- C<int> c;
-templateArgument()
- matches 'int' in C<int>.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('arrayType0')"><a name="arrayType0Anchor">arrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="arrayType0"><pre>Matches all kinds of arrays.
-
-Given
- int a[] = { 2, 3 };
- int b[4];
- void f() { int c[a[0]]; }
-arrayType()
- matches "int a[]", "int b[4]" and "int c[a[0]]";
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('atomicType0')"><a name="atomicType0Anchor">atomicType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="atomicType0"><pre>Matches atomic types.
-
-Given
- _Atomic(int) i;
-atomicType()
- matches "_Atomic(int) i"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('autoType0')"><a name="autoType0Anchor">autoType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="autoType0"><pre>Matches types nodes representing C++11 auto types.
-
-Given:
- auto n = 4;
- int v[] = { 2, 3 }
- for (auto i : v) { }
-autoType()
- matches "auto n" and "auto i"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('blockPointerType0')"><a name="blockPointerType0Anchor">blockPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="blockPointerType0"><pre>Matches block pointer types, i.e. types syntactically represented as
-"void (^)(int)".
-
-The pointee is always required to be a FunctionType.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('builtinType0')"><a name="builtinType0Anchor">builtinType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BuiltinType.html">BuiltinType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="builtinType0"><pre>Matches builtin Types.
-
-Given
- struct A {};
- A a;
- int b;
- float c;
- bool d;
-builtinType()
- matches "int b", "float c" and "bool d"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('complexType0')"><a name="complexType0Anchor">complexType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="complexType0"><pre>Matches C99 complex types.
-
-Given
- _Complex float f;
-complexType()
- matches "_Complex float f"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('constantArrayType0')"><a name="constantArrayType0Anchor">constantArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="constantArrayType0"><pre>Matches C arrays with a specified constant size.
-
-Given
- void() {
- int a[2];
- int b[] = { 2, 3 };
- int c[b[0]];
- }
-constantArrayType()
- matches "int a[2]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('decayedType0')"><a name="decayedType0Anchor">decayedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="decayedType0"><pre>Matches decayed type
-Example matches i[] in declaration of f.
- (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
-Example matches i[1].
- (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
- void f(int i[]) {
- i[1] = 0;
- }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('dependentSizedArrayType0')"><a name="dependentSizedArrayType0Anchor">dependentSizedArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DependentSizedArrayType.html">DependentSizedArrayType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="dependentSizedArrayType0"><pre>Matches C++ arrays whose size is a value-dependent expression.
-
-Given
- template<typename T, int Size>
- class array {
- T data[Size];
- };
-dependentSizedArrayType
- matches "T data[Size]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('elaboratedType0')"><a name="elaboratedType0Anchor">elaboratedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="elaboratedType0"><pre>Matches types specified with an elaborated type keyword or with a
-qualified name.
-
-Given
- namespace N {
- namespace M {
- class D {};
- }
- }
- class C {};
-
- class C c;
- N::M::D d;
-
-elaboratedType() matches the type of the variable declarations of both
-c and d.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('functionType0')"><a name="functionType0Anchor">functionType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionType.html">FunctionType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="functionType0"><pre>Matches FunctionType nodes.
-
-Given
- int (*f)(int);
- void g();
-functionType()
- matches "int (*f)(int)" and the type of "g".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('incompleteArrayType0')"><a name="incompleteArrayType0Anchor">incompleteArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IncompleteArrayType.html">IncompleteArrayType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="incompleteArrayType0"><pre>Matches C arrays with unspecified size.
-
-Given
- int a[] = { 2, 3 };
- int b[42];
- void f(int c[]) { int d[a[0]]; };
-incompleteArrayType()
- matches "int a[]" and "int c[]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('injectedClassNameType0')"><a name="injectedClassNameType0Anchor">injectedClassNameType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="injectedClassNameType0"><pre>Matches injected class name types.
-
-Example matches S s, but not S<T> s.
- (matcher = parmVarDecl(hasType(injectedClassNameType())))
- template <typename T> struct S {
- void f(S s);
- void g(S<T> s);
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('lValueReferenceType0')"><a name="lValueReferenceType0Anchor">lValueReferenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceType.html">LValueReferenceType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="lValueReferenceType0"><pre>Matches lvalue reference types.
-
-Given:
- int *a;
- int &b = *a;
- int &&c = 1;
- auto &d = b;
- auto &&e = c;
- auto &&f = 2;
- int g = 5;
-
-lValueReferenceType() matches the types of b, d, and e. e is
-matched since the type is deduced as int& by reference collapsing rules.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('memberPointerType0')"><a name="memberPointerType0Anchor">memberPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="memberPointerType0"><pre>Matches member pointer types.
-Given
- struct A { int i; }
- A::* ptr = A::i;
-memberPointerType()
- matches "A::* ptr"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('objcObjectPointerType0')"><a name="objcObjectPointerType0Anchor">objcObjectPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCObjectPointerType.html">ObjCObjectPointerType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="objcObjectPointerType0"><pre>Matches an Objective-C object pointer type, which is different from
-a pointer type, despite being syntactically similar.
-
-Given
- int *a;
-
- @interface Foo
- @end
- Foo *f;
-pointerType()
- matches "Foo *f", but does not match "int *a".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('parenType0')"><a name="parenType0Anchor">parenType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="parenType0"><pre>Matches ParenType nodes.
-
-Given
- int (*ptr_to_array)[4];
- int *array_of_ptrs[4];
-
-varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
-array_of_ptrs.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('pointerType0')"><a name="pointerType0Anchor">pointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="pointerType0"><pre>Matches pointer types, but does not match Objective-C object pointer
-types.
-
-Given
- int *a;
- int &b = *a;
- int c = 5;
-
- @interface Foo
- @end
- Foo *f;
-pointerType()
- matches "int *a", but does not match "Foo *f".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('rValueReferenceType0')"><a name="rValueReferenceType0Anchor">rValueReferenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceType.html">RValueReferenceType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="rValueReferenceType0"><pre>Matches rvalue reference types.
-
-Given:
- int *a;
- int &b = *a;
- int &&c = 1;
- auto &d = b;
- auto &&e = c;
- auto &&f = 2;
- int g = 5;
-
-rValueReferenceType() matches the types of c and f. e is not
-matched as it is deduced to int& by reference collapsing rules.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('recordType0')"><a name="recordType0Anchor">recordType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="recordType0"><pre>Matches record types (e.g. structs, classes).
-
-Given
- class C {};
- struct S {};
-
- C c;
- S s;
-
-recordType() matches the type of the variable declarations of both c
-and s.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('referenceType0')"><a name="referenceType0Anchor">referenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches both lvalue and rvalue reference types.
-
-Given
- int *a;
- int &b = *a;
- int &&c = 1;
- auto &d = b;
- auto &&e = c;
- auto &&f = 2;
- int g = 5;
-
-referenceType() matches the types of b, c, d, e, and f.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('substTemplateTypeParmType0')"><a name="substTemplateTypeParmType0Anchor">substTemplateTypeParmType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstTemplateTypeParmType.html">SubstTemplateTypeParmType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="substTemplateTypeParmType0"><pre>Matches types that represent the result of substituting a type for a
-template type parameter.
-
-Given
- template <typename T>
- void F(T t) {
- int i = 1 + t;
- }
-
-substTemplateTypeParmType() matches the type of 't' but not '1'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('templateSpecializationType0')"><a name="templateSpecializationType0Anchor">templateSpecializationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="templateSpecializationType0"><pre>Matches template specialization types.
-
-Given
- template <typename T>
- class C { };
-
- template class C<int>; A
- C<char> var; B
-
-templateSpecializationType() matches the type of the explicit
-instantiation in A and the type of the variable declaration in B.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('templateTypeParmType0')"><a name="templateTypeParmType0Anchor">templateTypeParmType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="templateTypeParmType0"><pre>Matches template type parameter types.
-
-Example matches T, but not int.
- (matcher = templateTypeParmType())
- template <typename T> void f(int i);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('type0')"><a name="type0Anchor">type</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="type0"><pre>Matches Types in the clang AST.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('typedefType0')"><a name="typedefType0Anchor">typedefType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="typedefType0"><pre>Matches typedef types.
-
-Given
- typedef int X;
-typedefType()
- matches "typedef int X"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('unaryTransformType0')"><a name="unaryTransformType0Anchor">unaryTransformType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryTransformType.html">UnaryTransformType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="unaryTransformType0"><pre>Matches types nodes representing unary type transformations.
-
-Given:
- typedef __underlying_type(T) type;
-unaryTransformType()
- matches "__underlying_type(T)"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('variableArrayType0')"><a name="variableArrayType0Anchor">variableArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>>...</td></tr>
-<tr><td colspan="4" class="doc" id="variableArrayType0"><pre>Matches C arrays with a specified size that is not an
-integer-constant-expression.
-
-Given
- void f() {
- int a[] = { 2, 3 }
- int b[42];
- int c[a[0]];
- }
-variableArrayType()
- matches "int c[a[0]]"
-</pre></td></tr>
-
-<!--END_DECL_MATCHERS -->
-</table>
-
-<!-- ======================================================================= -->
-<h2 id="narrowing-matchers">Narrowing Matchers</h2>
-<!-- ======================================================================= -->
-
-<p>Narrowing matchers match certain attributes on the current node, thus
-narrowing down the set of nodes of the current type to match on.</p>
-
-<p>There are special logical narrowing matchers (allOf, anyOf, anything and unless)
-which allow users to create more powerful match expressions.</p>
-
-<table>
-<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
-<!-- START_NARROWING_MATCHERS -->
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('allOf0')"><a name="allOf0Anchor">allOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="allOf0"><pre>Matches if all given matchers match.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('anyOf0')"><a name="anyOf0Anchor">anyOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="anyOf0"><pre>Matches if any of the given matchers matches.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('anything0')"><a name="anything0Anchor">anything</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="anything0"><pre>Matches any node.
-
-Useful when another matcher requires a child matcher, but there's no
-additional constraint. This will often be used with an explicit conversion
-to an internal::Matcher<> type such as TypeMatcher.
-
-Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
-"int* p" and "void f()" in
- int* p;
- void f();
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('unless0')"><a name="unless0Anchor">unless</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="unless0"><pre>Matches if the provided matcher does not match.
-
-Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
- class X {};
- class Y {};
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName0')"><a name="hasOperatorName0Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions (binary or
-unary).
-
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
-</pre></td></tr>
-
-
-<tr><td>Matcher<CXXBoolLiteral></td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value.
-
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>></td><td class="name" onclick="toggle('isCatchAll0')"><a name="isCatchAll0Anchor">isCatchAll</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isCatchAll0"><pre>Matches a C++ catch statement that has a catch-all handler.
-
-Given
- try {
- ...
- } catch (int) {
- ...
- } catch (...) {
- ...
- }
-endcode
-cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs1')"><a name="argumentCountIs1Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has
-a specific number of arguments (including absent default arguments).
-
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
- void f(int x, int y);
- f(0, 0);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('isListInitialization0')"><a name="isListInitialization0Anchor">isListInitialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isListInitialization0"><pre>Matches a constructor call expression which uses list initialization.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isCopyConstructor0')"><a name="isCopyConstructor0Anchor">isCopyConstructor</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isCopyConstructor0"><pre>Matches constructor declarations that are copy constructors.
-
-Given
- struct S {
- S(); #1
- S(const S &); #2
- S(S &&); #3
- };
-cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isDefaultConstructor0')"><a name="isDefaultConstructor0Anchor">isDefaultConstructor</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefaultConstructor0"><pre>Matches constructor declarations that are default constructors.
-
-Given
- struct S {
- S(); #1
- S(const S &); #2
- S(S &&); #3
- };
-cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isExplicit0')"><a name="isExplicit0Anchor">isExplicit</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor and conversion declarations that are marked with
-the explicit keyword.
-
-Given
- struct S {
- S(int); #1
- explicit S(double); #2
- operator int(); #3
- explicit operator bool(); #4
- };
-cxxConstructorDecl(isExplicit()) will match #2, but not #1.
-cxxConversionDecl(isExplicit()) will match #4, but not #3.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isMoveConstructor0')"><a name="isMoveConstructor0Anchor">isMoveConstructor</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isMoveConstructor0"><pre>Matches constructor declarations that are move constructors.
-
-Given
- struct S {
- S(); #1
- S(const S &); #2
- S(S &&); #3
- };
-cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>></td><td class="name" onclick="toggle('isExplicit1')"><a name="isExplicit1Anchor">isExplicit</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicit1"><pre>Matches constructor and conversion declarations that are marked with
-the explicit keyword.
-
-Given
- struct S {
- S(int); #1
- explicit S(double); #2
- operator int(); #3
- explicit operator bool(); #4
- };
-cxxConstructorDecl(isExplicit()) will match #2, but not #1.
-cxxConversionDecl(isExplicit()) will match #4, but not #3.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isBaseInitializer0')"><a name="isBaseInitializer0Anchor">isBaseInitializer</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isBaseInitializer0"><pre>Matches a constructor initializer if it is initializing a base, as
-opposed to a member.
-
-Given
- struct B {};
- struct D : B {
- int I;
- D(int i) : I(i) {}
- };
- struct E : B {
- E() : B() {}
- };
-cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer()))
- will match E(), but not match D(int).
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isMemberInitializer0')"><a name="isMemberInitializer0Anchor">isMemberInitializer</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isMemberInitializer0"><pre>Matches a constructor initializer if it is initializing a member, as
-opposed to a base.
-
-Given
- struct B {};
- struct D : B {
- int I;
- D(int i) : I(i) {}
- };
- struct E : B {
- E() : B() {}
- };
-cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer()))
- will match D(int), but not match E().
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isWritten0')"><a name="isWritten0Anchor">isWritten</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isWritten0"><pre>Matches a constructor initializer if it is explicitly written in
-code (as opposed to implicitly added by the compiler).
-
-Given
- struct Foo {
- Foo() { }
- Foo(int) : foo_("A") { }
- string foo_;
- };
-cxxConstructorDecl(hasAnyConstructorInitializer(isWritten()))
- will match Foo(int), but not Foo()
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
-
-Given
-struct A {
- void foo() const;
- void bar();
-};
-
-cxxMethodDecl(isConst()) matches A::foo() but not A::bar()
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isFinal1')"><a name="isFinal1Anchor">isFinal</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isFinal1"><pre>Matches if the given method or class declaration is final.
-
-Given:
- class A final {};
-
- struct B {
- virtual void f();
- };
-
- struct C : B {
- void f() final;
- };
-matches A and C::f, but not B, C, or B::f
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isOverride0')"><a name="isOverride0Anchor">isOverride</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isOverride0"><pre>Matches if the given method declaration overrides another method.
-
-Given
- class A {
- public:
- virtual void x();
- };
- class B : public A {
- public:
- virtual void x();
- };
- matches B::x
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isPure0')"><a name="isPure0Anchor">isPure</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isPure0"><pre>Matches if the given method declaration is pure.
-
-Given
- class A {
- public:
- virtual void x() = 0;
- };
- matches A::x
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isVirtual0')"><a name="isVirtual0Anchor">isVirtual</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isVirtual0"><pre>Matches if the given method declaration is virtual.
-
-Given
- class A {
- public:
- virtual void x();
- };
- matches A::x
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
-
-Matches overloaded operator names specified in strings without the
-"operator" prefix: e.g. "<<".
-
-Given:
- class A { int operator*(); };
- const A &operator<<(const A &a, const A &b);
- A a;
- a << a; <-- This matches
-
-cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
-specified line and
-cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
-matches the declaration of A.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
-static member variable template instantiations.
-
-Given
- template<typename T> void A(T t) { }
- template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isFinal0')"><a name="isFinal0Anchor">isFinal</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isFinal0"><pre>Matches if the given method or class declaration is final.
-
-Given:
- class A final {};
-
- struct B {
- virtual void f();
- };
-
- struct C : B {
- void f() final;
- };
-matches A and C::f, but not B, C, or B::f
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for
-isSameOrDerivedFrom(hasName(...)).
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static
-member variable template instantiations.
-
-Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
-
-But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- does not match, as X<A> is an explicit template specialization.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('argumentCountIs0')"><a name="argumentCountIs0Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="argumentCountIs0"><pre>Checks that a call expression or a constructor call expression has
-a specific number of arguments (including absent default arguments).
-
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
- void f(int x, int y);
- f(0, 0);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals3')"><a name="equals3Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value.
-
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('templateArgumentCountIs0')"><a name="templateArgumentCountIs0Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="templateArgumentCountIs0"><pre>Matches if the number of template arguments equals N.
-
-Given
- template<typename T> struct C {};
- C<int> c;
-classTemplateSpecializationDecl(templateArgumentCountIs(1))
- matches C<int>.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>></td><td class="name" onclick="toggle('statementCountIs0')"><a name="statementCountIs0Anchor">statementCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="statementCountIs0"><pre>Checks that a compound statement contains a specific number of
-child statements.
-
-Example: Given
- { for (;;) {} }
-compoundStmt(statementCountIs(0)))
- matches '{}'
- but does not match the outer compound statement.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>></td><td class="name" onclick="toggle('hasSize0')"><a name="hasSize0Anchor">hasSize</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="hasSize0"><pre>Matches ConstantArrayType nodes that have the specified size.
-
-Given
- int a[42];
- int b[2 * 21];
- int c[41], d[43];
-constantArrayType(hasSize(42))
- matches "int a[42]" and "int b[2 * 21]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('declCountIs0')"><a name="declCountIs0Anchor">declCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="declCountIs0"><pre>Matches declaration statements that contain a specific number of
-declarations.
-
-Example: Given
- int a, b;
- int c;
- int d = 2, e;
-declCountIs(2)
- matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('equalsBoundNode1')"><a name="equalsBoundNode1Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
-<tr><td colspan="4" class="doc" id="equalsBoundNode1"><pre>Matches if a node equals a previously bound node.
-
-Matches a node if it equals the node previously bound to ID.
-
-Given
- class X { int a; int b; };
-cxxRecordDecl(
- has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
- has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
-
-Note that when multiple matches are involved via forEach* matchers,
-equalsBoundNodes acts as a filter.
-For example:
-compoundStmt(
- forEachDescendant(varDecl().bind("d")),
- forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
-will trigger a match for each combination of variable declaration
-and reference to that variable declaration within a compound statement.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasAttr0')"><a name="hasAttr0Anchor">hasAttr</a></td><td>attr::Kind AttrKind</td></tr>
-<tr><td colspan="4" class="doc" id="hasAttr0"><pre>Matches declaration that has a given attribute.
-
-Given
- __attribute__((device)) void f() { ... }
-decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
-f. If the matcher is use from clang-query, attr::Kind parameter should be
-passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching0')"><a name="isExpansionInFileMatching0Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInFileMatching0"><pre>Matches AST nodes that were expanded within files whose name is
-partially matching a given regex.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInMainFile0')"><a name="isExpansionInMainFile0Anchor">isExpansionInMainFile</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInMainFile0"><pre>Matches AST nodes that were expanded within the main-file.
-
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader0')"><a name="isExpansionInSystemHeader0Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader0"><pre>Matches AST nodes that were expanded within system-header-files.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
- #include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches a declaration that has been implicitly added
-by the compiler (eg. implicit defaultcopy constructors).
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
-
-Given
- class C {
- public: int a;
- protected: int b;
- private: int c;
- };
-fieldDecl(isPrivate())
- matches 'int c;'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isProtected0')"><a name="isProtected0Anchor">isProtected</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isProtected0"><pre>Matches protected C++ declarations.
-
-Given
- class C {
- public: int a;
- protected: int b;
- private: int c;
- };
-fieldDecl(isProtected())
- matches 'int b;'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isPublic0')"><a name="isPublic0Anchor">isPublic</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isPublic0"><pre>Matches public C++ declarations.
-
-Given
- class C {
- public: int a;
- protected: int b;
- private: int c;
- };
-fieldDecl(isPublic())
- matches 'int a;'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>></td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
-
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
-
-Matches overloaded operator names specified in strings without the
-"operator" prefix: e.g. "<<".
-
-Given:
- class A { int operator*(); };
- const A &operator<<(const A &a, const A &b);
- A a;
- a << a; <-- This matches
-
-cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
-specified line and
-cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
-matches the declaration of A.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isConstexpr1')"><a name="isConstexpr1Anchor">isConstexpr</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isConstexpr1"><pre>Matches constexpr variable and function declarations.
-
-Given:
- constexpr int foo = 42;
- constexpr int bar();
-varDecl(isConstexpr())
- matches the declaration of foo.
-functionDecl(isConstexpr())
- matches the declaration of bar.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
-
-Example matches A, va, fa
- class A {};
- class B; Doesn't match, as it has no body.
- int va;
- extern int vb; Doesn't match, as it doesn't define the variable.
- void fa() {}
- void fb(); Doesn't match, as it has no body.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDeleted0')"><a name="isDeleted0Anchor">isDeleted</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDeleted0"><pre>Matches deleted function declarations.
-
-Given:
- void Func();
- void DeletedFunc() = delete;
-functionDecl(isDeleted())
- matches the declaration of DeletedFunc, but not Func.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
-static member variable template instantiations.
-
-Given
- template<typename T> void A(T t) { }
- template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function declarations.
-
-Given:
- extern "C" void f() {}
- extern "C" { void g() {} }
- void h() {}
-functionDecl(isExternC())
- matches the declaration of f and g, but not the declaration h
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isInline1')"><a name="isInline1Anchor">isInline</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isInline1"><pre>Matches function and namespace declarations that are marked with
-the inline keyword.
-
-Given
- inline void f();
- void g();
- namespace n {
- inline namespace m {}
- }
-functionDecl(isInline()) will match ::f().
-namespaceDecl(isInline()) will match n::m.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation0')"><a name="isTemplateInstantiation0Anchor">isTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isTemplateInstantiation0"><pre>Matches template instantiations of function, class, or static
-member variable template instantiations.
-
-Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
-
-But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- does not match, as X<A> is an explicit template specialization.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isVariadic0')"><a name="isVariadic0Anchor">isVariadic</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isVariadic0"><pre>Matches if a function declaration is variadic.
-
-Example matches f, but not g or h. The function i will not match, even when
-compiled in C mode.
- void f(...);
- void g(int);
- template <typename... Ts> void h(Ts...);
- void i();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('parameterCountIs0')"><a name="parameterCountIs0Anchor">parameterCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="parameterCountIs0"><pre>Matches FunctionDecls that have a specific parameter count.
-
-Given
- void f(int i) {}
- void g(int i, int j) {}
-functionDecl(parameterCountIs(2))
- matches g(int i, int j) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
-
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '->' as opposed
-to '.'.
-
-Member calls on the implicit this pointer match as called with '->'.
-
-Given
- class Y {
- void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
- int a;
- static int b;
- };
-memberExpr(isArrow())
- matches this->x, x, y.x, a, this->b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('hasName0')"><a name="hasName0Anchor">hasName</a></td><td>std::string Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasName0"><pre>Matches NamedDecl nodes that have the specified name.
-
-Supports specifying enclosing namespaces or classes by prefixing the name
-with '<enclosing>::'.
-Does not match typedefs of an underlying type with the given name.
-
-Example matches X (Name == "X")
- class X;
-
-Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
- namespace a { namespace b { class X; } }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose fully qualified names contain
-a substring matched by the given RegExp.
-
-Supports specifying enclosing namespaces or classes by
-prefixing the name with '<enclosing>::'. Does not match typedefs
-of an underlying type with the given name.
-
-Example matches X (regexp == "::X")
- class X;
-
-Example matches X (regexp is one of "::X", "^foo::.*X", among others)
- namespace foo { namespace bar { class X; } }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>></td><td class="name" onclick="toggle('isAnonymous0')"><a name="isAnonymous0Anchor">isAnonymous</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isAnonymous0"><pre>Matches anonymous namespace declarations.
-
-Given
- namespace n {
- namespace {} #1
- }
-namespaceDecl(isAnonymous()) will match #1 but not ::n.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>></td><td class="name" onclick="toggle('isInline0')"><a name="isInline0Anchor">isInline</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isInline0"><pre>Matches function and namespace declarations that are marked with
-the inline keyword.
-
-Given
- inline void f();
- void g();
- namespace n {
- inline namespace m {}
- }
-functionDecl(isInline()) will match ::f().
-namespaceDecl(isInline()) will match n::m.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has
-a specific number of arguments (including absent default arguments).
-
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
- void f(int x, int y);
- f(0, 0);
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasKeywordSelector0')"><a name="hasKeywordSelector0Anchor">hasKeywordSelector</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasKeywordSelector0"><pre>Matches when the selector is a keyword selector
-
-objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
-message expression in
-
- UIWebView *webView = ...;
- CGRect bodyFrame = webView.frame;
- bodyFrame.size.height = self.bodyContentHeight;
- webView.frame = bodyFrame;
- ^---- matches here
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasNullSelector0')"><a name="hasNullSelector0Anchor">hasNullSelector</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasNullSelector0"><pre>Matches when the selector is the empty selector
-
-Matches only when the selector of the objCMessageExpr is NULL. This may
-represent an error condition in the tree!
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasSelector0')"><a name="hasSelector0Anchor">hasSelector</a></td><td>std::string BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="hasSelector0"><pre>Matches when BaseName == Selector.getAsString()
-
- matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
- matches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
- [self.bodyView loadHTMLString:html baseURL:NULL];
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasUnarySelector0')"><a name="hasUnarySelector0Anchor">hasUnarySelector</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasUnarySelector0"><pre>Matches when the selector is a Unary Selector
-
- matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
- matches self.bodyView in the code below, but NOT the outer message
- invocation of "loadHTMLString:baseURL:".
- [self.bodyView loadHTMLString:html baseURL:NULL];
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="matchesSelector0"><pre>Matches ObjC selectors whose name contains
-a substring matched by the given RegExp.
- matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
- [self.bodyView loadHTMLString:html baseURL:NULL];
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('numSelectorArgs0')"><a name="numSelectorArgs0Anchor">numSelectorArgs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="numSelectorArgs0"><pre>Matches when the selector has the specified number of arguments
-
- matcher = objCMessageExpr(numSelectorArgs(0));
- matches self.bodyView in the code below
-
- matcher = objCMessageExpr(numSelectorArgs(2));
- matches the invocation of "loadHTMLString:baseURL:" but not that
- of self.bodyView
- [self.bodyView loadHTMLString:html baseURL:NULL];
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('asString0')"><a name="asString0Anchor">asString</a></td><td>std::string Name</td></tr>
-<tr><td colspan="4" class="doc" id="asString0"><pre>Matches if the matched type is represented by the given string.
-
-Given
- class Y { public: void x(); };
- void z() { Y* y; y->x(); }
-cxxMemberCallExpr(on(hasType(asString("class Y *"))))
- matches y->x()
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('equalsBoundNode3')"><a name="equalsBoundNode3Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
-<tr><td colspan="4" class="doc" id="equalsBoundNode3"><pre>Matches if a node equals a previously bound node.
-
-Matches a node if it equals the node previously bound to ID.
-
-Given
- class X { int a; int b; };
-cxxRecordDecl(
- has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
- has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
-
-Note that when multiple matches are involved via forEach* matchers,
-equalsBoundNodes acts as a filter.
-For example:
-compoundStmt(
- forEachDescendant(varDecl().bind("d")),
- forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
-will trigger a match for each combination of variable declaration
-and reference to that variable declaration within a compound statement.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasLocalQualifiers0')"><a name="hasLocalQualifiers0Anchor">hasLocalQualifiers</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasLocalQualifiers0"><pre>Matches QualType nodes that have local CV-qualifiers attached to
-the node, not hidden within a typedef.
-
-Given
- typedef const int const_int;
- const_int i;
- int *const j;
- int *volatile k;
- int m;
-varDecl(hasType(hasLocalQualifiers())) matches only j and k.
-i is const-qualified but the qualifier is not local.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isConstQualified0')"><a name="isConstQualified0Anchor">isConstQualified</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isConstQualified0"><pre>Matches QualType nodes that are const-qualified, i.e., that
-include "top-level" const.
-
-Given
- void a(int);
- void b(int const);
- void c(const int);
- void d(const int*);
- void e(int const) {};
-functionDecl(hasAnyParameter(hasType(isConstQualified())))
- matches "void b(int const)", "void c(const int)" and
- "void e(int const) {}". It does not match d as there
- is no top-level const on the parameter type "const int *".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isInteger0')"><a name="isInteger0Anchor">isInteger</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isInteger0"><pre>Matches QualType nodes that are of integer type.
-
-Given
- void a(int);
- void b(long);
- void c(double);
-functionDecl(hasAnyParameter(hasType(isInteger())))
-matches "a(int)", "b(long)", but not "c(double)".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isClass0')"><a name="isClass0Anchor">isClass</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isClass0"><pre>Matches RecordDecl object that are spelled with "class."
-
-Example matches C, but not S or U.
- struct S {};
- class C {};
- union U {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isStruct0')"><a name="isStruct0Anchor">isStruct</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isStruct0"><pre>Matches RecordDecl object that are spelled with "struct."
-
-Example matches S, but not C or U.
- struct S {};
- class C {};
- union U {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isUnion0')"><a name="isUnion0Anchor">isUnion</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isUnion0"><pre>Matches RecordDecl object that are spelled with "union."
-
-Example matches U, but not C or S.
- struct S {};
- class C {};
- union U {};
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('equalsBoundNode0')"><a name="equalsBoundNode0Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
-<tr><td colspan="4" class="doc" id="equalsBoundNode0"><pre>Matches if a node equals a previously bound node.
-
-Matches a node if it equals the node previously bound to ID.
-
-Given
- class X { int a; int b; };
-cxxRecordDecl(
- has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
- has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
-
-Note that when multiple matches are involved via forEach* matchers,
-equalsBoundNodes acts as a filter.
-For example:
-compoundStmt(
- forEachDescendant(varDecl().bind("d")),
- forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
-will trigger a match for each combination of variable declaration
-and reference to that variable declaration within a compound statement.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching1')"><a name="isExpansionInFileMatching1Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInFileMatching1"><pre>Matches AST nodes that were expanded within files whose name is
-partially matching a given regex.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInMainFile1')"><a name="isExpansionInMainFile1Anchor">isExpansionInMainFile</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInMainFile1"><pre>Matches AST nodes that were expanded within the main-file.
-
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader1')"><a name="isExpansionInSystemHeader1Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader1"><pre>Matches AST nodes that were expanded within system-header-files.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
- #include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
-
-Example matches A, va, fa
- class A {};
- class B; Doesn't match, as it has no body.
- int va;
- extern int vb; Doesn't match, as it doesn't define the variable.
- void fa() {}
- void fb(); Doesn't match, as it has no body.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('equalsIntegralValue0')"><a name="equalsIntegralValue0Anchor">equalsIntegralValue</a></td><td>std::string Value</td></tr>
-<tr><td colspan="4" class="doc" id="equalsIntegralValue0"><pre>Matches a TemplateArgument of integral type with a given value.
-
-Note that 'Value' is a string as the template argument's value is
-an arbitrary precision integer. 'Value' must be euqal to the canonical
-representation of that integral value in base 10.
-
-Given
- template<int T> struct A {};
- C<42> c;
-classTemplateSpecializationDecl(
- hasAnyTemplateArgument(equalsIntegralValue("42")))
- matches the implicit instantiation of C in C<42>.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('isIntegral0')"><a name="isIntegral0Anchor">isIntegral</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isIntegral0"><pre>Matches a TemplateArgument that is an integral value.
-
-Given
- template<int T> struct A {};
- C<42> c;
-classTemplateSpecializationDecl(
- hasAnyTemplateArgument(isIntegral()))
- matches the implicit instantiation of C in C<42>
- with isIntegral() matching 42.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('templateArgumentCountIs1')"><a name="templateArgumentCountIs1Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="templateArgumentCountIs1"><pre>Matches if the number of template arguments equals N.
-
-Given
- template<typename T> struct C {};
- C<int> c;
-classTemplateSpecializationDecl(templateArgumentCountIs(1))
- matches C<int>.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching2')"><a name="isExpansionInFileMatching2Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInFileMatching2"><pre>Matches AST nodes that were expanded within files whose name is
-partially matching a given regex.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
- #include "ASTMatcher.h"
- class X {};
-ASTMatcher.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInMainFile2')"><a name="isExpansionInMainFile2Anchor">isExpansionInMainFile</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInMainFile2"><pre>Matches AST nodes that were expanded within the main-file.
-
-Example matches X but not Y
- (matcher = cxxRecordDecl(isExpansionInMainFile())
- #include <Y.h>
- class X {};
-Y.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader2')"><a name="isExpansionInSystemHeader2Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader2"><pre>Matches AST nodes that were expanded within system-header-files.
-
-Example matches Y but not X
- (matcher = cxxRecordDecl(isExpansionInSystemHeader())
- #include <SystemHeader.h>
- class X {};
-SystemHeader.h:
- class Y {};
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('equalsBoundNode2')"><a name="equalsBoundNode2Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
-<tr><td colspan="4" class="doc" id="equalsBoundNode2"><pre>Matches if a node equals a previously bound node.
-
-Matches a node if it equals the node previously bound to ID.
-
-Given
- class X { int a; int b; };
-cxxRecordDecl(
- has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
- has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
- matches the class X, as a and b have the same type.
-
-Note that when multiple matches are involved via forEach* matchers,
-equalsBoundNodes acts as a filter.
-For example:
-compoundStmt(
- forEachDescendant(varDecl().bind("d")),
- forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
-will trigger a match for each combination of variable declaration
-and reference to that variable declaration within a compound statement.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('voidType0')"><a name="voidType0Anchor">voidType</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="voidType0"><pre>Matches type void.
-
-Given
- struct S { void func(); };
-functionDecl(returns(voidType()))
- matches "void func();"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>></td><td class="name" onclick="toggle('ofKind0')"><a name="ofKind0Anchor">ofKind</a></td><td>UnaryExprOrTypeTrait Kind</td></tr>
-<tr><td colspan="4" class="doc" id="ofKind0"><pre>Matches unary expressions of a certain kind.
-
-Given
- int x;
- int s = sizeof(x) + alignof(x)
-unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
- matches sizeof(x)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName1')"><a name="hasOperatorName1Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
-<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions (binary or
-unary).
-
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
- !(a || b)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasGlobalStorage0')"><a name="hasGlobalStorage0Anchor">hasGlobalStorage</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasGlobalStorage0"><pre>Matches a variable declaration that does not have local storage.
-
-Example matches y and z (matcher = varDecl(hasGlobalStorage())
-void f() {
- int x;
- static int y;
-}
-int z;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasLocalStorage0')"><a name="hasLocalStorage0Anchor">hasLocalStorage</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="hasLocalStorage0"><pre>Matches a variable declaration that has function scope and is a
-non-static local variable.
-
-Example matches x (matcher = varDecl(hasLocalStorage())
-void f() {
- int x;
- static int y;
-}
-int z;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isConstexpr0')"><a name="isConstexpr0Anchor">isConstexpr</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isConstexpr0"><pre>Matches constexpr variable and function declarations.
-
-Given:
- constexpr int foo = 42;
- constexpr int bar();
-varDecl(isConstexpr())
- matches the declaration of foo.
-functionDecl(isConstexpr())
- matches the declaration of bar.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isDefinition1')"><a name="isDefinition1Anchor">isDefinition</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefinition1"><pre>Matches if a declaration has a body attached.
-
-Example matches A, va, fa
- class A {};
- class B; Doesn't match, as it has no body.
- int va;
- extern int vb; Doesn't match, as it doesn't define the variable.
- void fa() {}
- void fb(); Doesn't match, as it has no body.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isExceptionVariable0')"><a name="isExceptionVariable0Anchor">isExceptionVariable</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExceptionVariable0"><pre>Matches a variable declaration that is an exception variable from
-a C++ catch block, or an Objective-C statement.
-
-Example matches x (matcher = varDecl(isExceptionVariable())
-void f(int y) {
- try {
- } catch (int x) {
- }
-}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization1')"><a name="isExplicitTemplateSpecialization1Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization1"><pre>Matches explicit template specializations of function, class, or
-static member variable template instantiations.
-
-Given
- template<typename T> void A(T t) { }
- template<> void A(int N) { }
-functionDecl(isExplicitTemplateSpecialization())
- matches the specialization A<int>().
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation1')"><a name="isTemplateInstantiation1Anchor">isTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isTemplateInstantiation1"><pre>Matches template instantiations of function, class, or static
-member variable template instantiations.
-
-Given
- template <typename T> class X {}; class A {}; X<A> x;
-or
- template <typename T> class X {}; class A {}; template class X<A>;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- matches the template instantiation of X<A>.
-
-But given
- template <typename T> class X {}; class A {};
- template <> class X<A> {}; X<A> x;
-cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
- does not match, as X<A> is an explicit template specialization.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>></td><td class="name" onclick="toggle('isInstantiated0')"><a name="isInstantiated0Anchor">isInstantiated</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isInstantiated0"><pre>Matches declarations that are template instantiations or are inside
-template instantiations.
-
-Given
- template<typename T> void A(T t) { T i; }
- A(0);
- A(0U);
-functionDecl(isInstantiated())
- matches 'A(int) {...};' and 'A(unsigned) {...}'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>></td><td class="name" onclick="toggle('isInTemplateInstantiation0')"><a name="isInTemplateInstantiation0Anchor">isInTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isInTemplateInstantiation0"><pre>Matches statements inside of a template instantiation.
-
-Given
- int j;
- template<typename T> void A(T t) { T i; j += 42;}
- A(0);
- A(0U);
-declStmt(isInTemplateInstantiation())
- matches 'int i;' and 'unsigned i'.
-unless(stmt(isInTemplateInstantiation()))
- will NOT match j += 42; as it's shared between the template definition and
- instantiation.
-</pre></td></tr>
-
-<!--END_NARROWING_MATCHERS -->
-</table>
-
-<!-- ======================================================================= -->
-<h2 id="traversal-matchers">AST Traversal Matchers</h2>
-<!-- ======================================================================= -->
-
-<p>Traversal matchers specify the relationship to other nodes that are
-reachable from the current node.</p>
-
-<p>Note that there are special traversal matchers (has, hasDescendant, forEach and
-forEachDescendant) which work on all nodes and allow users to write more generic
-match expressions.</p>
-
-<table>
-<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
-<!-- START_TRAVERSAL_MATCHERS -->
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('eachOf0')"><a name="eachOf0Anchor">eachOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="eachOf0"><pre>Matches if any of the given matchers matches.
-
-Unlike anyOf, eachOf will generate a match result for each
-matching submatcher.
-
-For example, in:
- class A { int a; int b; };
-The matcher:
- cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
- has(fieldDecl(hasName("b")).bind("v"))))
-will generate two results binding "v", the first of which binds
-the field declaration of a, the second the field declaration of
-b.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('forEachDescendant0')"><a name="forEachDescendant0Anchor">forEachDescendant</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="forEachDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
-provided matcher.
-
-Example matches X, A, B, C
- (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
- class X {}; Matches X, because X::X is a class of name X inside X.
- class A { class X {}; };
- class B { class C { class X {}; }; };
-
-DescendantT must be an AST base type.
-
-As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
-each result that matches instead of only on the first one.
-
-Note: Recursively combined ForEachDescendant can cause many matches:
- cxxRecordDecl(forEachDescendant(cxxRecordDecl(
- forEachDescendant(cxxRecordDecl())
- )))
-will match 10 times (plus injected class name matches) on:
- class A { class B { class C { class D { class E {}; }; }; }; };
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
-provided matcher.
-
-Example matches X, Y
- (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
- class X {}; Matches X, because X::X is a class of name X inside X.
- class Y { class X {}; };
- class Z { class Y { class X {}; }; }; Does not match Z.
-
-ChildT must be an AST base type.
-
-As opposed to 'has', 'forEach' will cause a match for each result that
-matches instead of only on the first one.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasAncestor0')"><a name="hasAncestor0Anchor">hasAncestor</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="hasAncestor0"><pre>Matches AST nodes that have an ancestor that matches the provided
-matcher.
-
-Given
-void f() { if (true) { int x = 42; } }
-void g() { for (;;) { int x = 43; } }
-expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasDescendant0')"><a name="hasDescendant0Anchor">hasDescendant</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="hasDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
-provided matcher.
-
-Example matches X, Y, Z
- (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
- class X {}; Matches X, because X::X is a class of name X inside X.
- class Y { class X {}; };
- class Z { class Y { class X {}; }; };
-
-DescendantT must be an AST base type.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('has0')"><a name="has0Anchor">has</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="has0"><pre>Matches AST nodes that have child AST nodes that match the
-provided matcher.
-
-Example matches X, Y
- (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
- class X {}; Matches X, because X::X is a class of name X inside X.
- class Y { class X {}; };
- class Z { class Y { class X {}; }; }; Does not match Z.
-
-ChildT must be an AST base type.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasParent0')"><a name="hasParent0Anchor">hasParent</a></td><td>Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="hasParent0"><pre>Matches AST nodes that have a parent that matches the provided
-matcher.
-
-Given
-void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
-compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasBase0')"><a name="hasBase0Anchor">hasBase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasBase0"><pre>Matches the base expression of an array subscript expression.
-
-Given
- int i[5];
- void f() { i[1] = 42; }
-arraySubscriptExpression(hasBase(implicitCastExpr(
- hasSourceExpression(declRefExpr()))))
- matches i[1] with the declRefExpr() matching i
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasIndex0')"><a name="hasIndex0Anchor">hasIndex</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasIndex0"><pre>Matches the index expression of an array subscript expression.
-
-Given
- int i[5];
- void f() { i[1] = 42; }
-arraySubscriptExpression(hasIndex(integerLiteral()))
- matches i[1] with the integerLiteral() matching 1
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element
-type.
-
-Given
- struct A {};
- A a[7];
- int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>></td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element
-type.
-
-Given
- struct A {};
- A a[7];
- int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicTypeLoc.html">AtomicTypeLoc</a>></td><td class="name" onclick="toggle('hasValueTypeLoc0')"><a name="hasValueTypeLoc0Anchor">hasValueTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasValueTypeLoc0"><pre>Matches atomic types with a specific value type.
-
-Given
- _Atomic(int) i;
- _Atomic(float) f;
-atomicType(hasValueType(isInteger()))
- matches "_Atomic(int) i"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>></td><td class="name" onclick="toggle('hasValueType0')"><a name="hasValueType0Anchor">hasValueType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasValueType0"><pre>Matches atomic types with a specific value type.
-
-Given
- _Atomic(int) i;
- _Atomic(float) f;
-atomicType(hasValueType(isInteger()))
- matches "_Atomic(int) i"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>></td><td class="name" onclick="toggle('hasDeducedType0')"><a name="hasDeducedType0Anchor">hasDeducedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasDeducedType0"><pre>Matches AutoType nodes where the deduced type is a specific type.
-
-Note: There is no TypeLoc for the deduced type and thus no
-getDeducedLoc() matcher.
-
-Given
- auto a = 1;
- auto b = 2.0;
-autoType(hasDeducedType(isInteger()))
- matches "auto a"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a
-binary operator matches.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasLHS0')"><a name="hasLHS0Anchor">hasLHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasLHS0"><pre>Matches the left hand side of binary operator expressions.
-
-Example matches a (matcher = binaryOperator(hasLHS()))
- a || b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasRHS0')"><a name="hasRHS0Anchor">hasRHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasRHS0"><pre>Matches the right hand side of binary operator expressions.
-
-Example matches b (matcher = binaryOperator(hasRHS()))
- a || b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>></td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument1')"><a name="hasAnyArgument1Anchor">hasAnyArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyArgument1"><pre>Matches any argument of a call expression or a constructor call
-expression.
-
-Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
- matching y
-
-FIXME: Currently this will ignore parentheses and implicit casts on
-the argument before applying the inner matcher. We'll want to remove
-this to allow for greater control by the user once ignoreImplicit()
-has been implemented.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasArgument1')"><a name="hasArgument1Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasArgument1"><pre>Matches the n'th argument of a call expression or a constructor
-call expression.
-
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
- void x(int) { int y; x(y); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasDeclaration12')"><a name="hasDeclaration12Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration12"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('forEachConstructorInitializer0')"><a name="forEachConstructorInitializer0Anchor">forEachConstructorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="forEachConstructorInitializer0"><pre>Matches each constructor initializer in a constructor definition.
-
-Given
- class A { A() : i(42), j(42) {} int i; int j; };
-cxxConstructorDecl(forEachConstructorInitializer(
- forField(decl().bind("x"))
-))
- will trigger two matches, binding for 'i' and 'j' respectively.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('hasAnyConstructorInitializer0')"><a name="hasAnyConstructorInitializer0Anchor">hasAnyConstructorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyConstructorInitializer0"><pre>Matches a constructor initializer.
-
-Given
- struct Foo {
- Foo() : foo_(1) { }
- int foo_;
- };
-cxxRecordDecl(has(cxxConstructorDecl(
- hasAnyConstructorInitializer(anything())
-)))
- record matches Foo, hasAnyConstructorInitializer matches foo_(1)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('forField0')"><a name="forField0Anchor">forField</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="forField0"><pre>Matches the field declaration of a constructor initializer.
-
-Given
- struct Foo {
- Foo() : foo_(1) { }
- int foo_;
- };
-cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
- forField(hasName("foo_"))))))
- matches Foo
-with forField matching foo_
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('withInitializer0')"><a name="withInitializer0Anchor">withInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="withInitializer0"><pre>Matches the initializer expression of a constructor initializer.
-
-Given
- struct Foo {
- Foo() : foo_(1) { }
- int foo_;
- };
-cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
- withInitializer(integerLiteral(equals(1)))))))
- matches Foo
-with withInitializer matching (1)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasBody3')"><a name="hasBody3Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasBody3"><pre>Matches a 'for', 'while', or 'do while' statement that has
-a given body.
-
-Given
- for (;;) {}
-hasBody(compoundStmt())
- matches 'for (;;) {}'
-with compoundStmt()
- matching '{}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasLoopVariable0')"><a name="hasLoopVariable0Anchor">hasLoopVariable</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasLoopVariable0"><pre>Matches the initialization statement of a for loop.
-
-Example:
- forStmt(hasLoopVariable(anything()))
-matches 'int x' in
- for (int x : a) { }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasRangeInit0')"><a name="hasRangeInit0Anchor">hasRangeInit</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasRangeInit0"><pre>Matches the range initialization statement of a for loop.
-
-Example:
- forStmt(hasRangeInit(anything()))
-matches 'a' in
- for (int x : a) { }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('onImplicitObjectArgument0')"><a name="onImplicitObjectArgument0Anchor">onImplicitObjectArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="onImplicitObjectArgument0"><pre></pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('on0')"><a name="on0Anchor">on</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="on0"><pre>Matches on the implicit object argument of a member call expression.
-
-Example matches y.x()
- (matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))))
- class Y { public: void x(); };
- void z() { Y y; y.x(); }",
-
-FIXME: Overload to allow directly matching types?
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType1')"><a name="thisPointerType1Anchor">thisPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="thisPointerType1"><pre>Overloaded to match the type's declaration.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType0')"><a name="thisPointerType0Anchor">thisPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="thisPointerType0"><pre>Matches if the expression's type either matches the specified
-matcher, or is a pointer to a type that matches the InnerMatcher.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('ofClass0')"><a name="ofClass0Anchor">ofClass</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="ofClass0"><pre>Matches the class declaration that the given method declaration
-belongs to.
-
-FIXME: Generalize this for other kinds of declarations.
-FIXME: What other kind of declarations would we need to generalize
-this to?
-
-Example matches A() in the last line
- (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl(
- ofClass(hasName("A"))))))
- class A {
- public:
- A();
- };
- A a = A();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
-
-Given:
- class A { void func(); };
- class B { void member(); };
-
-cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
-A but not B.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
-<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>Matches C++ classes that are directly or indirectly derived from
-a class matching Base.
-
-Note that a class is not considered to be derived from itself.
-
-Example matches Y, Z, C (Base == hasName("X"))
- class X;
- class Y : public X {}; directly derived
- class Z : public Y {}; indirectly derived
- typedef X A;
- typedef A B;
- class C : public B {}; derived from a typedef of X
-
-In the following example, Bar matches isDerivedFrom(hasName("X")):
- class Foo;
- typedef Foo X;
- class Bar : public Foo {}; derived from a type that X is a typedef of
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
-<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
-match Base.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
-given matcher.
-
-Example matches y.x() (matcher = callExpr(callee(
- cxxMethodDecl(hasName("x")))))
- class Y { public: void x(); };
- void z() { Y y; y.x(); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee0')"><a name="callee0Anchor">callee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="callee0"><pre>Matches if the call expression's callee expression matches.
-
-Given
- class Y { void x() { this->x(); x(); Y y; y.x(); } };
- void f() { f(); }
-callExpr(callee(expr()))
- matches this->x(), x(), y.x(), f()
-with callee(...)
- matching this->x, x, y.x, f respectively
-
-Note: Callee cannot take the more general internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>
-because this introduces ambiguous overloads with calls to Callee taking a
-internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, as the matcher hierarchy is purely
-implemented in terms of implicit casts.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument0')"><a name="hasAnyArgument0Anchor">hasAnyArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyArgument0"><pre>Matches any argument of a call expression or a constructor call
-expression.
-
-Given
- void x(int, int, int) { int y; x(1, y, 42); }
-callExpr(hasAnyArgument(declRefExpr()))
- matches x(1, y, 42)
-with hasAnyArgument(...)
- matching y
-
-FIXME: Currently this will ignore parentheses and implicit casts on
-the argument before applying the inner matcher. We'll want to remove
-this to allow for greater control by the user once ignoreImplicit()
-has been implemented.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasArgument0')"><a name="hasArgument0Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasArgument0"><pre>Matches the n'th argument of a call expression or a constructor
-call expression.
-
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
- void x(int) { int y; x(y); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasDeclaration13')"><a name="hasDeclaration13Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration13"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>></td><td class="name" onclick="toggle('hasCaseConstant0')"><a name="hasCaseConstant0Anchor">hasCaseConstant</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCaseConstant0"><pre>If the given case statement does not use the GNU case range
-extension, matches the constant given in the statement.
-
-Given
- switch (1) { case 1: case 1+1: case 3 ... 4: ; }
-caseStmt(hasCaseConstant(integerLiteral()))
- matches "case 1:"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>></td><td class="name" onclick="toggle('hasSourceExpression0')"><a name="hasSourceExpression0Anchor">hasSourceExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasSourceExpression0"><pre>Matches if the cast's source expression matches the given matcher.
-
-Example: matches "a string" (matcher =
- hasSourceExpression(cxxConstructExpr()))
-class URL { URL(string); };
-URL url = "a string";
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations that have at least one
-TemplateArgument matching the given InnerMatcher.
-
-Given
- template<typename T> class A {};
- template<> class A<double> {};
- A<int> a;
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasTemplateArgument0')"><a name="hasTemplateArgument0Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasTemplateArgument0"><pre>Matches classTemplateSpecializations where the n'th TemplateArgument
-matches the given InnerMatcher.
-
-Given
- template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
-classTemplateSpecializationDecl(hasTemplateArgument(
- 1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element
-type.
-
-Given
- struct A {};
- A a[7];
- int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>></td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element
-type.
-
-Given
- struct A {};
- A a[7];
- int b[7];
-arrayType(hasElementType(builtinType()))
- matches "int b[7]"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>></td><td class="name" onclick="toggle('hasAnySubstatement0')"><a name="hasAnySubstatement0Anchor">hasAnySubstatement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnySubstatement0"><pre>Matches compound statements where at least one substatement matches
-a given matcher.
-
-Given
- { {}; 1+2; }
-hasAnySubstatement(compoundStmt())
- matches '{ {}; 1+2; }'
-with compoundStmt()
- matching '{}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasCondition4')"><a name="hasCondition4Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCondition4"><pre>Matches the condition expression of an if statement, for loop,
-or conditional operator.
-
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
- if (true) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasFalseExpression0')"><a name="hasFalseExpression0Anchor">hasFalseExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasFalseExpression0"><pre>Matches the false branch expression of a conditional operator.
-
-Example matches b
- condition ? a : b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasTrueExpression0')"><a name="hasTrueExpression0Anchor">hasTrueExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasTrueExpression0"><pre>Matches the true branch expression of a conditional operator.
-
-Example matches a
- condition ? a : b
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>></td><td class="name" onclick="toggle('hasDecayedType0')"><a name="hasDecayedType0Anchor">hasDecayedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerType</td></tr>
-<tr><td colspan="4" class="doc" id="hasDecayedType0"><pre>Matches the decayed type, whos decayed type matches InnerMatcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('hasDeclaration11')"><a name="hasDeclaration11Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration11"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('throughUsingDecl0')"><a name="throughUsingDecl0Anchor">throughUsingDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="throughUsingDecl0"><pre>Matches a DeclRefExpr that refers to a declaration through a
-specific using shadow declaration.
-
-Given
- namespace a { void f() {} }
- using a::f;
- void g() {
- f(); Matches this ..
- a::f(); .. but not this.
- }
-declRefExpr(throughUsingDecl(anything()))
- matches f()
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('to0')"><a name="to0Anchor">to</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="to0"><pre>Matches a DeclRefExpr that refers to a declaration that matches the
-specified matcher.
-
-Example matches x in if(x)
- (matcher = declRefExpr(to(varDecl(hasName("x")))))
- bool x;
- if (x) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('containsDeclaration0')"><a name="containsDeclaration0Anchor">containsDeclaration</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="containsDeclaration0"><pre>Matches the n'th declaration of a declaration statement.
-
-Note that this does not work for global declarations because the AST
-breaks up multiple-declaration DeclStmt's into multiple single-declaration
-DeclStmt's.
-Example: Given non-global declarations
- int a, b = 0;
- int c;
- int d = 2, e;
-declStmt(containsDeclaration(
- 0, varDecl(hasInitializer(anything()))))
- matches only 'int d = 2, e;', and
-declStmt(containsDeclaration(1, varDecl()))
- matches 'int a, b = 0' as well as 'int d = 2, e;'
- but 'int c;' is not matched.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('hasSingleDecl0')"><a name="hasSingleDecl0Anchor">hasSingleDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasSingleDecl0"><pre>Matches the Decl of a DeclStmt which has a single declaration.
-
-Given
- int a, b;
- int c;
-declStmt(hasSingleDecl(anything()))
- matches 'int c;' but not 'int a, b;'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc0')"><a name="hasTypeLoc0Anchor">hasTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
-<tr><td colspan="4" class="doc" id="hasTypeLoc0"><pre>Matches if the type location of the declarator decl's type matches
-the inner matcher.
-
-Given
- int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
- matches int x
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasDeclContext0')"><a name="hasDeclContext0Anchor">hasDeclContext</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclContext0"><pre>Matches declarations whose declaration context, interpreted as a
-Decl, matches InnerMatcher.
-
-Given
- namespace N {
- namespace M {
- class D {};
- }
- }
-
-cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
-declaration of class D.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>></td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasBody0"><pre>Matches a 'for', 'while', or 'do while' statement that has
-a given body.
-
-Given
- for (;;) {}
-hasBody(compoundStmt())
- matches 'for (;;) {}'
-with compoundStmt()
- matching '{}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>></td><td class="name" onclick="toggle('hasCondition3')"><a name="hasCondition3Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCondition3"><pre>Matches the condition expression of an if statement, for loop,
-or conditional operator.
-
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
- if (true) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-matches InnerMatcher if the qualifier exists.
-
-Given
- namespace N {
- namespace M {
- class D {};
- }
- }
- N::M::D d;
-
-elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
-matches the type of the variable declaration of d.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('namesType0')"><a name="namesType0Anchor">namesType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="namesType0"><pre>Matches ElaboratedTypes whose named type matches InnerMatcher.
-
-Given
- namespace N {
- namespace M {
- class D {};
- }
- }
- N::M::D d;
-
-elaboratedType(namesType(recordType(
-hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
-declaration of d.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>></td><td class="name" onclick="toggle('hasDeclaration10')"><a name="hasDeclaration10Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration10"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>></td><td class="name" onclick="toggle('hasDestinationType0')"><a name="hasDestinationType0Anchor">hasDestinationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDestinationType0"><pre>Matches casts whose destination type matches a given matcher.
-
-(Note: Clang's AST refers to other conversions as "casts" too, and calls
-actual casts "explicit" casts.)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType2"><pre>Overloaded to match the declaration of the expression's or value
-declaration's type.
-
-In case of a value declaration (for example a variable declaration),
-this resolves one layer of indirection. For example, in the value
-declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
-X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
-declaration of x.
-
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- class X {};
- void y(X &x) { x; X z; }
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType0')"><a name="hasType0Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType0"><pre>Matches if the expression's or declaration's type matches a type
-matcher.
-
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- class X {};
- void y(X &x) { x; X z; }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringImpCasts0')"><a name="ignoringImpCasts0Anchor">ignoringImpCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="ignoringImpCasts0"><pre>Matches expressions that match InnerMatcher after any implicit casts
-are stripped off.
-
-Parentheses and explicit casts are not discarded.
-Given
- int arr[5];
- int a = 0;
- char b = 0;
- const int c = a;
- int *d = arr;
- long e = (long) 0l;
-The matchers
- varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
- varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
-would match the declarations for a, b, c, and d, but not e.
-While
- varDecl(hasInitializer(integerLiteral()))
- varDecl(hasInitializer(declRefExpr()))
-only match the declarations for b, c, and d.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringParenCasts0')"><a name="ignoringParenCasts0Anchor">ignoringParenCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="ignoringParenCasts0"><pre>Matches expressions that match InnerMatcher after parentheses and
-casts are stripped off.
-
-Implicit and non-C Style casts are also discarded.
-Given
- int a = 0;
- char b = (0);
- void* c = reinterpret_cast<char*>(0);
- char d = char(0);
-The matcher
- varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
-would match the declarations for a, b, c, and d.
-while
- varDecl(hasInitializer(integerLiteral()))
-only match the declaration for a.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringParenImpCasts0')"><a name="ignoringParenImpCasts0Anchor">ignoringParenImpCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="ignoringParenImpCasts0"><pre>Matches expressions that match InnerMatcher after implicit casts and
-parentheses are stripped off.
-
-Explicit casts are not discarded.
-Given
- int arr[5];
- int a = 0;
- char b = (0);
- const int c = a;
- int *d = (arr);
- long e = ((long) 0l);
-The matchers
- varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
- varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
-would match the declarations for a, b, c, and d, but not e.
-while
- varDecl(hasInitializer(integerLiteral()))
- varDecl(hasInitializer(declRefExpr()))
-would only match the declaration for a.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasBody1')"><a name="hasBody1Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasBody1"><pre>Matches a 'for', 'while', or 'do while' statement that has
-a given body.
-
-Given
- for (;;) {}
-hasBody(compoundStmt())
- matches 'for (;;) {}'
-with compoundStmt()
- matching '{}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasCondition1')"><a name="hasCondition1Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCondition1"><pre>Matches the condition expression of an if statement, for loop,
-or conditional operator.
-
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
- if (true) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasIncrement0')"><a name="hasIncrement0Anchor">hasIncrement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasIncrement0"><pre>Matches the increment statement of a for loop.
-
-Example:
- forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
-matches '++x' in
- for (x; x < N; ++x) { }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasLoopInit0')"><a name="hasLoopInit0Anchor">hasLoopInit</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasLoopInit0"><pre>Matches the initialization statement of a for loop.
-
-Example:
- forStmt(hasLoopInit(declStmt()))
-matches 'int x = 0' in
- for (int x = 0; x < N; ++x) { }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasAnyParameter0')"><a name="hasAnyParameter0Anchor">hasAnyParameter</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyParameter0"><pre>Matches any parameter of a function declaration.
-
-Does not match the 'this' parameter of a method.
-
-Given
- class X { void f(int x, int y, int z) {} };
-cxxMethodDecl(hasAnyParameter(hasName("y")))
- matches f(int x, int y, int z) {}
-with hasAnyParameter(...)
- matching int y
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasParameter0')"><a name="hasParameter0Anchor">hasParameter</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasParameter0"><pre>Matches the n'th parameter of a function declaration.
-
-Given
- class X { void f(int x) {} };
-cxxMethodDecl(hasParameter(0, hasType(varDecl())))
- matches f(int x) {}
-with hasParameter(...)
- matching int x
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('returns0')"><a name="returns0Anchor">returns</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="returns0"><pre>Matches the return type of a function declaration.
-
-Given:
- class X { int f() { return 1; } };
-cxxMethodDecl(returns(asString("int")))
- matches int f() { return 1; }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasCondition0')"><a name="hasCondition0Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCondition0"><pre>Matches the condition expression of an if statement, for loop,
-or conditional operator.
-
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
- if (true) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasConditionVariableStatement0')"><a name="hasConditionVariableStatement0Anchor">hasConditionVariableStatement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasConditionVariableStatement0"><pre>Matches the condition variable statement in an if statement.
-
-Given
- if (A* a = GetAPointer()) {}
-hasConditionVariableStatement(...)
- matches 'A* a = GetAPointer()'.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasElse0')"><a name="hasElse0Anchor">hasElse</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasElse0"><pre>Matches the else-statement of an if statement.
-
-Examples matches the if statement
- (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
- if (false) false; else true;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasThen0')"><a name="hasThen0Anchor">hasThen</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasThen0"><pre>Matches the then-statement of an if statement.
-
-Examples matches the if statement
- (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
- if (false) true; else false;
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>></td><td class="name" onclick="toggle('hasImplicitDestinationType0')"><a name="hasImplicitDestinationType0Anchor">hasImplicitDestinationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasImplicitDestinationType0"><pre>Matches implicit casts whose destination type matches a given
-matcher.
-
-FIXME: Unit test this matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>></td><td class="name" onclick="toggle('hasDeclaration9')"><a name="hasDeclaration9Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration9"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>></td><td class="name" onclick="toggle('hasDeclaration8')"><a name="hasDeclaration8Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration8"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasDeclaration7')"><a name="hasDeclaration7Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration7"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasObjectExpression0')"><a name="hasObjectExpression0Anchor">hasObjectExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasObjectExpression0"><pre>Matches a member expression where the object expression is
-matched by a given matcher.
-
-Given
- struct X { int m; };
- void f(X x) { x.m; m; }
-memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
- matches "x.m" and "m"
-with hasObjectExpression(...)
- matching "x" and the implicit object expression of "m" which has type X*.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('member0')"><a name="member0Anchor">member</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="member0"><pre>Matches a member expression where the member is matched by a
-given matcher.
-
-Given
- struct { int first, second; } first, second;
- int i(second.first);
- int j(first.second);
-memberExpr(member(hasName("first")))
- matches second.first
- but not first.second (because the member name there is "second").
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>></td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('hasPrefix1')"><a name="hasPrefix1Anchor">hasPrefix</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasPrefix1"><pre>Matches on the prefix of a NestedNameSpecifierLoc.
-
-Given
- struct A { struct B { struct C {}; }; };
- A::B::C c;
-nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
- matches "A::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('specifiesTypeLoc0')"><a name="specifiesTypeLoc0Anchor">specifiesTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="specifiesTypeLoc0"><pre>Matches nested name specifier locs that specify a type matching the
-given TypeLoc.
-
-Given
- struct A { struct B { struct C {}; }; };
- A::B::C c;
-nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
- hasDeclaration(cxxRecordDecl(hasName("A")))))))
- matches "A::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('hasPrefix0')"><a name="hasPrefix0Anchor">hasPrefix</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasPrefix0"><pre>Matches on the prefix of a NestedNameSpecifier.
-
-Given
- struct A { struct B { struct C {}; }; };
- A::B::C c;
-nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
- matches "A::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('specifiesNamespace0')"><a name="specifiesNamespace0Anchor">specifiesNamespace</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="specifiesNamespace0"><pre>Matches nested name specifiers that specify a namespace matching the
-given namespace matcher.
-
-Given
- namespace ns { struct A {}; }
- ns::A a;
-nestedNameSpecifier(specifiesNamespace(hasName("ns")))
- matches "ns::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('specifiesType0')"><a name="specifiesType0Anchor">specifiesType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="specifiesType0"><pre>Matches nested name specifiers that specify a type matching the
-given QualType matcher without qualifiers.
-
-Given
- struct A { struct B { struct C {}; }; };
- A::B::C c;
-nestedNameSpecifier(specifiesType(
- hasDeclaration(cxxRecordDecl(hasName("A")))
-))
- matches "A::"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasArgument2')"><a name="hasArgument2Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasArgument2"><pre>Matches the n'th argument of a call expression or a constructor
-call expression.
-
-Example matches y in x(y)
- (matcher = callExpr(hasArgument(0, declRefExpr())))
- void x(int) { int y; x(y); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasReceiverType0')"><a name="hasReceiverType0Anchor">hasReceiverType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>Matches on the receiver of an ObjectiveC Message expression.
-
-Example
-matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
-matches the [webView ...] message invocation.
- NSString *webViewJavaScript = ...
- UIWebView *webView = ...
- [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>></td><td class="name" onclick="toggle('innerType0')"><a name="innerType0Anchor">innerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="innerType0"><pre>Matches ParenType nodes where the inner type is a specific type.
-
-Given
- int (*ptr_to_array)[4];
- int (*ptr_to_func)(int);
-
-varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
-ptr_to_func but not ptr_to_array.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>></td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
-
-Given:
- typedef int &int_ref;
- int a;
- int_ref b = a;
-
-varDecl(hasType(qualType(referenceType()))))) will not match the
-declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasDeclaration6')"><a name="hasDeclaration6Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration6"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo1')"><a name="pointsTo1Anchor">pointsTo</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="pointsTo1"><pre>Overloaded to match the pointee type's declaration.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo0')"><a name="pointsTo0Anchor">pointsTo</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="pointsTo0"><pre>Matches if the matched type is a pointer type and the pointee type
-matches the specified matcher.
-
-Example matches y->x()
- (matcher = cxxMemberCallExpr(on(hasType(pointsTo
- cxxRecordDecl(hasName("Y")))))))
- class Y { public: void x(); };
- void z() { Y *y; y->x(); }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('references1')"><a name="references1Anchor">references</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="references1"><pre>Overloaded to match the referenced type's declaration.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('references0')"><a name="references0Anchor">references</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="references0"><pre>Matches if the matched type is a reference type and the referenced
-type matches the specified matcher.
-
-Example matches X &x and const X &y
- (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
- class X {
- void a(X b) {
- X &x = b;
- const X &y = b;
- }
- };
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>></td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>></td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
-<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
-pointee matches a given matcher.
-
-Given
- int *a;
- int const *b;
- float const *f;
-pointerType(pointee(isConstQualified(), isInteger()))
- matches "int const *b"
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('alignOfExpr0')"><a name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
-alignof.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="sizeOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
-sizeof.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>></td><td class="name" onclick="toggle('forEachSwitchCase0')"><a name="forEachSwitchCase0Anchor">forEachSwitchCase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="forEachSwitchCase0"><pre>Matches each case or default statement belonging to the given switch
-statement. This matcher may produce multiple matches.
-
-Given
- switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
-switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
- matches four times, with "c" binding each of "case 1:", "case 2:",
-"case 3:" and "case 4:", and "s" respectively binding "switch (1)",
-"switch (1)", "switch (2)" and "switch (2)".
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>></td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration4"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('isExpr0')"><a name="isExpr0Anchor">isExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="isExpr0"><pre>Matches a sugar TemplateArgument that refers to a certain expression.
-
-Given
- template<typename T> struct A {};
- struct B { B* next; };
- A<&B::next> a;
-templateSpecializationType(hasAnyTemplateArgument(
- isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
- matches the specialization A<&B::next> with fieldDecl(...) matching
- B::next
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToDeclaration0')"><a name="refersToDeclaration0Anchor">refersToDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="refersToDeclaration0"><pre>Matches a canonical TemplateArgument that refers to a certain
-declaration.
-
-Given
- template<typename T> struct A {};
- struct B { B* next; };
- A<&B::next> a;
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToDeclaration(fieldDecl(hasName("next"))))
- matches the specialization A<&B::next> with fieldDecl(...) matching
- B::next
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToIntegralType0')"><a name="refersToIntegralType0Anchor">refersToIntegralType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="refersToIntegralType0"><pre>Matches a TemplateArgument that referes to an integral type.
-
-Given
- template<int T> struct A {};
- C<42> c;
-classTemplateSpecializationDecl(
- hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
- matches the implicit instantiation of C in C<42>.
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToType0')"><a name="refersToType0Anchor">refersToType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="refersToType0"><pre>Matches a TemplateArgument that refers to a certain type.
-
-Given
- struct X {};
- template<typename T> struct A {};
- A<X> a;
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(class(hasName("X")))))
- matches the specialization A<X>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument1')"><a name="hasAnyTemplateArgument1Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>Matches classTemplateSpecializations that have at least one
-TemplateArgument matching the given InnerMatcher.
-
-Given
- template<typename T> class A {};
- template<> class A<double> {};
- A<int> a;
-classTemplateSpecializationDecl(hasAnyTemplateArgument(
- refersToType(asString("int"))))
- matches the specialization A<int>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasTemplateArgument1')"><a name="hasTemplateArgument1Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasTemplateArgument1"><pre>Matches classTemplateSpecializations where the n'th TemplateArgument
-matches the given InnerMatcher.
-
-Given
- template<typename T, typename U> class A {};
- A<bool, int> b;
- A<int, bool> c;
-classTemplateSpecializationDecl(hasTemplateArgument(
- 1, refersToType(asString("int"))))
- matches the specialization A<bool, int>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>></td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<T></td><td class="name" onclick="toggle('findAll0')"><a name="findAll0Anchor">findAll</a></td><td>Matcher<T> Matcher</td></tr>
-<tr><td colspan="4" class="doc" id="findAll0"><pre>Matches if the node or any descendant matches.
-
-Generates results for each match.
-
-For example, in:
- class A { class B {}; class C {}; };
-The matcher:
- cxxRecordDecl(hasName("::A"),
- findAll(cxxRecordDecl(isDefinition()).bind("m")))
-will generate results for A, B and C.
-
-Usable as: Any Matcher
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>></td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>></td><td class="name" onclick="toggle('hasArgumentOfType0')"><a name="hasArgumentOfType0Anchor">hasArgumentOfType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasArgumentOfType0"><pre>Matches unary expressions that have a specific type of argument.
-
-Given
- int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
-unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
- matches sizeof(a) and alignof(c)
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasUnaryOperand0')"><a name="hasUnaryOperand0Anchor">hasUnaryOperand</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasUnaryOperand0"><pre>Matches if the operand of a unary operator matches.
-
-Example matches true (matcher = hasUnaryOperand(
- cxxBoolLiteral(equals(true))))
- !true
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>></td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a node if the declaration associated with that node
-matches the given matcher.
-
-The associated declaration is:
-- for type nodes, the declaration of the underlying type
-- for CallExpr, the declaration of the callee
-- for MemberExpr, the declaration of the referenced member
-- for CXXConstructExpr, the declaration of the constructor
-
-Also usable as Matcher<T> for any T supporting the getDecl() member
-function. e.g. various subtypes of clang::Type and various expressions.
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
- Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>></td><td class="name" onclick="toggle('hasAnyUsingShadowDecl0')"><a name="hasAnyUsingShadowDecl0Anchor">hasAnyUsingShadowDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasAnyUsingShadowDecl0"><pre>Matches any using shadow declaration.
-
-Given
- namespace X { void b(); }
- using X::b;
-usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
- matches using X::b </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>></td><td class="name" onclick="toggle('hasTargetDecl0')"><a name="hasTargetDecl0Anchor">hasTargetDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasTargetDecl0"><pre>Matches a using shadow declaration where the target declaration is
-matched by the given matcher.
-
-Given
- namespace X { int a; void b(); }
- using X::a;
- using X::b;
-usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
- matches using X::b but not using X::a </pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value
-declaration's type.
-
-In case of a value declaration (for example a variable declaration),
-this resolves one layer of indirection. For example, in the value
-declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
-X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
-declaration of x.
-
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- class X {};
- void y(X &x) { x; X z; }
-
-Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType1')"><a name="hasType1Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType1"><pre>Matches if the expression's or declaration's type matches a type
-matcher.
-
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- class X {};
- void y(X &x) { x; X z; }
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasInitializer0')"><a name="hasInitializer0Anchor">hasInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasInitializer0"><pre>Matches a variable declaration that has an initializer expression
-that matches the given matcher.
-
-Example matches x (matcher = varDecl(hasInitializer(callExpr())))
- bool y() { return true; }
- bool x = y();
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>></td><td class="name" onclick="toggle('hasSizeExpr0')"><a name="hasSizeExpr0Anchor">hasSizeExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasSizeExpr0"><pre>Matches VariableArrayType nodes that have a specific size
-expression.
-
-Given
- void f(int b) {
- int a[b];
- }
-variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
- varDecl(hasName("b")))))))
- matches "int a[b]"
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>></td><td class="name" onclick="toggle('hasBody2')"><a name="hasBody2Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasBody2"><pre>Matches a 'for', 'while', or 'do while' statement that has
-a given body.
-
-Given
- for (;;) {}
-hasBody(compoundStmt())
- matches 'for (;;) {}'
-with compoundStmt()
- matching '{}'
-</pre></td></tr>
-
-
-<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>></td><td class="name" onclick="toggle('hasCondition2')"><a name="hasCondition2Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasCondition2"><pre>Matches the condition expression of an if statement, for loop,
-or conditional operator.
-
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
- if (true) {}
-</pre></td></tr>
-
-
-<tr><td>Matcher<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
-</pre></td></tr>
-
-
-<tr><td>Matcher<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>></td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
-QualType-matcher matches.
-</pre></td></tr>
-
-<!--END_TRAVERSAL_MATCHERS -->
-</table>
-
-</div>
-</body>
-</html>
-
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>AST Matcher Reference</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+td {
+ padding: .33em;
+}
+td.doc {
+ display: none;
+ border-bottom: 1px solid black;
+}
+td.name:hover {
+ color: blue;
+ cursor: pointer;
+}
+</style>
+<script type="text/javascript">
+function toggle(id) {
+ if (!id) return;
+ row = document.getElementById(id);
+ if (row.style.display != 'table-cell')
+ row.style.display = 'table-cell';
+ else
+ row.style.display = 'none';
+}
+</script>
+</head>
+<body onLoad="toggle(location.hash.substring(1, location.hash.length - 6))">
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>AST Matcher Reference</h1>
+
+<p>This document shows all currently implemented matchers. The matchers are grouped
+by category and node type they match. You can click on matcher names to show the
+matcher's source documentation.</p>
+
+<p>There are three different basic categories of matchers:
+<ul>
+<li><a href="#decl-matchers">Node Matchers:</a> Matchers that match a specific type of AST node.</li>
+<li><a href="#narrowing-matchers">Narrowing Matchers:</a> Matchers that match attributes on AST nodes.</li>
+<li><a href="#traversal-matchers">Traversal Matchers:</a> Matchers that allow traversal between AST nodes.</li>
+</ul>
+</p>
+
+<p>Within each category the matchers are ordered by node type they match on.
+Note that if a matcher can match multiple node types, it will it will appear
+multiple times. This means that by searching for Matcher<Stmt> you can
+find all matchers that can be used to match on Stmt nodes.</p>
+
+<p>The exception to that rule are matchers that can match on any node. Those
+are marked with a * and are listed in the beginning of each category.</p>
+
+<p>Note that the categorization of matchers is a great help when you combine
+them into matcher expressions. You will usually want to form matcher expressions
+that read like english sentences by alternating between node matchers and
+narrowing or traversal matchers, like this:
+<pre>
+recordDecl(hasDescendant(
+ ifStmt(hasTrueExpression(
+ expr(hasDescendant(
+ ifStmt()))))))
+</pre>
+</p>
+
+<!-- ======================================================================= -->
+<h2 id="decl-matchers">Node Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Node matchers are at the core of matcher expressions - they specify the type
+of node that is expected. Every match expression starts with a node matcher,
+which can then be further refined with a narrowing or traversal matcher. All
+traversal matchers take node matchers as their arguments.</p>
+
+<p>For convenience, all node matchers take an arbitrary number of arguments
+and implicitly act as allOf matchers.</p>
+
+<p>Node matchers are the only matchers that support the bind("id") call to
+bind the matched node to the given string, to be later retrieved from the
+match callback.</p>
+
+<p>It is important to remember that the arguments to node matchers are
+predicates on the same node, just with additional information about the type.
+This is often useful to make matcher expression more readable by inlining bind
+calls into redundant node matchers inside another node matcher:
+<pre>
+// This binds the CXXRecordDecl to "id", as the decl() matcher will stay on
+// the same node.
+recordDecl(decl().bind("id"), hasName("::MyClass"))
+</pre>
+</p>
+
+<table>
+<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
+<!-- START_DECL_MATCHERS -->
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers.
+
+Examples matches i(42).
+ class C {
+ C() : i(42) {}
+ int i;
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html">AccessSpecDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="accessSpecDecl0"><pre>Matches C++ access specifier declarations.
+
+Given
+ class C {
+ public:
+ int a;
+ };
+accessSpecDecl()
+ matches 'public:'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('classTemplateDecl0')"><a name="classTemplateDecl0Anchor">classTemplateDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="classTemplateDecl0"><pre>Matches C++ class template declarations.
+
+Example matches Z
+ template<class T> class Z {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('classTemplateSpecializationDecl0')"><a name="classTemplateSpecializationDecl0Anchor">classTemplateSpecializationDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="classTemplateSpecializationDecl0"><pre>Matches C++ class template specializations.
+
+Given
+ template<typename T> class A {};
+ template<> class A<double> {};
+ A<int> a;
+classTemplateSpecializationDecl()
+ matches the specializations A<int> and A<double>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxConstructorDecl0')"><a name="cxxConstructorDecl0Anchor">cxxConstructorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxConstructorDecl0"><pre>Matches C++ constructor declarations.
+
+Example matches Foo::Foo() and Foo::Foo(int)
+ class Foo {
+ public:
+ Foo();
+ Foo(int);
+ int DoSomething();
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxConversionDecl0')"><a name="cxxConversionDecl0Anchor">cxxConversionDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxConversionDecl0"><pre>Matches conversion operator declarations.
+
+Example matches the operator.
+ class X { operator int() const; };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxDestructorDecl0')"><a name="cxxDestructorDecl0Anchor">cxxDestructorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDestructorDecl.html">CXXDestructorDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxDestructorDecl0"><pre>Matches explicit C++ destructor declarations.
+
+Example matches Foo::~Foo()
+ class Foo {
+ public:
+ virtual ~Foo();
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxMethodDecl0')"><a name="cxxMethodDecl0Anchor">cxxMethodDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxMethodDecl0"><pre>Matches method declarations.
+
+Example matches y
+ class X { void y(); };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxRecordDecl0')"><a name="cxxRecordDecl0Anchor">cxxRecordDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxRecordDecl0"><pre>Matches C++ class declarations.
+
+Example matches X, Z
+ class X;
+ template<class T> class Z {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('decl0')"><a name="decl0Anchor">decl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="decl0"><pre>Matches declarations.
+
+Examples matches X, C, and the friend declaration inside C;
+ void X();
+ class C {
+ friend X;
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('declaratorDecl0')"><a name="declaratorDecl0Anchor">declaratorDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="declaratorDecl0"><pre>Matches declarator declarations (field, variable, function
+and non-type template parameter declarations).
+
+Given
+ class X { int y; };
+declaratorDecl()
+ matches int y.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('enumConstantDecl0')"><a name="enumConstantDecl0Anchor">enumConstantDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumConstantDecl.html">EnumConstantDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="enumConstantDecl0"><pre>Matches enum constants.
+
+Example matches A, B, C
+ enum X {
+ A, B, C
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('enumDecl0')"><a name="enumDecl0Anchor">enumDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumDecl.html">EnumDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="enumDecl0"><pre>Matches enum declarations.
+
+Example matches X
+ enum X {
+ A, B, C
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('fieldDecl0')"><a name="fieldDecl0Anchor">fieldDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.
+
+Given
+ class X { int m; };
+fieldDecl()
+ matches 'm'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('friendDecl0')"><a name="friendDecl0Anchor">friendDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="friendDecl0"><pre>Matches friend declarations.
+
+Given
+ class X { friend void foo(); };
+friendDecl()
+ matches 'friend void foo()'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('functionDecl0')"><a name="functionDecl0Anchor">functionDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="functionDecl0"><pre>Matches function declarations.
+
+Example matches f
+ void f();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('functionTemplateDecl0')"><a name="functionTemplateDecl0Anchor">functionTemplateDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTemplateDecl.html">FunctionTemplateDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="functionTemplateDecl0"><pre>Matches C++ function template declarations.
+
+Example matches f
+ template<class T> void f(T t) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('linkageSpecDecl0')"><a name="linkageSpecDecl0Anchor">linkageSpecDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LinkageSpecDecl.html">LinkageSpecDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="linkageSpecDecl0"><pre>Matches a declaration of a linkage specification.
+
+Given
+ extern "C" {}
+linkageSpecDecl()
+ matches "extern "C" {}"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namedDecl0')"><a name="namedDecl0Anchor">namedDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="namedDecl0"><pre>Matches a declaration of anything that could have a name.
+
+Example matches X, S, the anonymous union type, i, and U;
+ typedef int X;
+ struct S {
+ union {
+ int i;
+ } U;
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namespaceAliasDecl0')"><a name="namespaceAliasDecl0Anchor">namespaceAliasDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceAliasDecl.html">NamespaceAliasDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="namespaceAliasDecl0"><pre>Matches a declaration of a namespace alias.
+
+Given
+ namespace test {}
+ namespace alias = ::test;
+namespaceAliasDecl()
+ matches "namespace alias" but not "namespace test"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('namespaceDecl0')"><a name="namespaceDecl0Anchor">namespaceDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="namespaceDecl0"><pre>Matches a declaration of a namespace.
+
+Given
+ namespace {}
+ namespace test {}
+namespaceDecl()
+ matches "namespace {}" and "namespace test {}"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('nonTypeTemplateParmDecl0')"><a name="nonTypeTemplateParmDecl0Anchor">nonTypeTemplateParmDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NonTypeTemplateParmDecl.html">NonTypeTemplateParmDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="nonTypeTemplateParmDecl0"><pre>Matches non-type template parameter declarations.
+
+Given
+ template <typename T, int N> struct C {};
+nonTypeTemplateParmDecl()
+ matches 'N', but not 'T'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcInterfaceDecl0')"><a name="objcInterfaceDecl0Anchor">objcInterfaceDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="objcInterfaceDecl0"><pre>Matches Objective-C interface declarations.
+
+Example matches Foo
+ @interface Foo
+ @end
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('parmVarDecl0')"><a name="parmVarDecl0Anchor">parmVarDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="parmVarDecl0"><pre>Matches parameter variable declarations.
+
+Given
+ void f(int x);
+parmVarDecl()
+ matches int x.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('recordDecl0')"><a name="recordDecl0Anchor">recordDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="recordDecl0"><pre>Matches class, struct, and union declarations.
+
+Example matches X, Z, U, and S
+ class X;
+ template<class T> class Z {};
+ struct S {};
+ union U {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('staticAssertDecl0')"><a name="staticAssertDecl0Anchor">staticAssertDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1StaticAssertDecl.html">StaticAssertDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="staticAssertDecl0"><pre>Matches a C++ static_assert declaration.
+
+Example:
+ staticAssertExpr()
+matches
+ static_assert(sizeof(S) == sizeof(int))
+in
+ struct S {
+ int x;
+ };
+ static_assert(sizeof(S) == sizeof(int));
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('templateTypeParmDecl0')"><a name="templateTypeParmDecl0Anchor">templateTypeParmDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmDecl.html">TemplateTypeParmDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="templateTypeParmDecl0"><pre>Matches template type parameter declarations.
+
+Given
+ template <typename T, int N> struct C {};
+templateTypeParmDecl()
+ matches 'T', but not 'N'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('translationUnitDecl0')"><a name="translationUnitDecl0Anchor">translationUnitDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">TranslationUnitDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="translationUnitDecl0"><pre>Matches the top declaration context.
+
+Given
+ int X;
+ namespace NS {
+ int Y;
+ } namespace NS
+decl(hasDeclContext(translationUnitDecl()))
+ matches "int X", but not "int Y".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
+
+Given
+ typedef int X;
+typedefDecl()
+ matches "typedef int X"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('unresolvedUsingTypenameDecl0')"><a name="unresolvedUsingTypenameDecl0Anchor">unresolvedUsingTypenameDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingTypenameDecl.html">UnresolvedUsingTypenameDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="unresolvedUsingTypenameDecl0"><pre>Matches unresolved using value declarations that involve the
+typename.
+
+Given
+ template <typename T>
+ struct Base { typedef T Foo; };
+
+ template<typename T>
+ struct S : private Base<T> {
+ using typename Base<T>::Foo;
+ };
+unresolvedUsingTypenameDecl()
+ matches using Base<T>::Foo </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('unresolvedUsingValueDecl0')"><a name="unresolvedUsingValueDecl0Anchor">unresolvedUsingValueDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingValueDecl.html">UnresolvedUsingValueDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="unresolvedUsingValueDecl0"><pre>Matches unresolved using value declarations.
+
+Given
+ template<typename X>
+ class C : private X {
+ using X::x;
+ };
+unresolvedUsingValueDecl()
+ matches using X::x </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingDecl0')"><a name="usingDecl0Anchor">usingDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="usingDecl0"><pre>Matches using declarations.
+
+Given
+ namespace X { int x; }
+ using X::x;
+usingDecl()
+ matches using X::x </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('usingDirectiveDecl0')"><a name="usingDirectiveDecl0Anchor">usingDirectiveDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDirectiveDecl.html">UsingDirectiveDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="usingDirectiveDecl0"><pre>Matches using namespace declarations.
+
+Given
+ namespace X { int x; }
+ using namespace X;
+usingDirectiveDecl()
+ matches using namespace X </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('valueDecl0')"><a name="valueDecl0Anchor">valueDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="valueDecl0"><pre>Matches any value declaration.
+
+Example matches A, B, C and F
+ enum X { A, B, C };
+ void F();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('varDecl0')"><a name="varDecl0Anchor">varDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
+
+Note: this does not match declarations of member variables, which are
+"field" declarations in Clang parlance.
+
+Example matches a
+ int a;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('nestedNameSpecifierLoc0')"><a name="nestedNameSpecifierLoc0Anchor">nestedNameSpecifierLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="nestedNameSpecifierLoc0"><pre>Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('nestedNameSpecifier0')"><a name="nestedNameSpecifier0Anchor">nestedNameSpecifier</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="nestedNameSpecifier0"><pre>Matches nested name specifiers.
+
+Given
+ namespace ns {
+ struct A { static void f(); };
+ void A::f() {}
+ void g() { A::f(); }
+ }
+ ns::A a;
+nestedNameSpecifier()
+ matches "ns::" and both "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="qualType0"><pre>Matches QualTypes in the clang AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
+
+Given
+ int i = a[1];
+arraySubscriptExpr()
+ matches "a[1]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('asmStmt0')"><a name="asmStmt0Anchor">asmStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AsmStmt.html">AsmStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="asmStmt0"><pre>Matches asm statements.
+
+ int i = 100;
+ __asm("mov al, 2");
+asmStmt()
+ matches '__asm("mov al, 2")'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
+
+Example matches a || b
+ !(a || b)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('breakStmt0')"><a name="breakStmt0Anchor">breakStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BreakStmt.html">BreakStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="breakStmt0"><pre>Matches break statements.
+
+Given
+ while (true) { break; }
+breakStmt()
+ matches 'break'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cStyleCastExpr0')"><a name="cStyleCastExpr0Anchor">cStyleCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CStyleCastExpr.html">CStyleCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cStyleCastExpr0"><pre>Matches a C-style cast expression.
+
+Example: Matches (int*) 2.2f in
+ int i = (int) 2.2f;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('callExpr0')"><a name="callExpr0Anchor">callExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
+
+Example matches x.y() and y()
+ X x;
+ x.y();
+ y();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('caseStmt0')"><a name="caseStmt0Anchor">caseStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="caseStmt0"><pre>Matches case statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+caseStmt()
+ matches 'case 42: break;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
+
+Example: castExpr() matches each of the following:
+ (int) 3;
+ const_cast<Expr *>(SubExpr);
+ char c = 0;
+but does not match
+ int i = (0);
+ int k = 0;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('characterLiteral0')"><a name="characterLiteral0Anchor">characterLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="characterLiteral0"><pre>Matches character literals (also matches wchar_t).
+
+Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
+though.
+
+Example matches 'a', L'a'
+ char ch = 'a'; wchar_t chw = L'a';
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundLiteralExpr0')"><a name="compoundLiteralExpr0Anchor">compoundLiteralExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals
+
+Example match: {1}, (1, 2)
+ int array[4] = {1}; vector int myvec = (vector int)(1, 2);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundStmt0')"><a name="compoundStmt0Anchor">compoundStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="compoundStmt0"><pre>Matches compound statements.
+
+Example matches '{}' and '{{}}'in 'for (;;) {{}}'
+ for (;;) {{}}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('conditionalOperator0')"><a name="conditionalOperator0Anchor">conditionalOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="conditionalOperator0"><pre>Matches conditional operator expressions.
+
+Example matches a ? b : c
+ (a ? b : c) + 42
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('continueStmt0')"><a name="continueStmt0Anchor">continueStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ContinueStmt.html">ContinueStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="continueStmt0"><pre>Matches continue statements.
+
+Given
+ while (true) { continue; }
+continueStmt()
+ matches 'continue'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cudaKernelCallExpr0')"><a name="cudaKernelCallExpr0Anchor">cudaKernelCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CUDAKernelCallExpr.html">CUDAKernelCallExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cudaKernelCallExpr0"><pre>Matches CUDA kernel call expression.
+
+Example matches,
+ kernel<<<i,j>>>();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxBindTemporaryExpr0')"><a name="cxxBindTemporaryExpr0Anchor">cxxBindTemporaryExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxBindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
+
+Example matches FunctionTakesString(GetStringByValue())
+ (matcher = cxxBindTemporaryExpr())
+ FunctionTakesString(GetStringByValue());
+ FunctionTakesStringByPointer(GetStringPointer());
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxBoolLiteral0')"><a name="cxxBoolLiteral0Anchor">cxxBoolLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxBoolLiteral0"><pre>Matches bool literals.
+
+Example matches true
+ true
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxCatchStmt0')"><a name="cxxCatchStmt0Anchor">cxxCatchStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxCatchStmt0"><pre>Matches catch statements.
+
+ try {} catch(int i) {}
+cxxCatchStmt()
+ matches 'catch(int i)'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstCastExpr0')"><a name="cxxConstCastExpr0Anchor">cxxConstCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxConstCastExpr0"><pre>Matches a const_cast expression.
+
+Example: Matches const_cast<int*>(&r) in
+ int n = 42;
+ const int &r(n);
+ int* p = const_cast<int*>(&r);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstructExpr0')"><a name="cxxConstructExpr0Anchor">cxxConstructExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxConstructExpr0"><pre>Matches constructor call expressions (including implicit ones).
+
+Example matches string(ptr, n) and ptr within arguments of f
+ (matcher = cxxConstructExpr())
+ void f(const string &a, const string &b);
+ char *ptr;
+ int n;
+ f(string(ptr, n), ptr);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDefaultArgExpr0')"><a name="cxxDefaultArgExpr0Anchor">cxxDefaultArgExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDefaultArgExpr.html">CXXDefaultArgExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxDefaultArgExpr0"><pre>Matches the value of a default argument at the call site.
+
+Example matches the CXXDefaultArgExpr placeholder inserted for the
+ default value of the second parameter in the call expression f(42)
+ (matcher = cxxDefaultArgExpr())
+ void f(int x, int y = 0);
+ f(42);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDeleteExpr0')"><a name="cxxDeleteExpr0Anchor">cxxDeleteExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDeleteExpr.html">CXXDeleteExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxDeleteExpr0"><pre>Matches delete expressions.
+
+Given
+ delete X;
+cxxDeleteExpr()
+ matches 'delete X'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDynamicCastExpr0')"><a name="cxxDynamicCastExpr0Anchor">cxxDynamicCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxDynamicCastExpr0"><pre>Matches a dynamic_cast expression.
+
+Example:
+ cxxDynamicCastExpr()
+matches
+ dynamic_cast<D*>(&b);
+in
+ struct B { virtual ~B() {} }; struct D : B {};
+ B b;
+ D* p = dynamic_cast<D*>(&b);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxForRangeStmt0')"><a name="cxxForRangeStmt0Anchor">cxxForRangeStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxForRangeStmt0"><pre>Matches range-based for statements.
+
+cxxForRangeStmt() matches 'for (auto a : i)'
+ int i[] = {1, 2, 3}; for (auto a : i);
+ for(int j = 0; j < 5; ++j);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxFunctionalCastExpr0')"><a name="cxxFunctionalCastExpr0Anchor">cxxFunctionalCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxFunctionalCastExpr0"><pre>Matches functional cast expressions
+
+Example: Matches Foo(bar);
+ Foo f = bar;
+ Foo g = (Foo) bar;
+ Foo h = Foo(bar);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxMemberCallExpr0')"><a name="cxxMemberCallExpr0Anchor">cxxMemberCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxMemberCallExpr0"><pre>Matches member call expressions.
+
+Example matches x.y()
+ X x;
+ x.y();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxNewExpr0')"><a name="cxxNewExpr0Anchor">cxxNewExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxNewExpr0"><pre>Matches new expressions.
+
+Given
+ new X;
+cxxNewExpr()
+ matches 'new X'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxNullPtrLiteralExpr0')"><a name="cxxNullPtrLiteralExpr0Anchor">cxxNullPtrLiteralExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNullPtrLiteralExpr.html">CXXNullPtrLiteralExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxNullPtrLiteralExpr0"><pre>Matches nullptr literal.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxOperatorCallExpr0')"><a name="cxxOperatorCallExpr0Anchor">cxxOperatorCallExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxOperatorCallExpr0"><pre>Matches overloaded operator calls.
+
+Note that if an operator isn't overloaded, it won't match. Instead, use
+binaryOperator matcher.
+Currently it does not match operators such as new delete.
+FIXME: figure out why these do not match?
+
+Example matches both operator<<((o << b), c) and operator<<(o, b)
+ (matcher = cxxOperatorCallExpr())
+ ostream &operator<< (ostream &out, int i) { };
+ ostream &o; int b = 1, c = 1;
+ o << b << c;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxReinterpretCastExpr0')"><a name="cxxReinterpretCastExpr0Anchor">cxxReinterpretCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxReinterpretCastExpr0"><pre>Matches a reinterpret_cast expression.
+
+Either the source expression or the destination type can be matched
+using has(), but hasDestinationType() is more specific and can be
+more readable.
+
+Example matches reinterpret_cast<char*>(&p) in
+ void* p = reinterpret_cast<char*>(&p);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStaticCastExpr0')"><a name="cxxStaticCastExpr0Anchor">cxxStaticCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxStaticCastExpr0"><pre>Matches a C++ static_cast expression.
+
+hasDestinationType
+reinterpretCast
+
+Example:
+ cxxStaticCastExpr()
+matches
+ static_cast<long>(8)
+in
+ long eight(static_cast<long>(8));
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
+
+Example: Matches Foo(bar, bar)
+ Foo h = Foo(bar, bar);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThisExpr0')"><a name="cxxThisExpr0Anchor">cxxThisExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxThisExpr0"><pre>Matches implicit and explicit this expressions.
+
+Example matches the implicit this expression in "return i".
+ (matcher = cxxThisExpr())
+struct foo {
+ int i;
+ int f() { return i; }
+};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxThrowExpr0')"><a name="cxxThrowExpr0Anchor">cxxThrowExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThrowExpr.html">CXXThrowExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxThrowExpr0"><pre>Matches throw expressions.
+
+ try { throw 5; } catch(int i) {}
+cxxThrowExpr()
+ matches 'throw 5'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTryStmt0')"><a name="cxxTryStmt0Anchor">cxxTryStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTryStmt.html">CXXTryStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxTryStmt0"><pre>Matches try statements.
+
+ try {} catch(int i) {}
+cxxTryStmt()
+ matches 'try {}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxUnresolvedConstructExpr0')"><a name="cxxUnresolvedConstructExpr0Anchor">cxxUnresolvedConstructExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxUnresolvedConstructExpr0"><pre>Matches unresolved constructor call expressions.
+
+Example matches T(t) in return statement of f
+ (matcher = cxxUnresolvedConstructExpr())
+ template <typename T>
+ void f(const T& t) { return T(t); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('declRefExpr0')"><a name="declRefExpr0Anchor">declRefExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="declRefExpr0"><pre>Matches expressions that refer to declarations.
+
+Example matches x in if (x)
+ bool x;
+ if (x) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('declStmt0')"><a name="declStmt0Anchor">declStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="declStmt0"><pre>Matches declaration statements.
+
+Given
+ int a;
+declStmt()
+ matches 'int a'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('defaultStmt0')"><a name="defaultStmt0Anchor">defaultStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DefaultStmt.html">DefaultStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="defaultStmt0"><pre>Matches default statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+defaultStmt()
+ matches 'default: break;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('doStmt0')"><a name="doStmt0Anchor">doStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="doStmt0"><pre>Matches do statements.
+
+Given
+ do {} while (true);
+doStmt()
+ matches 'do {} while(true)'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('explicitCastExpr0')"><a name="explicitCastExpr0Anchor">explicitCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="explicitCastExpr0"><pre>Matches explicit cast expressions.
+
+Matches any cast expression written in user code, whether it be a
+C-style cast, a functional-style cast, or a keyword cast.
+
+Does not match implicit conversions.
+
+Note: the name "explicitCast" is chosen to match Clang's terminology, as
+Clang uses the term "cast" to apply to implicit conversions as well as to
+actual cast expressions.
+
+hasDestinationType.
+
+Example: matches all five of the casts in
+ int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
+but does not match the implicit conversion in
+ long ell = 42;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('expr0')"><a name="expr0Anchor">expr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="expr0"><pre>Matches expressions.
+
+Example matches x()
+ void f() { x(); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('exprWithCleanups0')"><a name="exprWithCleanups0Anchor">exprWithCleanups</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExprWithCleanups.html">ExprWithCleanups</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="exprWithCleanups0"><pre>Matches expressions that introduce cleanups to be run at the end
+of the sub-expression's evaluation.
+
+Example matches std::string()
+ const std::string str = std::string();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('floatLiteral0')"><a name="floatLiteral0Anchor">floatLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes encodings, e.g.
+1.0, 1.0f, 1.0L and 1e10.
+
+Does not match implicit conversions such as
+ float a = 10;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forStmt0')"><a name="forStmt0Anchor">forStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="forStmt0"><pre>Matches for statements.
+
+Example matches 'for (;;) {}'
+ for (;;) {}
+ int i[] = {1, 2, 3}; for (auto a : i);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('gnuNullExpr0')"><a name="gnuNullExpr0Anchor">gnuNullExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1GNUNullExpr.html">GNUNullExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="gnuNullExpr0"><pre>Matches GNU __null expression.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('gotoStmt0')"><a name="gotoStmt0Anchor">gotoStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1GotoStmt.html">GotoStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="gotoStmt0"><pre>Matches goto statements.
+
+Given
+ goto FOO;
+ FOO: bar();
+gotoStmt()
+ matches 'goto FOO'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('ifStmt0')"><a name="ifStmt0Anchor">ifStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="ifStmt0"><pre>Matches if statements.
+
+Example matches 'if (x) {}'
+ if (x) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('implicitCastExpr0')"><a name="implicitCastExpr0Anchor">implicitCastExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="implicitCastExpr0"><pre>Matches the implicit cast nodes of Clang's AST.
+
+This matches many different places, including function call return value
+eliding, as well as any type conversions.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('initListExpr0')"><a name="initListExpr0Anchor">initListExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="initListExpr0"><pre>Matches init list expressions.
+
+Given
+ int a[] = { 1, 2 };
+ struct B { int x, y; };
+ B b = { 5, 6 };
+initListExpr()
+ matches "{ 1, 2 }" and "{ 5, 6 }"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('integerLiteral0')"><a name="integerLiteral0Anchor">integerLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings, e.g.
+1, 1L, 0x1 and 1U.
+
+Does not match character-encoded integers such as L'a'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('labelStmt0')"><a name="labelStmt0Anchor">labelStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="labelStmt0"><pre>Matches label statements.
+
+Given
+ goto FOO;
+ FOO: bar();
+labelStmt()
+ matches 'FOO:'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('lambdaExpr0')"><a name="lambdaExpr0Anchor">lambdaExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="lambdaExpr0"><pre>Matches lambda expressions.
+
+Example matches [&](){return 5;}
+ [&](){return 5;}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('materializeTemporaryExpr0')"><a name="materializeTemporaryExpr0Anchor">materializeTemporaryExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MaterializeTemporaryExpr.html">MaterializeTemporaryExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
+
+Example: Given
+ struct T {void func()};
+ T f();
+ void g(T);
+materializeTemporaryExpr() matches 'f()' in these statements
+ T u(f());
+ g(f());
+but does not match
+ f();
+ f().func();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('memberExpr0')"><a name="memberExpr0Anchor">memberExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="memberExpr0"><pre>Matches member expressions.
+
+Given
+ class Y {
+ void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+ int a; static int b;
+ };
+memberExpr()
+ matches this->x, x, y.x, a, this->b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('nullStmt0')"><a name="nullStmt0Anchor">nullStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NullStmt.html">NullStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="nullStmt0"><pre>Matches null statements.
+
+ foo();;
+nullStmt()
+ matches the second ';'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcMessageExpr0')"><a name="objcMessageExpr0Anchor">objcMessageExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="objcMessageExpr0"><pre>Matches ObjectiveC Message invocation expressions.
+
+The innermost message send invokes the "alloc" class method on the
+NSString class, while the outermost message send invokes the
+"initWithString" instance method on the object returned from
+NSString's "alloc". This matcher should match both message sends.
+ [[NSString alloc] initWithString:@"Hello"]
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('returnStmt0')"><a name="returnStmt0Anchor">returnStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html">ReturnStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="returnStmt0"><pre>Matches return statements.
+
+Given
+ return 1;
+returnStmt()
+ matches 'return 1'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stmt0')"><a name="stmt0Anchor">stmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
+
+Given
+ { ++a; }
+stmt()
+ matches both the compound statement '{ ++a; }' and '++a'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
+
+Example matches "abcd", L"abcd"
+ char *s = "abcd"; wchar_t *ws = L"abcd"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('substNonTypeTemplateParmExpr0')"><a name="substNonTypeTemplateParmExpr0Anchor">substNonTypeTemplateParmExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstNonTypeTemplateParmExpr.html">SubstNonTypeTemplateParmExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="substNonTypeTemplateParmExpr0"><pre>Matches substitutions of non-type template parameters.
+
+Given
+ template <int N>
+ struct A { static const int n = N; };
+ struct B : public A<42> {};
+substNonTypeTemplateParmExpr()
+ matches "N" in the right-hand side of "static const int n = N;"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+switchCase()
+ matches 'case 42: break;' and 'default: break;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('switchStmt0')"><a name="switchStmt0Anchor">switchStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="switchStmt0"><pre>Matches switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+switchStmt()
+ matches 'switch(a)'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('unaryExprOrTypeTraitExpr0')"><a name="unaryExprOrTypeTraitExpr0Anchor">unaryExprOrTypeTraitExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryExprOrTypeTraitExpr0"><pre>Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
+
+Given
+ Foo x = bar;
+ int y = sizeof(x) + alignof(x);
+unaryExprOrTypeTraitExpr()
+ matches sizeof(x) and alignof(x)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('unaryOperator0')"><a name="unaryOperator0Anchor">unaryOperator</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryOperator0"><pre>Matches unary operator expressions.
+
+Example matches !a
+ !a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('userDefinedLiteral0')"><a name="userDefinedLiteral0Anchor">userDefinedLiteral</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UserDefinedLiteral.html">UserDefinedLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="userDefinedLiteral0"><pre>Matches user defined literal operator call.
+
+Example match: "foo"_suffix
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('whileStmt0')"><a name="whileStmt0Anchor">whileStmt</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="whileStmt0"><pre>Matches while statements.
+
+Given
+ while (true) {}
+whileStmt()
+ matches 'while (true) {}'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgument0"><pre>Matches template arguments.
+
+Given
+ template <typename T> struct C {};
+ C<int> c;
+templateArgument()
+ matches 'int' in C<int>.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('arrayType0')"><a name="arrayType0Anchor">arrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="arrayType0"><pre>Matches all kinds of arrays.
+
+Given
+ int a[] = { 2, 3 };
+ int b[4];
+ void f() { int c[a[0]]; }
+arrayType()
+ matches "int a[]", "int b[4]" and "int c[a[0]]";
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('atomicType0')"><a name="atomicType0Anchor">atomicType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="atomicType0"><pre>Matches atomic types.
+
+Given
+ _Atomic(int) i;
+atomicType()
+ matches "_Atomic(int) i"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('autoType0')"><a name="autoType0Anchor">autoType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="autoType0"><pre>Matches types nodes representing C++11 auto types.
+
+Given:
+ auto n = 4;
+ int v[] = { 2, 3 }
+ for (auto i : v) { }
+autoType()
+ matches "auto n" and "auto i"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('blockPointerType0')"><a name="blockPointerType0Anchor">blockPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="blockPointerType0"><pre>Matches block pointer types, i.e. types syntactically represented as
+"void (^)(int)".
+
+The pointee is always required to be a FunctionType.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('builtinType0')"><a name="builtinType0Anchor">builtinType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BuiltinType.html">BuiltinType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="builtinType0"><pre>Matches builtin Types.
+
+Given
+ struct A {};
+ A a;
+ int b;
+ float c;
+ bool d;
+builtinType()
+ matches "int b", "float c" and "bool d"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('complexType0')"><a name="complexType0Anchor">complexType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="complexType0"><pre>Matches C99 complex types.
+
+Given
+ _Complex float f;
+complexType()
+ matches "_Complex float f"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('constantArrayType0')"><a name="constantArrayType0Anchor">constantArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="constantArrayType0"><pre>Matches C arrays with a specified constant size.
+
+Given
+ void() {
+ int a[2];
+ int b[] = { 2, 3 };
+ int c[b[0]];
+ }
+constantArrayType()
+ matches "int a[2]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('decayedType0')"><a name="decayedType0Anchor">decayedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="decayedType0"><pre>Matches decayed type
+Example matches i[] in declaration of f.
+ (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
+Example matches i[1].
+ (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
+ void f(int i[]) {
+ i[1] = 0;
+ }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('dependentSizedArrayType0')"><a name="dependentSizedArrayType0Anchor">dependentSizedArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DependentSizedArrayType.html">DependentSizedArrayType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="dependentSizedArrayType0"><pre>Matches C++ arrays whose size is a value-dependent expression.
+
+Given
+ template<typename T, int Size>
+ class array {
+ T data[Size];
+ };
+dependentSizedArrayType
+ matches "T data[Size]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('elaboratedType0')"><a name="elaboratedType0Anchor">elaboratedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="elaboratedType0"><pre>Matches types specified with an elaborated type keyword or with a
+qualified name.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ class C {};
+
+ class C c;
+ N::M::D d;
+
+elaboratedType() matches the type of the variable declarations of both
+c and d.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('functionType0')"><a name="functionType0Anchor">functionType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionType.html">FunctionType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="functionType0"><pre>Matches FunctionType nodes.
+
+Given
+ int (*f)(int);
+ void g();
+functionType()
+ matches "int (*f)(int)" and the type of "g".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('incompleteArrayType0')"><a name="incompleteArrayType0Anchor">incompleteArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IncompleteArrayType.html">IncompleteArrayType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="incompleteArrayType0"><pre>Matches C arrays with unspecified size.
+
+Given
+ int a[] = { 2, 3 };
+ int b[42];
+ void f(int c[]) { int d[a[0]]; };
+incompleteArrayType()
+ matches "int a[]" and "int c[]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('injectedClassNameType0')"><a name="injectedClassNameType0Anchor">injectedClassNameType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="injectedClassNameType0"><pre>Matches injected class name types.
+
+Example matches S s, but not S<T> s.
+ (matcher = parmVarDecl(hasType(injectedClassNameType())))
+ template <typename T> struct S {
+ void f(S s);
+ void g(S<T> s);
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('lValueReferenceType0')"><a name="lValueReferenceType0Anchor">lValueReferenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceType.html">LValueReferenceType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="lValueReferenceType0"><pre>Matches lvalue reference types.
+
+Given:
+ int *a;
+ int &b = *a;
+ int &&c = 1;
+ auto &d = b;
+ auto &&e = c;
+ auto &&f = 2;
+ int g = 5;
+
+lValueReferenceType() matches the types of b, d, and e. e is
+matched since the type is deduced as int& by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('memberPointerType0')"><a name="memberPointerType0Anchor">memberPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="memberPointerType0"><pre>Matches member pointer types.
+Given
+ struct A { int i; }
+ A::* ptr = A::i;
+memberPointerType()
+ matches "A::* ptr"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('objcObjectPointerType0')"><a name="objcObjectPointerType0Anchor">objcObjectPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCObjectPointerType.html">ObjCObjectPointerType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="objcObjectPointerType0"><pre>Matches an Objective-C object pointer type, which is different from
+a pointer type, despite being syntactically similar.
+
+Given
+ int *a;
+
+ @interface Foo
+ @end
+ Foo *f;
+pointerType()
+ matches "Foo *f", but does not match "int *a".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('parenType0')"><a name="parenType0Anchor">parenType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="parenType0"><pre>Matches ParenType nodes.
+
+Given
+ int (*ptr_to_array)[4];
+ int *array_of_ptrs[4];
+
+varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
+array_of_ptrs.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('pointerType0')"><a name="pointerType0Anchor">pointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="pointerType0"><pre>Matches pointer types, but does not match Objective-C object pointer
+types.
+
+Given
+ int *a;
+ int &b = *a;
+ int c = 5;
+
+ @interface Foo
+ @end
+ Foo *f;
+pointerType()
+ matches "int *a", but does not match "Foo *f".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('rValueReferenceType0')"><a name="rValueReferenceType0Anchor">rValueReferenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceType.html">RValueReferenceType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="rValueReferenceType0"><pre>Matches rvalue reference types.
+
+Given:
+ int *a;
+ int &b = *a;
+ int &&c = 1;
+ auto &d = b;
+ auto &&e = c;
+ auto &&f = 2;
+ int g = 5;
+
+rValueReferenceType() matches the types of c and f. e is not
+matched as it is deduced to int& by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('recordType0')"><a name="recordType0Anchor">recordType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="recordType0"><pre>Matches record types (e.g. structs, classes).
+
+Given
+ class C {};
+ struct S {};
+
+ C c;
+ S s;
+
+recordType() matches the type of the variable declarations of both c
+and s.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('referenceType0')"><a name="referenceType0Anchor">referenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches both lvalue and rvalue reference types.
+
+Given
+ int *a;
+ int &b = *a;
+ int &&c = 1;
+ auto &d = b;
+ auto &&e = c;
+ auto &&f = 2;
+ int g = 5;
+
+referenceType() matches the types of b, c, d, e, and f.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('substTemplateTypeParmType0')"><a name="substTemplateTypeParmType0Anchor">substTemplateTypeParmType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SubstTemplateTypeParmType.html">SubstTemplateTypeParmType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="substTemplateTypeParmType0"><pre>Matches types that represent the result of substituting a type for a
+template type parameter.
+
+Given
+ template <typename T>
+ void F(T t) {
+ int i = 1 + t;
+ }
+
+substTemplateTypeParmType() matches the type of 't' but not '1'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('templateSpecializationType0')"><a name="templateSpecializationType0Anchor">templateSpecializationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="templateSpecializationType0"><pre>Matches template specialization types.
+
+Given
+ template <typename T>
+ class C { };
+
+ template class C<int>; A
+ C<char> var; B
+
+templateSpecializationType() matches the type of the explicit
+instantiation in A and the type of the variable declaration in B.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('templateTypeParmType0')"><a name="templateTypeParmType0Anchor">templateTypeParmType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="templateTypeParmType0"><pre>Matches template type parameter types.
+
+Example matches T, but not int.
+ (matcher = templateTypeParmType())
+ template <typename T> void f(int i);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('type0')"><a name="type0Anchor">type</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="type0"><pre>Matches Types in the clang AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('typedefType0')"><a name="typedefType0Anchor">typedefType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="typedefType0"><pre>Matches typedef types.
+
+Given
+ typedef int X;
+typedefType()
+ matches "typedef int X"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('unaryTransformType0')"><a name="unaryTransformType0Anchor">unaryTransformType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryTransformType.html">UnaryTransformType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryTransformType0"><pre>Matches types nodes representing unary type transformations.
+
+Given:
+ typedef __underlying_type(T) type;
+unaryTransformType()
+ matches "__underlying_type(T)"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('variableArrayType0')"><a name="variableArrayType0Anchor">variableArrayType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="variableArrayType0"><pre>Matches C arrays with a specified size that is not an
+integer-constant-expression.
+
+Given
+ void f() {
+ int a[] = { 2, 3 }
+ int b[42];
+ int c[a[0]];
+ }
+variableArrayType()
+ matches "int c[a[0]]"
+</pre></td></tr>
+
+<!--END_DECL_MATCHERS -->
+</table>
+
+<!-- ======================================================================= -->
+<h2 id="narrowing-matchers">Narrowing Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Narrowing matchers match certain attributes on the current node, thus
+narrowing down the set of nodes of the current type to match on.</p>
+
+<p>There are special logical narrowing matchers (allOf, anyOf, anything and unless)
+which allow users to create more powerful match expressions.</p>
+
+<table>
+<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
+<!-- START_NARROWING_MATCHERS -->
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('allOf0')"><a name="allOf0Anchor">allOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="allOf0"><pre>Matches if all given matchers match.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('anyOf0')"><a name="anyOf0Anchor">anyOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="anyOf0"><pre>Matches if any of the given matchers matches.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('anything0')"><a name="anything0Anchor">anything</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="anything0"><pre>Matches any node.
+
+Useful when another matcher requires a child matcher, but there's no
+additional constraint. This will often be used with an explicit conversion
+to an internal::Matcher<> type such as TypeMatcher.
+
+Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
+"int* p" and "void f()" in
+ int* p;
+ void f();
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('unless0')"><a name="unless0Anchor">unless</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="unless0"><pre>Matches if the provided matcher does not match.
+
+Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
+ class X {};
+ class Y {};
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName0')"><a name="hasOperatorName0Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions (binary or
+unary).
+
+Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+ !(a || b)
+</pre></td></tr>
+
+
+<tr><td>Matcher<CXXBoolLiteral></td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = cxxBoolLiteral(equals(true)))
+ true
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>></td><td class="name" onclick="toggle('isCatchAll0')"><a name="isCatchAll0Anchor">isCatchAll</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isCatchAll0"><pre>Matches a C++ catch statement that has a catch-all handler.
+
+Given
+ try {
+ ...
+ } catch (int) {
+ ...
+ } catch (...) {
+ ...
+ }
+endcode
+cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs1')"><a name="argumentCountIs1Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('isListInitialization0')"><a name="isListInitialization0Anchor">isListInitialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isListInitialization0"><pre>Matches a constructor call expression which uses list initialization.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isCopyConstructor0')"><a name="isCopyConstructor0Anchor">isCopyConstructor</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isCopyConstructor0"><pre>Matches constructor declarations that are copy constructors.
+
+Given
+ struct S {
+ S(); #1
+ S(const S &); #2
+ S(S &&); #3
+ };
+cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isDefaultConstructor0')"><a name="isDefaultConstructor0Anchor">isDefaultConstructor</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefaultConstructor0"><pre>Matches constructor declarations that are default constructors.
+
+Given
+ struct S {
+ S(); #1
+ S(const S &); #2
+ S(S &&); #3
+ };
+cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isExplicit0')"><a name="isExplicit0Anchor">isExplicit</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor and conversion declarations that are marked with
+the explicit keyword.
+
+Given
+ struct S {
+ S(int); #1
+ explicit S(double); #2
+ operator int(); #3
+ explicit operator bool(); #4
+ };
+cxxConstructorDecl(isExplicit()) will match #2, but not #1.
+cxxConversionDecl(isExplicit()) will match #4, but not #3.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isMoveConstructor0')"><a name="isMoveConstructor0Anchor">isMoveConstructor</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isMoveConstructor0"><pre>Matches constructor declarations that are move constructors.
+
+Given
+ struct S {
+ S(); #1
+ S(const S &); #2
+ S(S &&); #3
+ };
+cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>></td><td class="name" onclick="toggle('isExplicit1')"><a name="isExplicit1Anchor">isExplicit</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicit1"><pre>Matches constructor and conversion declarations that are marked with
+the explicit keyword.
+
+Given
+ struct S {
+ S(int); #1
+ explicit S(double); #2
+ operator int(); #3
+ explicit operator bool(); #4
+ };
+cxxConstructorDecl(isExplicit()) will match #2, but not #1.
+cxxConversionDecl(isExplicit()) will match #4, but not #3.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isBaseInitializer0')"><a name="isBaseInitializer0Anchor">isBaseInitializer</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isBaseInitializer0"><pre>Matches a constructor initializer if it is initializing a base, as
+opposed to a member.
+
+Given
+ struct B {};
+ struct D : B {
+ int I;
+ D(int i) : I(i) {}
+ };
+ struct E : B {
+ E() : B() {}
+ };
+cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer()))
+ will match E(), but not match D(int).
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isMemberInitializer0')"><a name="isMemberInitializer0Anchor">isMemberInitializer</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isMemberInitializer0"><pre>Matches a constructor initializer if it is initializing a member, as
+opposed to a base.
+
+Given
+ struct B {};
+ struct D : B {
+ int I;
+ D(int i) : I(i) {}
+ };
+ struct E : B {
+ E() : B() {}
+ };
+cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer()))
+ will match D(int), but not match E().
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('isWritten0')"><a name="isWritten0Anchor">isWritten</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isWritten0"><pre>Matches a constructor initializer if it is explicitly written in
+code (as opposed to implicitly added by the compiler).
+
+Given
+ struct Foo {
+ Foo() { }
+ Foo(int) : foo_("A") { }
+ string foo_;
+ };
+cxxConstructorDecl(hasAnyConstructorInitializer(isWritten()))
+ will match Foo(int), but not Foo()
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
+
+Given
+struct A {
+ void foo() const;
+ void bar();
+};
+
+cxxMethodDecl(isConst()) matches A::foo() but not A::bar()
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isCopyAssignmentOperator0')"><a name="isCopyAssignmentOperator0Anchor">isCopyAssignmentOperator</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isCopyAssignmentOperator0"><pre>Matches if the given method declaration declares a copy assignment
+operator.
+
+Given
+struct A {
+ A &operator=(const A &);
+ A &operator=(A &&);
+};
+
+cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not
+the second one.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isFinal1')"><a name="isFinal1Anchor">isFinal</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isFinal1"><pre>Matches if the given method or class declaration is final.
+
+Given:
+ class A final {};
+
+ struct B {
+ virtual void f();
+ };
+
+ struct C : B {
+ void f() final;
+ };
+matches A and C::f, but not B, C, or B::f
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isOverride0')"><a name="isOverride0Anchor">isOverride</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isOverride0"><pre>Matches if the given method declaration overrides another method.
+
+Given
+ class A {
+ public:
+ virtual void x();
+ };
+ class B : public A {
+ public:
+ virtual void x();
+ };
+ matches B::x
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isPure0')"><a name="isPure0Anchor">isPure</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isPure0"><pre>Matches if the given method declaration is pure.
+
+Given
+ class A {
+ public:
+ virtual void x() = 0;
+ };
+ matches A::x
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isVirtual0')"><a name="isVirtual0Anchor">isVirtual</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isVirtual0"><pre>Matches if the given method declaration is virtual.
+
+Given
+ class A {
+ public:
+ virtual void x();
+ };
+ matches A::x
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "<<".
+
+Given:
+ class A { int operator*(); };
+ const A &operator<<(const A &a, const A &b);
+ A a;
+ a << a; <-- This matches
+
+cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
+specified line and
+cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
+matches the declaration of A.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template<typename T> void A(T t) { }
+ template<> void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A<int>().
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isFinal0')"><a name="isFinal0Anchor">isFinal</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isFinal0"><pre>Matches if the given method or class declaration is final.
+
+Given:
+ class A final {};
+
+ struct B {
+ virtual void f();
+ };
+
+ struct C : B {
+ void f() final;
+ };
+matches A and C::f, but not B, C, or B::f
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for
+isSameOrDerivedFrom(hasName(...)).
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template <typename T> class X {}; class A {}; X<A> x;
+or
+ template <typename T> class X {}; class A {}; template class X<A>;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X<A>.
+
+But given
+ template <typename T> class X {}; class A {};
+ template <> class X<A> {}; X<A> x;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X<A> is an explicit template specialization.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('argumentCountIs0')"><a name="argumentCountIs0Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs0"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals3')"><a name="equals3Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = cxxBoolLiteral(equals(true)))
+ true
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('templateArgumentCountIs0')"><a name="templateArgumentCountIs0Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgumentCountIs0"><pre>Matches if the number of template arguments equals N.
+
+Given
+ template<typename T> struct C {};
+ C<int> c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+ matches C<int>.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>></td><td class="name" onclick="toggle('statementCountIs0')"><a name="statementCountIs0Anchor">statementCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="statementCountIs0"><pre>Checks that a compound statement contains a specific number of
+child statements.
+
+Example: Given
+ { for (;;) {} }
+compoundStmt(statementCountIs(0)))
+ matches '{}'
+ but does not match the outer compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>></td><td class="name" onclick="toggle('hasSize0')"><a name="hasSize0Anchor">hasSize</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="hasSize0"><pre>Matches ConstantArrayType nodes that have the specified size.
+
+Given
+ int a[42];
+ int b[2 * 21];
+ int c[41], d[43];
+constantArrayType(hasSize(42))
+ matches "int a[42]" and "int b[2 * 21]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('declCountIs0')"><a name="declCountIs0Anchor">declCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="declCountIs0"><pre>Matches declaration statements that contain a specific number of
+declarations.
+
+Example: Given
+ int a, b;
+ int c;
+ int d = 2, e;
+declCountIs(2)
+ matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('equalsBoundNode1')"><a name="equalsBoundNode1Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode1"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+cxxRecordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasAttr0')"><a name="hasAttr0Anchor">hasAttr</a></td><td>attr::Kind AttrKind</td></tr>
+<tr><td colspan="4" class="doc" id="hasAttr0"><pre>Matches declaration that has a given attribute.
+
+Given
+ __attribute__((device)) void f() { ... }
+decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
+f. If the matcher is use from clang-query, attr::Kind parameter should be
+passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching0')"><a name="isExpansionInFileMatching0Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching0"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInMainFile0')"><a name="isExpansionInMainFile0Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile0"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y
+ (matcher = cxxRecordDecl(isExpansionInMainFile())
+ #include <Y.h>
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader0')"><a name="isExpansionInSystemHeader0Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader0"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+ #include <SystemHeader.h>
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches a declaration that has been implicitly added
+by the compiler (eg. implicit defaultcopy constructors).
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isPrivate())
+ matches 'int c;'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isProtected0')"><a name="isProtected0Anchor">isProtected</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isProtected0"><pre>Matches protected C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isProtected())
+ matches 'int b;'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isPublic0')"><a name="isPublic0Anchor">isPublic</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isPublic0"><pre>Matches public C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isPublic())
+ matches 'int a;'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>></td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = cxxBoolLiteral(equals(true)))
+ true
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "<<".
+
+Given:
+ class A { int operator*(); };
+ const A &operator<<(const A &a, const A &b);
+ A a;
+ a << a; <-- This matches
+
+cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the
+specified line and
+cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*")))
+matches the declaration of A.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isConstexpr1')"><a name="isConstexpr1Anchor">isConstexpr</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConstexpr1"><pre>Matches constexpr variable and function declarations.
+
+Given:
+ constexpr int foo = 42;
+ constexpr int bar();
+varDecl(isConstexpr())
+ matches the declaration of foo.
+functionDecl(isConstexpr())
+ matches the declaration of bar.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDefaulted0')"><a name="isDefaulted0Anchor">isDefaulted</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefaulted0"><pre>Matches defaulted function declarations.
+
+Given:
+ class A { ~A(); };
+ class B { ~B() = default; };
+functionDecl(isDefaulted())
+ matches the declaration of ~B, but not ~A.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isDeleted0')"><a name="isDeleted0Anchor">isDeleted</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDeleted0"><pre>Matches deleted function declarations.
+
+Given:
+ void Func();
+ void DeletedFunc() = delete;
+functionDecl(isDeleted())
+ matches the declaration of DeletedFunc, but not Func.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template<typename T> void A(T t) { }
+ template<> void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A<int>().
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function declarations.
+
+Given:
+ extern "C" void f() {}
+ extern "C" { void g() {} }
+ void h() {}
+functionDecl(isExternC())
+ matches the declaration of f and g, but not the declaration h
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isInline1')"><a name="isInline1Anchor">isInline</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInline1"><pre>Matches function and namespace declarations that are marked with
+the inline keyword.
+
+Given
+ inline void f();
+ void g();
+ namespace n {
+ inline namespace m {}
+ }
+functionDecl(isInline()) will match ::f().
+namespaceDecl(isInline()) will match n::m.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isNoThrow0')"><a name="isNoThrow0Anchor">isNoThrow</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isNoThrow0"><pre>Matches functions that have a non-throwing exception specification.
+
+Given:
+ void f();
+ void g() noexcept;
+ void h() throw();
+ void i() throw(int);
+ void j() noexcept(false);
+functionDecl(isNoThrow())
+ matches the declarations of g, and h, but not f, i or j.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation0')"><a name="isTemplateInstantiation0Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation0"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template <typename T> class X {}; class A {}; X<A> x;
+or
+ template <typename T> class X {}; class A {}; template class X<A>;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X<A>.
+
+But given
+ template <typename T> class X {}; class A {};
+ template <> class X<A> {}; X<A> x;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X<A> is an explicit template specialization.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('isVariadic0')"><a name="isVariadic0Anchor">isVariadic</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isVariadic0"><pre>Matches if a function declaration is variadic.
+
+Example matches f, but not g or h. The function i will not match, even when
+compiled in C mode.
+ void f(...);
+ void g(int);
+ template <typename... Ts> void h(Ts...);
+ void i();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('parameterCountIs0')"><a name="parameterCountIs0Anchor">parameterCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="parameterCountIs0"><pre>Matches FunctionDecls that have a specific parameter count.
+
+Given
+ void f(int i) {}
+ void g(int i, int j) {}
+functionDecl(parameterCountIs(2))
+ matches g(int i, int j) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = cxxBoolLiteral(equals(true)))
+ true
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '->' as opposed
+to '.'.
+
+Member calls on the implicit this pointer match as called with '->'.
+
+Given
+ class Y {
+ void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+ int a;
+ static int b;
+ };
+memberExpr(isArrow())
+ matches this->x, x, y.x, a, this->b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('hasName0')"><a name="hasName0Anchor">hasName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasName0"><pre>Matches NamedDecl nodes that have the specified name.
+
+Supports specifying enclosing namespaces or classes by prefixing the name
+with '<enclosing>::'.
+Does not match typedefs of an underlying type with the given name.
+
+Example matches X (Name == "X")
+ class X;
+
+Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
+ namespace a { namespace b { class X; } }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose fully qualified names contain
+a substring matched by the given RegExp.
+
+Supports specifying enclosing namespaces or classes by
+prefixing the name with '<enclosing>::'. Does not match typedefs
+of an underlying type with the given name.
+
+Example matches X (regexp == "::X")
+ class X;
+
+Example matches X (regexp is one of "::X", "^foo::.*X", among others)
+ namespace foo { namespace bar { class X; } }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>></td><td class="name" onclick="toggle('isAnonymous0')"><a name="isAnonymous0Anchor">isAnonymous</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isAnonymous0"><pre>Matches anonymous namespace declarations.
+
+Given
+ namespace n {
+ namespace {} #1
+ }
+namespaceDecl(isAnonymous()) will match #1 but not ::n.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>></td><td class="name" onclick="toggle('isInline0')"><a name="isInline0Anchor">isInline</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInline0"><pre>Matches function and namespace declarations that are marked with
+the inline keyword.
+
+Given
+ inline void f();
+ void g();
+ namespace n {
+ inline namespace m {}
+ }
+functionDecl(isInline()) will match ::f().
+namespaceDecl(isInline()) will match n::m.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasKeywordSelector0')"><a name="hasKeywordSelector0Anchor">hasKeywordSelector</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasKeywordSelector0"><pre>Matches when the selector is a keyword selector
+
+objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
+message expression in
+
+ UIWebView *webView = ...;
+ CGRect bodyFrame = webView.frame;
+ bodyFrame.size.height = self.bodyContentHeight;
+ webView.frame = bodyFrame;
+ ^---- matches here
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasNullSelector0')"><a name="hasNullSelector0Anchor">hasNullSelector</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasNullSelector0"><pre>Matches when the selector is the empty selector
+
+Matches only when the selector of the objCMessageExpr is NULL. This may
+represent an error condition in the tree!
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasSelector0')"><a name="hasSelector0Anchor">hasSelector</a></td><td>std::string BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="hasSelector0"><pre>Matches when BaseName == Selector.getAsString()
+
+ matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
+ matches the outer message expr in the code below, but NOT the message
+ invocation for self.bodyView.
+ [self.bodyView loadHTMLString:html baseURL:NULL];
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasUnarySelector0')"><a name="hasUnarySelector0Anchor">hasUnarySelector</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasUnarySelector0"><pre>Matches when the selector is a Unary Selector
+
+ matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
+ matches self.bodyView in the code below, but NOT the outer message
+ invocation of "loadHTMLString:baseURL:".
+ [self.bodyView loadHTMLString:html baseURL:NULL];
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="matchesSelector0"><pre>Matches ObjC selectors whose name contains
+a substring matched by the given RegExp.
+ matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
+ invocation for self.bodyView.
+ [self.bodyView loadHTMLString:html baseURL:NULL];
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('numSelectorArgs0')"><a name="numSelectorArgs0Anchor">numSelectorArgs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="numSelectorArgs0"><pre>Matches when the selector has the specified number of arguments
+
+ matcher = objCMessageExpr(numSelectorArgs(0));
+ matches self.bodyView in the code below
+
+ matcher = objCMessageExpr(numSelectorArgs(2));
+ matches the invocation of "loadHTMLString:baseURL:" but not that
+ of self.bodyView
+ [self.bodyView loadHTMLString:html baseURL:NULL];
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('asString0')"><a name="asString0Anchor">asString</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="asString0"><pre>Matches if the matched type is represented by the given string.
+
+Given
+ class Y { public: void x(); };
+ void z() { Y* y; y->x(); }
+cxxMemberCallExpr(on(hasType(asString("class Y *"))))
+ matches y->x()
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('equalsBoundNode3')"><a name="equalsBoundNode3Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode3"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+cxxRecordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasLocalQualifiers0')"><a name="hasLocalQualifiers0Anchor">hasLocalQualifiers</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasLocalQualifiers0"><pre>Matches QualType nodes that have local CV-qualifiers attached to
+the node, not hidden within a typedef.
+
+Given
+ typedef const int const_int;
+ const_int i;
+ int *const j;
+ int *volatile k;
+ int m;
+varDecl(hasType(hasLocalQualifiers())) matches only j and k.
+i is const-qualified but the qualifier is not local.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isAnyCharacter0')"><a name="isAnyCharacter0Anchor">isAnyCharacter</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isAnyCharacter0"><pre>Matches QualType nodes that are of character type.
+
+Given
+ void a(char);
+ void b(wchar_t);
+ void c(double);
+functionDecl(hasAnyParameter(hasType(isAnyCharacter())))
+matches "a(char)", "b(wchar_t)", but not "c(double)".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isConstQualified0')"><a name="isConstQualified0Anchor">isConstQualified</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConstQualified0"><pre>Matches QualType nodes that are const-qualified, i.e., that
+include "top-level" const.
+
+Given
+ void a(int);
+ void b(int const);
+ void c(const int);
+ void d(const int*);
+ void e(int const) {};
+functionDecl(hasAnyParameter(hasType(isConstQualified())))
+ matches "void b(int const)", "void c(const int)" and
+ "void e(int const) {}". It does not match d as there
+ is no top-level const on the parameter type "const int *".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isInteger0')"><a name="isInteger0Anchor">isInteger</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInteger0"><pre>Matches QualType nodes that are of integer type.
+
+Given
+ void a(int);
+ void b(long);
+ void c(double);
+functionDecl(hasAnyParameter(hasType(isInteger())))
+matches "a(int)", "b(long)", but not "c(double)".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('isVolatileQualified0')"><a name="isVolatileQualified0Anchor">isVolatileQualified</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isVolatileQualified0"><pre>Matches QualType nodes that are volatile-qualified, i.e., that
+include "top-level" volatile.
+
+Given
+ void a(int);
+ void b(int volatile);
+ void c(volatile int);
+ void d(volatile int*);
+ void e(int volatile) {};
+functionDecl(hasAnyParameter(hasType(isVolatileQualified())))
+ matches "void b(int volatile)", "void c(volatile int)" and
+ "void e(int volatile) {}". It does not match d as there
+ is no top-level volatile on the parameter type "volatile int *".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isClass0')"><a name="isClass0Anchor">isClass</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isClass0"><pre>Matches RecordDecl object that are spelled with "class."
+
+Example matches C, but not S or U.
+ struct S {};
+ class C {};
+ union U {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isStruct0')"><a name="isStruct0Anchor">isStruct</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isStruct0"><pre>Matches RecordDecl object that are spelled with "struct."
+
+Example matches S, but not C or U.
+ struct S {};
+ class C {};
+ union U {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordDecl.html">RecordDecl</a>></td><td class="name" onclick="toggle('isUnion0')"><a name="isUnion0Anchor">isUnion</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isUnion0"><pre>Matches RecordDecl object that are spelled with "union."
+
+Example matches U, but not C or S.
+ struct S {};
+ class C {};
+ union U {};
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('equalsBoundNode0')"><a name="equalsBoundNode0Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode0"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+cxxRecordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching1')"><a name="isExpansionInFileMatching1Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching1"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInMainFile1')"><a name="isExpansionInMainFile1Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile1"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y
+ (matcher = cxxRecordDecl(isExpansionInMainFile())
+ #include <Y.h>
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader1')"><a name="isExpansionInSystemHeader1Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader1"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+ #include <SystemHeader.h>
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('equalsIntegralValue0')"><a name="equalsIntegralValue0Anchor">equalsIntegralValue</a></td><td>std::string Value</td></tr>
+<tr><td colspan="4" class="doc" id="equalsIntegralValue0"><pre>Matches a TemplateArgument of integral type with a given value.
+
+Note that 'Value' is a string as the template argument's value is
+an arbitrary precision integer. 'Value' must be euqal to the canonical
+representation of that integral value in base 10.
+
+Given
+ template<int T> struct A {};
+ C<42> c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("42")))
+ matches the implicit instantiation of C in C<42>.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('isIntegral0')"><a name="isIntegral0Anchor">isIntegral</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isIntegral0"><pre>Matches a TemplateArgument that is an integral value.
+
+Given
+ template<int T> struct A {};
+ C<42> c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(isIntegral()))
+ matches the implicit instantiation of C in C<42>
+ with isIntegral() matching 42.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('templateArgumentCountIs1')"><a name="templateArgumentCountIs1Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="templateArgumentCountIs1"><pre>Matches if the number of template arguments equals N.
+
+Given
+ template<typename T> struct C {};
+ C<int> c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+ matches C<int>.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching2')"><a name="isExpansionInFileMatching2Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInFileMatching2"><pre>Matches AST nodes that were expanded within files whose name is
+partially matching a given regex.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
+ #include "ASTMatcher.h"
+ class X {};
+ASTMatcher.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInMainFile2')"><a name="isExpansionInMainFile2Anchor">isExpansionInMainFile</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInMainFile2"><pre>Matches AST nodes that were expanded within the main-file.
+
+Example matches X but not Y
+ (matcher = cxxRecordDecl(isExpansionInMainFile())
+ #include <Y.h>
+ class X {};
+Y.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInSystemHeader2')"><a name="isExpansionInSystemHeader2Anchor">isExpansionInSystemHeader</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExpansionInSystemHeader2"><pre>Matches AST nodes that were expanded within system-header-files.
+
+Example matches Y but not X
+ (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+ #include <SystemHeader.h>
+ class X {};
+SystemHeader.h:
+ class Y {};
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('booleanType0')"><a name="booleanType0Anchor">booleanType</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="booleanType0"><pre>Matches type bool.
+
+Given
+ struct S { bool func(); };
+functionDecl(returns(booleanType()))
+ matches "bool func();"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('equalsBoundNode2')"><a name="equalsBoundNode2Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
+<tr><td colspan="4" class="doc" id="equalsBoundNode2"><pre>Matches if a node equals a previously bound node.
+
+Matches a node if it equals the node previously bound to ID.
+
+Given
+ class X { int a; int b; };
+cxxRecordDecl(
+ has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+ has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+ matches the class X, as a and b have the same type.
+
+Note that when multiple matches are involved via forEach* matchers,
+equalsBoundNodes acts as a filter.
+For example:
+compoundStmt(
+ forEachDescendant(varDecl().bind("d")),
+ forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+will trigger a match for each combination of variable declaration
+and reference to that variable declaration within a compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('voidType0')"><a name="voidType0Anchor">voidType</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="voidType0"><pre>Matches type void.
+
+Given
+ struct S { void func(); };
+functionDecl(returns(voidType()))
+ matches "void func();"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>></td><td class="name" onclick="toggle('ofKind0')"><a name="ofKind0Anchor">ofKind</a></td><td>UnaryExprOrTypeTrait Kind</td></tr>
+<tr><td colspan="4" class="doc" id="ofKind0"><pre>Matches unary expressions of a certain kind.
+
+Given
+ int x;
+ int s = sizeof(x) + alignof(x)
+unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
+ matches sizeof(x)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName1')"><a name="hasOperatorName1Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions (binary or
+unary).
+
+Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+ !(a || b)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasAutomaticStorageDuration0')"><a name="hasAutomaticStorageDuration0Anchor">hasAutomaticStorageDuration</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasAutomaticStorageDuration0"><pre>Matches a variable declaration that has automatic storage duration.
+
+Example matches x, but not y, z, or a.
+(matcher = varDecl(hasAutomaticStorageDuration())
+void f() {
+ int x;
+ static int y;
+ thread_local int z;
+}
+int a;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasGlobalStorage0')"><a name="hasGlobalStorage0Anchor">hasGlobalStorage</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasGlobalStorage0"><pre>Matches a variable declaration that does not have local storage.
+
+Example matches y and z (matcher = varDecl(hasGlobalStorage())
+void f() {
+ int x;
+ static int y;
+}
+int z;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasLocalStorage0')"><a name="hasLocalStorage0Anchor">hasLocalStorage</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasLocalStorage0"><pre>Matches a variable declaration that has function scope and is a
+non-static local variable.
+
+Example matches x (matcher = varDecl(hasLocalStorage())
+void f() {
+ int x;
+ static int y;
+}
+int z;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasStaticStorageDuration0')"><a name="hasStaticStorageDuration0Anchor">hasStaticStorageDuration</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasStaticStorageDuration0"><pre>Matches a variable declaration that has static storage duration.
+
+Example matches y and a, but not x or z.
+(matcher = varDecl(hasStaticStorageDuration())
+void f() {
+ int x;
+ static int y;
+ thread_local int z;
+}
+int a;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasThreadStorageDuration0')"><a name="hasThreadStorageDuration0Anchor">hasThreadStorageDuration</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasThreadStorageDuration0"><pre>Matches a variable declaration that has thread storage duration.
+
+Example matches z, but not x, z, or a.
+(matcher = varDecl(hasThreadStorageDuration())
+void f() {
+ int x;
+ static int y;
+ thread_local int z;
+}
+int a;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isConstexpr0')"><a name="isConstexpr0Anchor">isConstexpr</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConstexpr0"><pre>Matches constexpr variable and function declarations.
+
+Given:
+ constexpr int foo = 42;
+ constexpr int bar();
+varDecl(isConstexpr())
+ matches the declaration of foo.
+functionDecl(isConstexpr())
+ matches the declaration of bar.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isDefinition1')"><a name="isDefinition1Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition1"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isExceptionVariable0')"><a name="isExceptionVariable0Anchor">isExceptionVariable</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExceptionVariable0"><pre>Matches a variable declaration that is an exception variable from
+a C++ catch block, or an Objective-C statement.
+
+Example matches x (matcher = varDecl(isExceptionVariable())
+void f(int y) {
+ try {
+ } catch (int x) {
+ }
+}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization1')"><a name="isExplicitTemplateSpecialization1Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization1"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template<typename T> void A(T t) { }
+ template<> void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A<int>().
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation1')"><a name="isTemplateInstantiation1Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation1"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template <typename T> class X {}; class A {}; X<A> x;
+or
+ template <typename T> class X {}; class A {}; template class X<A>;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X<A>.
+
+But given
+ template <typename T> class X {}; class A {};
+ template <> class X<A> {}; X<A> x;
+cxxRecordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X<A> is an explicit template specialization.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>></td><td class="name" onclick="toggle('isInstantiated0')"><a name="isInstantiated0Anchor">isInstantiated</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInstantiated0"><pre>Matches declarations that are template instantiations or are inside
+template instantiations.
+
+Given
+ template<typename T> void A(T t) { T i; }
+ A(0);
+ A(0U);
+functionDecl(isInstantiated())
+ matches 'A(int) {...};' and 'A(unsigned) {...}'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>></td><td class="name" onclick="toggle('isInTemplateInstantiation0')"><a name="isInTemplateInstantiation0Anchor">isInTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInTemplateInstantiation0"><pre>Matches statements inside of a template instantiation.
+
+Given
+ int j;
+ template<typename T> void A(T t) { T i; j += 42;}
+ A(0);
+ A(0U);
+declStmt(isInTemplateInstantiation())
+ matches 'int i;' and 'unsigned i'.
+unless(stmt(isInTemplateInstantiation()))
+ will NOT match j += 42; as it's shared between the template definition and
+ instantiation.
+</pre></td></tr>
+
+<!--END_NARROWING_MATCHERS -->
+</table>
+
+<!-- ======================================================================= -->
+<h2 id="traversal-matchers">AST Traversal Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Traversal matchers specify the relationship to other nodes that are
+reachable from the current node.</p>
+
+<p>Note that there are special traversal matchers (has, hasDescendant, forEach and
+forEachDescendant) which work on all nodes and allow users to write more generic
+match expressions.</p>
+
+<table>
+<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
+<!-- START_TRAVERSAL_MATCHERS -->
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('eachOf0')"><a name="eachOf0Anchor">eachOf</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="eachOf0"><pre>Matches if any of the given matchers matches.
+
+Unlike anyOf, eachOf will generate a match result for each
+matching submatcher.
+
+For example, in:
+ class A { int a; int b; };
+The matcher:
+ cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v"))))
+will generate two results binding "v", the first of which binds
+the field declaration of a, the second the field declaration of
+b.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('forEachDescendant0')"><a name="forEachDescendant0Anchor">forEachDescendant</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="forEachDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
+provided matcher.
+
+Example matches X, A, B, C
+ (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class A { class X {}; };
+ class B { class C { class X {}; }; };
+
+DescendantT must be an AST base type.
+
+As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
+each result that matches instead of only on the first one.
+
+Note: Recursively combined ForEachDescendant can cause many matches:
+ cxxRecordDecl(forEachDescendant(cxxRecordDecl(
+ forEachDescendant(cxxRecordDecl())
+ )))
+will match 10 times (plus injected class name matches) on:
+ class A { class B { class C { class D { class E {}; }; }; }; };
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
+provided matcher.
+
+Example matches X, Y
+ (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; }; Does not match Z.
+
+ChildT must be an AST base type.
+
+As opposed to 'has', 'forEach' will cause a match for each result that
+matches instead of only on the first one.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasAncestor0')"><a name="hasAncestor0Anchor">hasAncestor</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="hasAncestor0"><pre>Matches AST nodes that have an ancestor that matches the provided
+matcher.
+
+Given
+void f() { if (true) { int x = 42; } }
+void g() { for (;;) { int x = 43; } }
+expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasDescendant0')"><a name="hasDescendant0Anchor">hasDescendant</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="hasDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
+provided matcher.
+
+Example matches X, Y, Z
+ (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; };
+
+DescendantT must be an AST base type.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('has0')"><a name="has0Anchor">has</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="has0"><pre>Matches AST nodes that have child AST nodes that match the
+provided matcher.
+
+Example matches X, Y
+ (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; }; Does not match Z.
+
+ChildT must be an AST base type.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasParent0')"><a name="hasParent0Anchor">hasParent</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="hasParent0"><pre>Matches AST nodes that have a parent that matches the provided
+matcher.
+
+Given
+void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasBase0')"><a name="hasBase0Anchor">hasBase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBase0"><pre>Matches the base expression of an array subscript expression.
+
+Given
+ int i[5];
+ void f() { i[1] = 42; }
+arraySubscriptExpression(hasBase(implicitCastExpr(
+ hasSourceExpression(declRefExpr()))))
+ matches i[1] with the declRefExpr() matching i
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasIndex0')"><a name="hasIndex0Anchor">hasIndex</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasIndex0"><pre>Matches the index expression of an array subscript expression.
+
+Given
+ int i[5];
+ void f() { i[1] = 42; }
+arraySubscriptExpression(hasIndex(integerLiteral()))
+ matches i[1] with the integerLiteral() matching 1
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasLHS1')"><a name="hasLHS1Anchor">hasLHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasLHS1"><pre>Matches the left hand side of binary operator expressions.
+
+Example matches a (matcher = binaryOperator(hasLHS()))
+ a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>></td><td class="name" onclick="toggle('hasRHS1')"><a name="hasRHS1Anchor">hasRHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasRHS1"><pre>Matches the right hand side of binary operator expressions.
+
+Example matches b (matcher = binaryOperator(hasRHS()))
+ a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>></td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicTypeLoc.html">AtomicTypeLoc</a>></td><td class="name" onclick="toggle('hasValueTypeLoc0')"><a name="hasValueTypeLoc0Anchor">hasValueTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasValueTypeLoc0"><pre>Matches atomic types with a specific value type.
+
+Given
+ _Atomic(int) i;
+ _Atomic(float) f;
+atomicType(hasValueType(isInteger()))
+ matches "_Atomic(int) i"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>></td><td class="name" onclick="toggle('hasValueType0')"><a name="hasValueType0Anchor">hasValueType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasValueType0"><pre>Matches atomic types with a specific value type.
+
+Given
+ _Atomic(int) i;
+ _Atomic(float) f;
+atomicType(hasValueType(isInteger()))
+ matches "_Atomic(int) i"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>></td><td class="name" onclick="toggle('hasDeducedType0')"><a name="hasDeducedType0Anchor">hasDeducedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasDeducedType0"><pre>Matches AutoType nodes where the deduced type is a specific type.
+
+Note: There is no TypeLoc for the deduced type and thus no
+getDeducedLoc() matcher.
+
+Given
+ auto a = 1;
+ auto b = 2.0;
+autoType(hasDeducedType(isInteger()))
+ matches "auto a"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a
+binary operator matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasLHS0')"><a name="hasLHS0Anchor">hasLHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasLHS0"><pre>Matches the left hand side of binary operator expressions.
+
+Example matches a (matcher = binaryOperator(hasLHS()))
+ a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasRHS0')"><a name="hasRHS0Anchor">hasRHS</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasRHS0"><pre>Matches the right hand side of binary operator expressions.
+
+Example matches b (matcher = binaryOperator(hasRHS()))
+ a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>></td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('forEachArgumentWithParam1')"><a name="forEachArgumentWithParam1Anchor">forEachArgumentWithParam</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> ArgMatcher, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> ParamMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachArgumentWithParam1"><pre>Matches all arguments and their respective ParmVarDecl.
+
+Given
+ void f(int i);
+ int y;
+ f(y);
+callExpr(declRefExpr(to(varDecl(hasName("y")))),
+parmVarDecl(hasType(isInteger())))
+ matches f(y);
+with declRefExpr(...)
+ matching int y
+and parmVarDecl(...)
+ matching int i
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument1')"><a name="hasAnyArgument1Anchor">hasAnyArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyArgument1"><pre>Matches any argument of a call expression or a constructor call
+expression.
+
+Given
+ void x(int, int, int) { int y; x(1, y, 42); }
+callExpr(hasAnyArgument(declRefExpr()))
+ matches x(1, y, 42)
+with hasAnyArgument(...)
+ matching y
+
+FIXME: Currently this will ignore parentheses and implicit casts on
+the argument before applying the inner matcher. We'll want to remove
+this to allow for greater control by the user once ignoreImplicit()
+has been implemented.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasArgument1')"><a name="hasArgument1Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument1"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasDeclaration12')"><a name="hasDeclaration12Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration12"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('forEachConstructorInitializer0')"><a name="forEachConstructorInitializer0Anchor">forEachConstructorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachConstructorInitializer0"><pre>Matches each constructor initializer in a constructor definition.
+
+Given
+ class A { A() : i(42), j(42) {} int i; int j; };
+cxxConstructorDecl(forEachConstructorInitializer(
+ forField(decl().bind("x"))
+))
+ will trigger two matches, binding for 'i' and 'j' respectively.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('hasAnyConstructorInitializer0')"><a name="hasAnyConstructorInitializer0Anchor">hasAnyConstructorInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyConstructorInitializer0"><pre>Matches a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+cxxRecordDecl(has(cxxConstructorDecl(
+ hasAnyConstructorInitializer(anything())
+)))
+ record matches Foo, hasAnyConstructorInitializer matches foo_(1)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('forField0')"><a name="forField0Anchor">forField</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forField0"><pre>Matches the field declaration of a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
+ forField(hasName("foo_"))))))
+ matches Foo
+with forField matching foo_
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('withInitializer0')"><a name="withInitializer0Anchor">withInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="withInitializer0"><pre>Matches the initializer expression of a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer(
+ withInitializer(integerLiteral(equals(1)))))))
+ matches Foo
+with withInitializer matching (1)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasBody3')"><a name="hasBody3Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody3"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasLoopVariable0')"><a name="hasLoopVariable0Anchor">hasLoopVariable</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasLoopVariable0"><pre>Matches the initialization statement of a for loop.
+
+Example:
+ forStmt(hasLoopVariable(anything()))
+matches 'int x' in
+ for (int x : a) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasRangeInit0')"><a name="hasRangeInit0Anchor">hasRangeInit</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasRangeInit0"><pre>Matches the range initialization statement of a for loop.
+
+Example:
+ forStmt(hasRangeInit(anything()))
+matches 'a' in
+ for (int x : a) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('onImplicitObjectArgument0')"><a name="onImplicitObjectArgument0Anchor">onImplicitObjectArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="onImplicitObjectArgument0"><pre></pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('on0')"><a name="on0Anchor">on</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="on0"><pre>Matches on the implicit object argument of a member call expression.
+
+Example matches y.x()
+ (matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))))
+ class Y { public: void x(); };
+ void z() { Y y; y.x(); }",
+
+FIXME: Overload to allow directly matching types?
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType1')"><a name="thisPointerType1Anchor">thisPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="thisPointerType1"><pre>Overloaded to match the type's declaration.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>></td><td class="name" onclick="toggle('thisPointerType0')"><a name="thisPointerType0Anchor">thisPointerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="thisPointerType0"><pre>Matches if the expression's type either matches the specified
+matcher, or is a pointer to a type that matches the InnerMatcher.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('ofClass0')"><a name="ofClass0Anchor">ofClass</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ofClass0"><pre>Matches the class declaration that the given method declaration
+belongs to.
+
+FIXME: Generalize this for other kinds of declarations.
+FIXME: What other kind of declarations would we need to generalize
+this to?
+
+Example matches A() in the last line
+ (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl(
+ ofClass(hasName("A"))))))
+ class A {
+ public:
+ A();
+ };
+ A a = A();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
+
+Given:
+ class A { void func(); };
+ class B { void member(); };
+
+cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
+A but not B.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
+<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>Matches C++ classes that are directly or indirectly derived from
+a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+ class X;
+ class Y : public X {}; directly derived
+ class Z : public Y {}; indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; derived from a typedef of X
+
+In the following example, Bar matches isDerivedFrom(hasName("X")):
+ class Foo;
+ typedef Foo X;
+ class Bar : public Foo {}; derived from a type that X is a typedef of
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
+given matcher.
+
+Example matches y.x() (matcher = callExpr(callee(
+ cxxMethodDecl(hasName("x")))))
+ class Y { public: void x(); };
+ void z() { Y y; y.x(); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee0')"><a name="callee0Anchor">callee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="callee0"><pre>Matches if the call expression's callee expression matches.
+
+Given
+ class Y { void x() { this->x(); x(); Y y; y.x(); } };
+ void f() { f(); }
+callExpr(callee(expr()))
+ matches this->x(), x(), y.x(), f()
+with callee(...)
+ matching this->x, x, y.x, f respectively
+
+Note: Callee cannot take the more general internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>
+because this introduces ambiguous overloads with calls to Callee taking a
+internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, as the matcher hierarchy is purely
+implemented in terms of implicit casts.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('forEachArgumentWithParam0')"><a name="forEachArgumentWithParam0Anchor">forEachArgumentWithParam</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> ArgMatcher, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> ParamMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachArgumentWithParam0"><pre>Matches all arguments and their respective ParmVarDecl.
+
+Given
+ void f(int i);
+ int y;
+ f(y);
+callExpr(declRefExpr(to(varDecl(hasName("y")))),
+parmVarDecl(hasType(isInteger())))
+ matches f(y);
+with declRefExpr(...)
+ matching int y
+and parmVarDecl(...)
+ matching int i
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument0')"><a name="hasAnyArgument0Anchor">hasAnyArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyArgument0"><pre>Matches any argument of a call expression or a constructor call
+expression.
+
+Given
+ void x(int, int, int) { int y; x(1, y, 42); }
+callExpr(hasAnyArgument(declRefExpr()))
+ matches x(1, y, 42)
+with hasAnyArgument(...)
+ matching y
+
+FIXME: Currently this will ignore parentheses and implicit casts on
+the argument before applying the inner matcher. We'll want to remove
+this to allow for greater control by the user once ignoreImplicit()
+has been implemented.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasArgument0')"><a name="hasArgument0Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument0"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('hasDeclaration13')"><a name="hasDeclaration13Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration13"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CaseStmt.html">CaseStmt</a>></td><td class="name" onclick="toggle('hasCaseConstant0')"><a name="hasCaseConstant0Anchor">hasCaseConstant</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCaseConstant0"><pre>If the given case statement does not use the GNU case range
+extension, matches the constant given in the statement.
+
+Given
+ switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+caseStmt(hasCaseConstant(integerLiteral()))
+ matches "case 1:"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>></td><td class="name" onclick="toggle('hasSourceExpression0')"><a name="hasSourceExpression0Anchor">hasSourceExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSourceExpression0"><pre>Matches if the cast's source expression matches the given matcher.
+
+Example: matches "a string" (matcher =
+ hasSourceExpression(cxxConstructExpr()))
+class URL { URL(string); };
+URL url = "a string";
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations that have at least one
+TemplateArgument matching the given InnerMatcher.
+
+Given
+ template<typename T> class A {};
+ template<> class A<double> {};
+ A<int> a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+ matches the specialization A<int>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasTemplateArgument0')"><a name="hasTemplateArgument0Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTemplateArgument0"><pre>Matches classTemplateSpecializations where the n'th TemplateArgument
+matches the given InnerMatcher.
+
+Given
+ template<typename T, typename U> class A {};
+ A<bool, int> b;
+ A<int, bool> c;
+classTemplateSpecializationDecl(hasTemplateArgument(
+ 1, refersToType(asString("int"))))
+ matches the specialization A<bool, int>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>></td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>></td><td class="name" onclick="toggle('hasAnySubstatement0')"><a name="hasAnySubstatement0Anchor">hasAnySubstatement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnySubstatement0"><pre>Matches compound statements where at least one substatement matches
+a given matcher.
+
+Given
+ { {}; 1+2; }
+hasAnySubstatement(compoundStmt())
+ matches '{ {}; 1+2; }'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasCondition4')"><a name="hasCondition4Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCondition4"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasFalseExpression0')"><a name="hasFalseExpression0Anchor">hasFalseExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasFalseExpression0"><pre>Matches the false branch expression of a conditional operator.
+
+Example matches b
+ condition ? a : b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>></td><td class="name" onclick="toggle('hasTrueExpression0')"><a name="hasTrueExpression0Anchor">hasTrueExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTrueExpression0"><pre>Matches the true branch expression of a conditional operator.
+
+Example matches a
+ condition ? a : b
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DecayedType.html">DecayedType</a>></td><td class="name" onclick="toggle('hasDecayedType0')"><a name="hasDecayedType0Anchor">hasDecayedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerType</td></tr>
+<tr><td colspan="4" class="doc" id="hasDecayedType0"><pre>Matches the decayed type, whos decayed type matches InnerMatcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('hasDeclaration11')"><a name="hasDeclaration11Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration11"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('throughUsingDecl0')"><a name="throughUsingDecl0Anchor">throughUsingDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="throughUsingDecl0"><pre>Matches a DeclRefExpr that refers to a declaration through a
+specific using shadow declaration.
+
+Given
+ namespace a { void f() {} }
+ using a::f;
+ void g() {
+ f(); Matches this ..
+ a::f(); .. but not this.
+ }
+declRefExpr(throughUsingDecl(anything()))
+ matches f()
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>></td><td class="name" onclick="toggle('to0')"><a name="to0Anchor">to</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="to0"><pre>Matches a DeclRefExpr that refers to a declaration that matches the
+specified matcher.
+
+Example matches x in if(x)
+ (matcher = declRefExpr(to(varDecl(hasName("x")))))
+ bool x;
+ if (x) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('containsDeclaration0')"><a name="containsDeclaration0Anchor">containsDeclaration</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="containsDeclaration0"><pre>Matches the n'th declaration of a declaration statement.
+
+Note that this does not work for global declarations because the AST
+breaks up multiple-declaration DeclStmt's into multiple single-declaration
+DeclStmt's.
+Example: Given non-global declarations
+ int a, b = 0;
+ int c;
+ int d = 2, e;
+declStmt(containsDeclaration(
+ 0, varDecl(hasInitializer(anything()))))
+ matches only 'int d = 2, e;', and
+declStmt(containsDeclaration(1, varDecl()))
+ matches 'int a, b = 0' as well as 'int d = 2, e;'
+ but 'int c;' is not matched.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>></td><td class="name" onclick="toggle('hasSingleDecl0')"><a name="hasSingleDecl0Anchor">hasSingleDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSingleDecl0"><pre>Matches the Decl of a DeclStmt which has a single declaration.
+
+Given
+ int a, b;
+ int c;
+declStmt(hasSingleDecl(anything()))
+ matches 'int c;' but not 'int a, b;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html">DeclaratorDecl</a>></td><td class="name" onclick="toggle('hasTypeLoc0')"><a name="hasTypeLoc0Anchor">hasTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> Inner</td></tr>
+<tr><td colspan="4" class="doc" id="hasTypeLoc0"><pre>Matches if the type location of the declarator decl's type matches
+the inner matcher.
+
+Given
+ int x;
+declaratorDecl(hasTypeLoc(loc(asString("int"))))
+ matches int x
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasDeclContext0')"><a name="hasDeclContext0Anchor">hasDeclContext</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclContext0"><pre>Matches declarations whose declaration context, interpreted as a
+Decl, matches InnerMatcher.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+
+cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
+declaration of class D.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>></td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody0"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>></td><td class="name" onclick="toggle('hasCondition3')"><a name="hasCondition3Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCondition3"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
+matches InnerMatcher if the qualifier exists.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ N::M::D d;
+
+elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
+matches the type of the variable declaration of d.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('namesType0')"><a name="namesType0Anchor">namesType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="namesType0"><pre>Matches ElaboratedTypes whose named type matches InnerMatcher.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ N::M::D d;
+
+elaboratedType(namesType(recordType(
+hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
+declaration of d.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>></td><td class="name" onclick="toggle('hasDeclaration10')"><a name="hasDeclaration10Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration10"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>></td><td class="name" onclick="toggle('hasDestinationType0')"><a name="hasDestinationType0Anchor">hasDestinationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDestinationType0"><pre>Matches casts whose destination type matches a given matcher.
+
+(Note: Clang's AST refers to other conversions as "casts" too, and calls
+actual casts "explicit" casts.)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType2"><pre>Overloaded to match the declaration of the expression's or value
+declaration's type.
+
+In case of a value declaration (for example a variable declaration),
+this resolves one layer of indirection. For example, in the value
+declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
+X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
+declaration of x.
+
+Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
+ class X {};
+ void y(X &x) { x; X z; }
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType0')"><a name="hasType0Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType0"><pre>Matches if the expression's or declaration's type matches a type
+matcher.
+
+Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
+ class X {};
+ void y(X &x) { x; X z; }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringImpCasts0')"><a name="ignoringImpCasts0Anchor">ignoringImpCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ignoringImpCasts0"><pre>Matches expressions that match InnerMatcher after any implicit casts
+are stripped off.
+
+Parentheses and explicit casts are not discarded.
+Given
+ int arr[5];
+ int a = 0;
+ char b = 0;
+ const int c = a;
+ int *d = arr;
+ long e = (long) 0l;
+The matchers
+ varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
+ varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
+would match the declarations for a, b, c, and d, but not e.
+While
+ varDecl(hasInitializer(integerLiteral()))
+ varDecl(hasInitializer(declRefExpr()))
+only match the declarations for b, c, and d.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringParenCasts0')"><a name="ignoringParenCasts0Anchor">ignoringParenCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ignoringParenCasts0"><pre>Matches expressions that match InnerMatcher after parentheses and
+casts are stripped off.
+
+Implicit and non-C Style casts are also discarded.
+Given
+ int a = 0;
+ char b = (0);
+ void* c = reinterpret_cast<char*>(0);
+ char d = char(0);
+The matcher
+ varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
+would match the declarations for a, b, c, and d.
+while
+ varDecl(hasInitializer(integerLiteral()))
+only match the declaration for a.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringParenImpCasts0')"><a name="ignoringParenImpCasts0Anchor">ignoringParenImpCasts</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ignoringParenImpCasts0"><pre>Matches expressions that match InnerMatcher after implicit casts and
+parentheses are stripped off.
+
+Explicit casts are not discarded.
+Given
+ int arr[5];
+ int a = 0;
+ char b = (0);
+ const int c = a;
+ int *d = (arr);
+ long e = ((long) 0l);
+The matchers
+ varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
+ varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
+would match the declarations for a, b, c, and d, but not e.
+while
+ varDecl(hasInitializer(integerLiteral()))
+ varDecl(hasInitializer(declRefExpr()))
+would only match the declaration for a.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasBody1')"><a name="hasBody1Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody1"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasCondition1')"><a name="hasCondition1Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCondition1"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasIncrement0')"><a name="hasIncrement0Anchor">hasIncrement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasIncrement0"><pre>Matches the increment statement of a for loop.
+
+Example:
+ forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
+matches '++x' in
+ for (x; x < N; ++x) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasLoopInit0')"><a name="hasLoopInit0Anchor">hasLoopInit</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasLoopInit0"><pre>Matches the initialization statement of a for loop.
+
+Example:
+ forStmt(hasLoopInit(declStmt()))
+matches 'int x = 0' in
+ for (int x = 0; x < N; ++x) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasAnyParameter0')"><a name="hasAnyParameter0Anchor">hasAnyParameter</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyParameter0"><pre>Matches any parameter of a function declaration.
+
+Does not match the 'this' parameter of a method.
+
+Given
+ class X { void f(int x, int y, int z) {} };
+cxxMethodDecl(hasAnyParameter(hasName("y")))
+ matches f(int x, int y, int z) {}
+with hasAnyParameter(...)
+ matching int y
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasParameter0')"><a name="hasParameter0Anchor">hasParameter</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasParameter0"><pre>Matches the n'th parameter of a function declaration.
+
+Given
+ class X { void f(int x) {} };
+cxxMethodDecl(hasParameter(0, hasType(varDecl())))
+ matches f(int x) {}
+with hasParameter(...)
+ matching int x
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('returns0')"><a name="returns0Anchor">returns</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="returns0"><pre>Matches the return type of a function declaration.
+
+Given:
+ class X { int f() { return 1; } };
+cxxMethodDecl(returns(asString("int")))
+ matches int f() { return 1; }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasCondition0')"><a name="hasCondition0Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCondition0"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasConditionVariableStatement0')"><a name="hasConditionVariableStatement0Anchor">hasConditionVariableStatement</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasConditionVariableStatement0"><pre>Matches the condition variable statement in an if statement.
+
+Given
+ if (A* a = GetAPointer()) {}
+hasConditionVariableStatement(...)
+ matches 'A* a = GetAPointer()'.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasElse0')"><a name="hasElse0Anchor">hasElse</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasElse0"><pre>Matches the else-statement of an if statement.
+
+Examples matches the if statement
+ (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
+ if (false) false; else true;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>></td><td class="name" onclick="toggle('hasThen0')"><a name="hasThen0Anchor">hasThen</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasThen0"><pre>Matches the then-statement of an if statement.
+
+Examples matches the if statement
+ (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
+ if (false) true; else false;
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>></td><td class="name" onclick="toggle('hasImplicitDestinationType0')"><a name="hasImplicitDestinationType0Anchor">hasImplicitDestinationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasImplicitDestinationType0"><pre>Matches implicit casts whose destination type matches a given
+matcher.
+
+FIXME: Unit test this matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>></td><td class="name" onclick="toggle('hasDeclaration9')"><a name="hasDeclaration9Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration9"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>></td><td class="name" onclick="toggle('hasDeclaration8')"><a name="hasDeclaration8Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration8"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasDeclaration7')"><a name="hasDeclaration7Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration7"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasObjectExpression0')"><a name="hasObjectExpression0Anchor">hasObjectExpression</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasObjectExpression0"><pre>Matches a member expression where the object expression is
+matched by a given matcher.
+
+Given
+ struct X { int m; };
+ void f(X x) { x.m; m; }
+memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
+ matches "x.m" and "m"
+with hasObjectExpression(...)
+ matching "x" and the implicit object expression of "m" which has type X*.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('member0')"><a name="member0Anchor">member</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="member0"><pre>Matches a member expression where the member is matched by a
+given matcher.
+
+Given
+ struct { int first, second; } first, second;
+ int i(second.first);
+ int j(first.second);
+memberExpr(member(hasName("first")))
+ matches second.first
+ but not first.second (because the member name there is "second").
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>></td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('hasPrefix1')"><a name="hasPrefix1Anchor">hasPrefix</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasPrefix1"><pre>Matches on the prefix of a NestedNameSpecifierLoc.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('specifiesTypeLoc0')"><a name="specifiesTypeLoc0Anchor">specifiesTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesTypeLoc0"><pre>Matches nested name specifier locs that specify a type matching the
+given TypeLoc.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
+ hasDeclaration(cxxRecordDecl(hasName("A")))))))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('hasPrefix0')"><a name="hasPrefix0Anchor">hasPrefix</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasPrefix0"><pre>Matches on the prefix of a NestedNameSpecifier.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('specifiesNamespace0')"><a name="specifiesNamespace0Anchor">specifiesNamespace</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesNamespace0"><pre>Matches nested name specifiers that specify a namespace matching the
+given namespace matcher.
+
+Given
+ namespace ns { struct A {}; }
+ ns::A a;
+nestedNameSpecifier(specifiesNamespace(hasName("ns")))
+ matches "ns::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>></td><td class="name" onclick="toggle('specifiesType0')"><a name="specifiesType0Anchor">specifiesType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesType0"><pre>Matches nested name specifiers that specify a type matching the
+given QualType matcher without qualifiers.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifier(specifiesType(
+ hasDeclaration(cxxRecordDecl(hasName("A")))
+))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasArgument2')"><a name="hasArgument2Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument2"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasReceiverType0')"><a name="hasReceiverType0Anchor">hasReceiverType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>Matches on the receiver of an ObjectiveC Message expression.
+
+Example
+matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
+matches the [webView ...] message invocation.
+ NSString *webViewJavaScript = ...
+ UIWebView *webView = ...
+ [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>></td><td class="name" onclick="toggle('innerType0')"><a name="innerType0Anchor">innerType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="innerType0"><pre>Matches ParenType nodes where the inner type is a specific type.
+
+Given
+ int (*ptr_to_array)[4];
+ int (*ptr_to_func)(int);
+
+varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
+ptr_to_func but not ptr_to_array.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>></td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
+
+Given:
+ typedef int &int_ref;
+ int a;
+ int_ref b = a;
+
+varDecl(hasType(qualType(referenceType()))))) will not match the
+declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasDeclaration6')"><a name="hasDeclaration6Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration6"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo1')"><a name="pointsTo1Anchor">pointsTo</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="pointsTo1"><pre>Overloaded to match the pointee type's declaration.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('pointsTo0')"><a name="pointsTo0Anchor">pointsTo</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="pointsTo0"><pre>Matches if the matched type is a pointer type and the pointee type
+matches the specified matcher.
+
+Example matches y->x()
+ (matcher = cxxMemberCallExpr(on(hasType(pointsTo
+ cxxRecordDecl(hasName("Y")))))))
+ class Y { public: void x(); };
+ void z() { Y *y; y->x(); }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('references1')"><a name="references1Anchor">references</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="references1"><pre>Overloaded to match the referenced type's declaration.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('references0')"><a name="references0Anchor">references</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="references0"><pre>Matches if the matched type is a reference type and the referenced
+type matches the specified matcher.
+
+Example matches X &x and const X &y
+ (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
+ class X {
+ void a(X b) {
+ X &x = b;
+ const X &y = b;
+ }
+ };
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>></td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>></td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr>
+<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('alignOfExpr0')"><a name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
+alignof.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="sizeOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
+sizeof.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>></td><td class="name" onclick="toggle('forEachSwitchCase0')"><a name="forEachSwitchCase0Anchor">forEachSwitchCase</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachSwitchCase0"><pre>Matches each case or default statement belonging to the given switch
+statement. This matcher may produce multiple matches.
+
+Given
+ switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
+ matches four times, with "c" binding each of "case 1:", "case 2:",
+"case 3:" and "case 4:", and "s" respectively binding "switch (1)",
+"switch (1)", "switch (2)" and "switch (2)".
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>></td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration4"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('isExpr0')"><a name="isExpr0Anchor">isExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="isExpr0"><pre>Matches a sugar TemplateArgument that refers to a certain expression.
+
+Given
+ template<typename T> struct A {};
+ struct B { B* next; };
+ A<&B::next> a;
+templateSpecializationType(hasAnyTemplateArgument(
+ isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
+ matches the specialization A<&B::next> with fieldDecl(...) matching
+ B::next
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToDeclaration0')"><a name="refersToDeclaration0Anchor">refersToDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="refersToDeclaration0"><pre>Matches a canonical TemplateArgument that refers to a certain
+declaration.
+
+Given
+ template<typename T> struct A {};
+ struct B { B* next; };
+ A<&B::next> a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(fieldDecl(hasName("next"))))
+ matches the specialization A<&B::next> with fieldDecl(...) matching
+ B::next
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToIntegralType0')"><a name="refersToIntegralType0Anchor">refersToIntegralType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="refersToIntegralType0"><pre>Matches a TemplateArgument that referes to an integral type.
+
+Given
+ template<int T> struct A {};
+ C<42> c;
+classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
+ matches the implicit instantiation of C in C<42>.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('refersToType0')"><a name="refersToType0Anchor">refersToType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="refersToType0"><pre>Matches a TemplateArgument that refers to a certain type.
+
+Given
+ struct X {};
+ template<typename T> struct A {};
+ A<X> a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToType(class(hasName("X")))))
+ matches the specialization A<X>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument1')"><a name="hasAnyTemplateArgument1Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>Matches classTemplateSpecializations that have at least one
+TemplateArgument matching the given InnerMatcher.
+
+Given
+ template<typename T> class A {};
+ template<> class A<double> {};
+ A<int> a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+ matches the specialization A<int>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasTemplateArgument1')"><a name="hasTemplateArgument1Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTemplateArgument1"><pre>Matches classTemplateSpecializations where the n'th TemplateArgument
+matches the given InnerMatcher.
+
+Given
+ template<typename T, typename U> class A {};
+ A<bool, int> b;
+ A<int, bool> c;
+classTemplateSpecializationDecl(hasTemplateArgument(
+ 1, refersToType(asString("int"))))
+ matches the specialization A<bool, int>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>></td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<T></td><td class="name" onclick="toggle('findAll0')"><a name="findAll0Anchor">findAll</a></td><td>Matcher<T> Matcher</td></tr>
+<tr><td colspan="4" class="doc" id="findAll0"><pre>Matches if the node or any descendant matches.
+
+Generates results for each match.
+
+For example, in:
+ class A { class B {}; class C {}; };
+The matcher:
+ cxxRecordDecl(hasName("::A"),
+ findAll(cxxRecordDecl(isDefinition()).bind("m")))
+will generate results for A, B and C.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>></td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>></td><td class="name" onclick="toggle('hasArgumentOfType0')"><a name="hasArgumentOfType0Anchor">hasArgumentOfType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgumentOfType0"><pre>Matches unary expressions that have a specific type of argument.
+
+Given
+ int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
+unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
+ matches sizeof(a) and alignof(c)
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasUnaryOperand0')"><a name="hasUnaryOperand0Anchor">hasUnaryOperand</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasUnaryOperand0"><pre>Matches if the operand of a unary operator matches.
+
+Example matches true (matcher = hasUnaryOperand(
+ cxxBoolLiteral(equals(true))))
+ !true
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>></td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a node if the declaration associated with that node
+matches the given matcher.
+
+The associated declaration is:
+- for type nodes, the declaration of the underlying type
+- for CallExpr, the declaration of the callee
+- for MemberExpr, the declaration of the referenced member
+- for CXXConstructExpr, the declaration of the constructor
+
+Also usable as Matcher<T> for any T supporting the getDecl() member
+function. e.g. various subtypes of clang::Type and various expressions.
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumType.html">EnumType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1InjectedClassNameType.html">InjectedClassNameType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateTypeParmType.html">TemplateTypeParmType</a>>,
+ Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnresolvedUsingType.html">UnresolvedUsingType</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingDecl.html">UsingDecl</a>></td><td class="name" onclick="toggle('hasAnyUsingShadowDecl0')"><a name="hasAnyUsingShadowDecl0Anchor">hasAnyUsingShadowDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyUsingShadowDecl0"><pre>Matches any using shadow declaration.
+
+Given
+ namespace X { void b(); }
+ using X::b;
+usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
+ matches using X::b </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>></td><td class="name" onclick="toggle('hasTargetDecl0')"><a name="hasTargetDecl0Anchor">hasTargetDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTargetDecl0"><pre>Matches a using shadow declaration where the target declaration is
+matched by the given matcher.
+
+Given
+ namespace X { int a; void b(); }
+ using X::a;
+ using X::b;
+usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
+ matches using X::b but not using X::a </pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value
+declaration's type.
+
+In case of a value declaration (for example a variable declaration),
+this resolves one layer of indirection. For example, in the value
+declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
+X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
+declaration of x.
+
+Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
+ class X {};
+ void y(X &x) { x; X z; }
+
+Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType1')"><a name="hasType1Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasType1"><pre>Matches if the expression's or declaration's type matches a type
+matcher.
+
+Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
+ class X {};
+ void y(X &x) { x; X z; }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('hasInitializer0')"><a name="hasInitializer0Anchor">hasInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasInitializer0"><pre>Matches a variable declaration that has an initializer expression
+that matches the given matcher.
+
+Example matches x (matcher = varDecl(hasInitializer(callExpr())))
+ bool y() { return true; }
+ bool x = y();
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>></td><td class="name" onclick="toggle('hasSizeExpr0')"><a name="hasSizeExpr0Anchor">hasSizeExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSizeExpr0"><pre>Matches VariableArrayType nodes that have a specific size
+expression.
+
+Given
+ void f(int b) {
+ int a[b];
+ }
+variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+ varDecl(hasName("b")))))))
+ matches "int a[b]"
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>></td><td class="name" onclick="toggle('hasBody2')"><a name="hasBody2Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody2"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>></td><td class="name" onclick="toggle('hasCondition2')"><a name="hasCondition2Anchor">hasCondition</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCondition2"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>></td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
+QualType-matcher matches.
+</pre></td></tr>
+
+<!--END_TRAVERSAL_MATCHERS -->
+</table>
+
+</div>
+</body>
+</html>
+
+
diff --git a/docs/LibASTMatchersTutorial.rst b/docs/LibASTMatchersTutorial.rst
index fe36511..603b2fa 100644
--- a/docs/LibASTMatchersTutorial.rst
+++ b/docs/LibASTMatchersTutorial.rst
@@ -108,7 +108,6 @@
::
set(LLVM_LINK_COMPONENTS support)
- set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
add_clang_executable(loop-convert
LoopConvert.cpp
diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst
index f97355f..62cacce 100644
--- a/docs/MemorySanitizer.rst
+++ b/docs/MemorySanitizer.rst
@@ -48,10 +48,7 @@
% clang -fsanitize=memory -fno-omit-frame-pointer -g -O2 umr.cc
If a bug is detected, the program will print an error message to
-stderr and exit with a non-zero exit code. Currently, MemorySanitizer
-does not symbolize its output by default, so you may need to use a
-separate script to symbolize the result offline (this will be fixed in
-future).
+stderr and exit with a non-zero exit code.
.. code-block:: console
@@ -60,7 +57,9 @@
#0 0x7f45944b418a in main umr.cc:6
#1 0x7f45938b676c in __libc_start_main libc-start.c:226
-By default, MemorySanitizer exits on the first detected error.
+By default, MemorySanitizer exits on the first detected error. If you
+find the error report hard to understand, try enabling
+:ref:`origin tracking <msan-origins>`.
``__has_feature(memory_sanitizer)``
------------------------------------
@@ -102,10 +101,12 @@
reports. Make sure that ``llvm-symbolizer`` binary is in ``PATH``,
or set environment variable ``MSAN_SYMBOLIZER_PATH`` to point to it.
+.. _msan-origins:
+
Origin Tracking
===============
-MemorySanitizer can track origins of unitialized values, similar to
+MemorySanitizer can track origins of uninitialized values, similar to
Valgrind's --track-origins option. This feature is enabled by
``-fsanitize-memory-track-origins=2`` (or simply
``-fsanitize-memory-track-origins``) Clang option. With the code from
@@ -143,14 +144,29 @@
intermediate stores the uninitialized value went through. Origin
tracking has proved to be very useful for debugging MemorySanitizer
reports. It slows down program execution by a factor of 1.5x-2x on top
-of the usual MemorySanitizer slowdown.
+of the usual MemorySanitizer slowdown and increases memory overhead.
-Clang option ``-fsanitize-memory-track-origins=1`` enabled a slightly
+Clang option ``-fsanitize-memory-track-origins=1`` enables a slightly
faster mode when MemorySanitizer collects only allocation points but
not intermediate stores.
+Use-after-destruction detection
+===============================
+
+You can enable experimental use-after-destruction detection in MemorySanitizer.
+After invocation of the destructor, the object will be considered no longer
+readable, and using underlying memory will lead to error reports in runtime.
+
+This feature is still experimental, in order to enable it at runtime you need
+to:
+
+#. Pass addition Clang option ``-fsanitize-memory-use-after-dtor`` during
+ compilation.
+#. Set environment variable `MSAN_OPTIONS=poison_in_dtor=1` before running
+ the program.
+
Handling external code
-============================
+======================
MemorySanitizer requires that all program code is instrumented. This
also includes any libraries that the program depends on, even libc.
@@ -167,9 +183,7 @@
Supported Platforms
===================
-MemorySanitizer is supported on
-
-* Linux x86\_64 (tested on Ubuntu 12.04);
+MemorySanitizer is supported on Linux x86\_64/MIPS64/AArch64.
Limitations
===========
@@ -180,22 +194,19 @@
address space. This means that tools like ``ulimit`` may not work as
usually expected.
* Static linking is not supported.
-* Non-position-independent executables are not supported. Therefore, the
- ``fsanitize=memory`` flag will cause Clang to act as though the ``-fPIE``
- flag had been supplied if compiling without ``-fPIC``, and as though the
- ``-pie`` flag had been supplied if linking an executable.
-* Depending on the version of Linux kernel, running without ASLR may
- be not supported. Note that GDB disables ASLR by default. To debug
- instrumented programs, use "set disable-randomization off".
+* Older versions of MSan (LLVM 3.7 and older) didn't work with
+ non-position-independent executables, and could fail on some Linux
+ kernel versions with disabled ASLR. Refer to documentation for older versions
+ for more details.
Current Status
==============
-MemorySanitizer is an experimental tool. It is known to work on large
-real-world programs, like Clang/LLVM itself.
+MemorySanitizer is known to work on large real-world programs
+(like Clang/LLVM itself) that can be recompiled from source, including all
+dependent libraries.
More Information
================
-`http://code.google.com/p/memory-sanitizer <http://code.google.com/p/memory-sanitizer/>`_
-
+`<https://github.com/google/sanitizers/wiki/MemorySanitizer>`_
diff --git a/docs/RAVFrontendAction.rst b/docs/RAVFrontendAction.rst
index ec5d5d5..c37d3c0 100644
--- a/docs/RAVFrontendAction.rst
+++ b/docs/RAVFrontendAction.rst
@@ -205,10 +205,10 @@
::
- set(LLVM_USED_LIBS clangTooling)
-
add_clang_executable(find-class-decls FindClassDecls.cpp)
+ target_link_libraries(find-class-decls clangTooling)
+
When running this tool over a small code snippet it will output all
declarations of a class n::m::C it found:
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 779d45c..ea3dcf2 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,5 +1,5 @@
=====================================
-Clang 3.8 (In-Progress) Release Notes
+Clang 3.9 (In-Progress) Release Notes
=====================================
.. contents::
@@ -10,7 +10,7 @@
.. warning::
- These are in-progress notes for the upcoming Clang 3.8 release. You may
+ These are in-progress notes for the upcoming Clang 3.9 release. You may
prefer the `Clang 3.7 Release Notes
<http://llvm.org/releases/3.7.0/tools/clang/docs/ReleaseNotes.html>`_.
@@ -18,7 +18,7 @@
============
This document contains the release notes for the Clang C/C++/Objective-C
-frontend, part of the LLVM Compiler Infrastructure, release 3.8. Here we
+frontend, part of the LLVM Compiler Infrastructure, release 3.9. Here we
describe the status of Clang in some detail, including major
improvements from the previous release and new feature work. For the
general LLVM release notes, see `the LLVM
@@ -36,7 +36,7 @@
the current one. To see the release notes for a specific release, please
see the `releases page <http://llvm.org/releases/>`_.
-What's New in Clang 3.8?
+What's New in Clang 3.9?
========================
Some of the major new features and improvements to Clang are listed
@@ -74,6 +74,8 @@
Clang's support for building native Windows programs ...
+TLS is enabled for Cygwin defaults to -femulated-tls.
+
C Language Changes in Clang
---------------------------
@@ -108,7 +110,7 @@
Internal API Changes
--------------------
-These are major API changes that have happened since the 3.7 release of
+These are major API changes that have happened since the 3.8 release of
Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading.
@@ -116,46 +118,6 @@
AST Matchers
------------
-The AST matcher functions were renamed to reflect the exact AST node names,
-which is a breaking change to AST matching code. The following matchers were
-affected:
-
-======================= ============================
-Previous Matcher Name New Matcher Name
-======================= ============================
-recordDecl recordDecl and cxxRecordDecl
-ctorInitializer cxxCtorInitializer
-constructorDecl cxxConstructorDecl
-destructorDecl cxxDestructorDecl
-methodDecl cxxMethodDecl
-conversionDecl cxxConversionDecl
-memberCallExpr cxxMemberCallExpr
-constructExpr cxxConstructExpr
-unresolvedConstructExpr cxxUnresolvedConstructExpr
-thisExpr cxxThisExpr
-bindTemporaryExpr cxxBindTemporaryExpr
-newExpr cxxNewExpr
-deleteExpr cxxDeleteExpr
-defaultArgExpr cxxDefaultArgExpr
-operatorCallExpr cxxOperatorCallExpr
-forRangeStmt cxxForRangeStmt
-catchStmt cxxCatchStmt
-tryStmt cxxTryStmt
-throwExpr cxxThrowExpr
-boolLiteral cxxBoolLiteral
-nullPtrLiteralExpr cxxNullPtrLiteralExpr
-reinterpretCastExpr cxxReinterpretCastExpr
-staticCastExpr cxxStaticCastExpr
-dynamicCastExpr cxxDynamicCastExpr
-constCastExpr cxxConstCastExpr
-functionalCastExpr cxxFunctionalCastExpr
-temporaryObjectExpr cxxTemporaryObjectExpr
-CUDAKernalCallExpr cudaKernelCallExpr
-======================= ============================
-
-recordDecl() previously matched AST nodes of type CXXRecordDecl, but now
-matches AST nodes of type RecordDecl. If a CXXRecordDecl is required, use the
-cxxRecordDecl() matcher instead.
...
diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst
index efcb49e..e759b35 100644
--- a/docs/SanitizerCoverage.rst
+++ b/docs/SanitizerCoverage.rst
@@ -249,6 +249,13 @@
uintptr_t
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+Tracing basic blocks
+====================
+An *experimental* feature to support 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]``).
+
Tracing data flow
=================
@@ -275,6 +282,7 @@
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases);
This interface is a subject to change.
+The current implementation is not thread-safe and thus can be safely used only for single-threaded targets.
Output directory
================
diff --git a/docs/SanitizerStats.rst b/docs/SanitizerStats.rst
new file mode 100644
index 0000000..cff68f6
--- /dev/null
+++ b/docs/SanitizerStats.rst
@@ -0,0 +1,62 @@
+==============
+SanitizerStats
+==============
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+The sanitizers support a simple mechanism for gathering profiling statistics
+to help understand the overhead associated with sanitizers.
+
+How to build and run
+====================
+
+SanitizerStats can currently only be used with :doc:`ControlFlowIntegrity`.
+In addition to ``-fsanitize=cfi*``, pass the ``-fsanitize-stats`` flag.
+This will cause the program to count the number of times that each control
+flow integrity check in the program fires.
+
+At run time, set the ``SANITIZER_STATS_PATH`` environment variable to direct
+statistics output to a file. The file will be written on process exit.
+The following substitutions will be applied to the environment variable:
+
+ - ``%b`` -- The executable basename.
+ - ``%p`` -- The process ID.
+
+You can also send the ``SIGUSR2`` signal to a process to make it write
+sanitizer statistics immediately.
+
+The ``sanstats`` program can be used to dump statistics. It takes as a
+command line argument the path to a statistics file produced by a program
+compiled with ``-fsanitize-stats``.
+
+The output of ``sanstats`` is in four columns, separated by spaces. The first
+column is the file and line number of the call site. The second column is
+the function name. The third column is the type of statistic gathered (in
+this case, the type of control flow integrity check). The fourth column is
+the call count.
+
+Example:
+
+.. code-block:: console
+
+ $ cat -n vcall.cc
+ 1 struct A {
+ 2 virtual void f() {}
+ 3 };
+ 4
+ 5 __attribute__((noinline)) void g(A *a) {
+ 6 a->f();
+ 7 }
+ 8
+ 9 int main() {
+ 10 A a;
+ 11 g(&a);
+ 12 }
+ $ clang++ -fsanitize=cfi -flto -fuse-ld=gold vcall.cc -fsanitize-stats -g
+ $ SANITIZER_STATS_PATH=a.stats ./a.out
+ $ sanstats a.stats
+ vcall.cc:6 _Z1gP1A cfi-vcall 1
diff --git a/docs/ThreadSanitizer.rst b/docs/ThreadSanitizer.rst
index 9a8b140..0b9b163 100644
--- a/docs/ThreadSanitizer.rst
+++ b/docs/ThreadSanitizer.rst
@@ -131,5 +131,4 @@
More Information
----------------
-`http://code.google.com/p/thread-sanitizer <http://code.google.com/p/thread-sanitizer/>`_.
-
+`<https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual>`_
diff --git a/docs/UndefinedBehaviorSanitizer.rst b/docs/UndefinedBehaviorSanitizer.rst
new file mode 100644
index 0000000..37ff16d
--- /dev/null
+++ b/docs/UndefinedBehaviorSanitizer.rst
@@ -0,0 +1,204 @@
+==========================
+UndefinedBehaviorSanitizer
+==========================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+UndefinedBehaviorSanitizer (UBSan) is a fast undefined behavior detector.
+UBSan modifies the program at compile-time to catch various kinds of undefined
+behavior during program execution, for example:
+
+* Using misaligned or null pointer
+* Signed integer overflow
+* Conversion to, from, or between floating-point types which would
+ overflow the destination
+
+See the full list of available :ref:`checks <ubsan-checks>` below.
+
+UBSan has an optional run-time library which provides better error reporting.
+The checks have small runtime cost and no impact on address space layout or ABI.
+
+How to build
+============
+
+Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
+
+Usage
+=====
+
+Use ``clang++`` to compile and link your program with ``-fsanitize=undefined``
+flag. Make sure to use ``clang++`` (not ``ld``) as a linker, so that your
+executable is linked with proper UBSan runtime libraries. You can use ``clang``
+instead of ``clang++`` if you're compiling/linking C code.
+
+.. code-block:: console
+
+ % cat test.cc
+ int main(int argc, char **argv) {
+ int k = 0x7fffffff;
+ k += argc;
+ return 0;
+ }
+ % clang++ -fsanitize=undefined test.cc
+ % ./a.out
+ test.cc:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
+
+You can enable only a subset of :ref:`checks <ubsan-checks>` offered by UBSan,
+and define the desired behavior for each kind of check:
+
+* print a verbose error report and continue execution (default);
+* print a verbose error report and exit the program;
+* execute a trap instruction (doesn't require UBSan run-time support).
+
+For example if you compile/link your program as:
+
+.. code-block:: console
+
+ % clang++ -fsanitize=signed-integer-overflow,null,alignment -fno-sanitize-recover=null -fsanitize-trap=alignment
+
+the program will continue execution after signed integer overflows, exit after
+the first invalid use of a null pointer, and trap after the first use of misaligned
+pointer.
+
+.. _ubsan-checks:
+
+Availablle checks
+=================
+
+Available checks are:
+
+ - ``-fsanitize=alignment``: Use of a misaligned pointer or creation
+ of a misaligned reference.
+ - ``-fsanitize=bool``: Load of a ``bool`` value which is neither
+ ``true`` nor ``false``.
+ - ``-fsanitize=bounds``: Out of bounds array indexing, in cases
+ where the array bound can be statically determined.
+ - ``-fsanitize=enum``: Load of a value of an enumerated type which
+ is not in the range of representable values for that enumerated
+ type.
+ - ``-fsanitize=float-cast-overflow``: Conversion to, from, or
+ between floating-point types which would overflow the
+ destination.
+ - ``-fsanitize=float-divide-by-zero``: Floating point division by
+ zero.
+ - ``-fsanitize=function``: Indirect call of a function through a
+ function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
+ - ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
+ - ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
+ parameter which is declared to never be null.
+ - ``-fsanitize=null``: Use of a null pointer or creation of a null
+ reference.
+ - ``-fsanitize=object-size``: An attempt to use bytes which the
+ optimizer can determine are not part of the object being
+ accessed. The sizes of objects are determined using
+ ``__builtin_object_size``, and consequently may be able to detect
+ more problems at higher optimization levels.
+ - ``-fsanitize=return``: In C++, reaching the end of a
+ value-returning function without returning a value.
+ - ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
+ from a function which is declared to never return null.
+ - ``-fsanitize=shift``: Shift operators where the amount shifted is
+ greater or equal to the promoted bit-width of the left hand side
+ or less than zero, or where the left hand side is negative. For a
+ signed left shift, also checks for signed overflow in C, and for
+ unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
+ ``-fsanitize=shift-exponent`` to check only left-hand side or
+ right-hand side of shift operation, respectively.
+ - ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
+ including all the checks added by ``-ftrapv``, and checking for
+ overflow in signed division (``INT_MIN / -1``).
+ - ``-fsanitize=unreachable``: If control flow reaches
+ ``__builtin_unreachable``.
+ - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
+ overflows.
+ - ``-fsanitize=vla-bound``: A variable-length array whose bound
+ does not evaluate to a positive value.
+ - ``-fsanitize=vptr``: Use of an object whose vptr indicates that
+ it is of the wrong dynamic type, or that its lifetime has not
+ begun or has ended. Incompatible with ``-fno-rtti``. Link must
+ be performed by ``clang++``, not ``clang``, to make sure C++-specific
+ parts of the runtime library and C++ standard libraries are present.
+
+You can also use the following check groups:
+ - ``-fsanitize=undefined``: All of the checks listed above other than
+ ``unsigned-integer-overflow``.
+ - ``-fsanitize=undefined-trap``: Deprecated alias of
+ ``-fsanitize=undefined``.
+ - ``-fsanitize=integer``: Checks for undefined or suspicious integer
+ behavior (e.g. unsigned integer overflow).
+
+Stack traces and report symbolization
+=====================================
+If you want UBSan to print symbolized stack trace for each error report, you
+will need to:
+
+#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug
+ information in your binary.
+#. Run your program with environment variable
+ ``UBSAN_OPTIONS=print_stacktrace=1``.
+#. Make sure ``llvm-symbolizer`` binary is in ``PATH``.
+
+Issue Suppression
+=================
+
+UndefinedBehaviorSanitizer is not expected to produce false positives.
+If you see one, look again; most likely it is a true positive!
+
+Disabling Instrumentation with ``__attribute__((no_sanitize("undefined")))``
+----------------------------------------------------------------------------
+
+You disable UBSan checks for particular functions with
+``__attribute__((no_sanitize("undefined")))``. You can use all values of
+``-fsanitize=`` flag in this attribute, e.g. if your function deliberately
+contains possible signed integer overflow, you can use
+``__attribute__((no_sanitize("signed-integer-overflow")))``.
+
+This attribute may not be
+supported by other compilers, so consider using it together with
+``#if defined(__clang__)``.
+
+Suppressing Errors in Recompiled Code (Blacklist)
+-------------------------------------------------
+
+UndefinedBehaviorSanitizer supports ``src`` and ``fun`` entity types in
+:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
+in the specified source files or functions.
+
+Supported Platforms
+===================
+
+UndefinedBehaviorSanitizer is supported on the following OS:
+
+* Android
+* Linux
+* FreeBSD
+* OS X 10.6 onwards
+
+and for the following architectures:
+
+* i386/x86\_64
+* ARM
+* AArch64
+* PowerPC64
+* MIPS/MIPS64
+
+Current Status
+==============
+
+UndefinedBehaviorSanitizer is available on selected platforms starting from LLVM
+3.3. The test suite is integrated into the CMake build and can be run with
+``check-ubsan`` command.
+
+More Information
+================
+
+* From LLVM project blog:
+ `What Every C Programmer Should Know About Undefined Behavior
+ <http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html>`_
+* From John Regehr's *Embedded in Academia* blog:
+ `A Guide to Undefined Behavior in C and C++
+ <http://blog.regehr.org/archives/213>`_
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index fdba358..ea75d1e 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -952,26 +952,18 @@
``-fsanitize=address``:
:doc:`AddressSanitizer`, a memory error
detector.
- - ``-fsanitize=integer``: Enables checks for undefined or
- suspicious integer behavior.
- .. _opt_fsanitize_thread:
``-fsanitize=thread``: :doc:`ThreadSanitizer`, a data race detector.
- .. _opt_fsanitize_memory:
``-fsanitize=memory``: :doc:`MemorySanitizer`,
- an *experimental* detector of uninitialized reads. Not ready for
- widespread use.
+ a detector of uninitialized reads. Requires instrumentation of all
+ program code.
- .. _opt_fsanitize_undefined:
- ``-fsanitize=undefined``: Fast and compatible undefined behavior
- checker. Enables the undefined behavior checks that have small
- runtime cost and no impact on address space layout or ABI. This
- includes all of the checks listed below other than
- ``unsigned-integer-overflow``.
-
- - ``-fsanitize=undefined-trap``: This is a deprecated alias for
- ``-fsanitize=undefined``.
+ ``-fsanitize=undefined``: :doc:`UndefinedBehaviorSanitizer`,
+ a fast and compatible undefined behavior checker.
- ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
flow analysis.
@@ -980,113 +972,17 @@
- ``-fsanitize=safe-stack``: :doc:`safe stack <SafeStack>`
protection against stack-based memory corruption errors.
- The following more fine-grained checks are also available:
-
- - ``-fsanitize=alignment``: Use of a misaligned pointer or creation
- of a misaligned reference.
- - ``-fsanitize=bool``: Load of a ``bool`` value which is neither
- ``true`` nor ``false``.
- - ``-fsanitize=bounds``: Out of bounds array indexing, in cases
- where the array bound can be statically determined.
- - ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
- <cfi-strictness>`.
- - ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
- dynamic type. Requires ``-flto``.
- - ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
- unrelated type to the wrong dynamic type. Requires ``-flto``.
- - ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
- the wrong dynamic type. Requires ``-flto``.
- - ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
- wrong dynamic type. Requires ``-flto``.
- - ``-fsanitize=enum``: Load of a value of an enumerated type which
- is not in the range of representable values for that enumerated
- type.
- - ``-fsanitize=float-cast-overflow``: Conversion to, from, or
- between floating-point types which would overflow the
- destination.
- - ``-fsanitize=float-divide-by-zero``: Floating point division by
- zero.
- - ``-fsanitize=function``: Indirect call of a function through a
- function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
- - ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
- - ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
- parameter which is declared to never be null.
- - ``-fsanitize=null``: Use of a null pointer or creation of a null
- reference.
- - ``-fsanitize=object-size``: An attempt to use bytes which the
- optimizer can determine are not part of the object being
- accessed. The sizes of objects are determined using
- ``__builtin_object_size``, and consequently may be able to detect
- more problems at higher optimization levels.
- - ``-fsanitize=return``: In C++, reaching the end of a
- value-returning function without returning a value.
- - ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
- from a function which is declared to never return null.
- - ``-fsanitize=shift``: Shift operators where the amount shifted is
- greater or equal to the promoted bit-width of the left hand side
- or less than zero, or where the left hand side is negative. For a
- signed left shift, also checks for signed overflow in C, and for
- unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
- ``-fsanitize=shift-exponent`` to check only left-hand side or
- right-hand side of shift operation, respectively.
- - ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
- including all the checks added by ``-ftrapv``, and checking for
- overflow in signed division (``INT_MIN / -1``).
- - ``-fsanitize=unreachable``: If control flow reaches
- ``__builtin_unreachable``.
- - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
- overflows.
- - ``-fsanitize=vla-bound``: A variable-length array whose bound
- does not evaluate to a positive value.
- - ``-fsanitize=vptr``: Use of an object whose vptr indicates that
- it is of the wrong dynamic type, or that its lifetime has not
- begun or has ended. Incompatible with ``-fno-rtti``.
-
- You can turn off or modify checks for certain source files, functions
- or even variables by providing a special file:
-
- - ``-fsanitize-blacklist=/path/to/blacklist/file``: disable or modify
- sanitizer checks for objects listed in the file. See
- :doc:`SanitizerSpecialCaseList` for file format description.
- - ``-fno-sanitize-blacklist``: don't use blacklist file, if it was
- specified earlier in the command line.
-
- Extra features of MemorySanitizer (require explicit
- ``-fsanitize=memory``):
-
- - ``-fsanitize-memory-track-origins[=level]``: Enables origin tracking in
- MemorySanitizer. Adds a second section to MemorySanitizer
- reports pointing to the heap or stack allocation the
- uninitialized bits came from. Slows down execution by additional
- 1.5x-2x.
-
- Possible values for level are 0 (off), 1, 2 (default). Level 2
- adds more sections to MemorySanitizer reports describing the
- order of memory stores the uninitialized value went
- through. This mode may use extra memory in programs that copy
- uninitialized memory a lot.
- - ``-fsanitize-memory-use-after-dtor``: Enables use-after-destruction
- detection in MemorySanitizer. After invocation of the destructor,
- the object is considered no longer readable. Facilitates the
- detection of use-after-destroy bugs.
-
- Setting the MSAN_OPTIONS=poison_in_dtor=1 enables the poisoning of
- memory at runtime. Any subsequent access to the destroyed object
- fails at runtime. This feature is still experimental, but this
- environment variable must be set to 1 in order for the above flag
- to have any effect.
+ There are more fine-grained checks available: see
+ the :ref:`list <ubsan-checks>` of specific kinds of
+ undefined behavior that can be detected and the :ref:`list <cfi-schemes>`
+ of control flow integrity schemes.
The ``-fsanitize=`` argument must also be provided when linking, in
- order to link to the appropriate runtime library. When using
- ``-fsanitize=vptr`` (or a group that includes it, such as
- ``-fsanitize=undefined``) with a C++ program, the link must be
- performed by ``clang++``, not ``clang``, in order to link against the
- C++-specific parts of the runtime library.
+ order to link to the appropriate runtime library.
It is not possible to combine more than one of the ``-fsanitize=address``,
``-fsanitize=thread``, and ``-fsanitize=memory`` checkers in the same
- program. The ``-fsanitize=undefined`` checks can only be combined with
- ``-fsanitize=address``.
+ program.
**-f[no-]sanitize-recover=check1,check2,...**
@@ -1094,10 +990,12 @@
If the check is fatal, program will halt after the first error
of this kind is detected and error report is printed.
- By default, non-fatal checks are those enabled by UndefinedBehaviorSanitizer,
+ By default, non-fatal checks are those enabled by
+ :doc:`UndefinedBehaviorSanitizer`,
except for ``-fsanitize=return`` and ``-fsanitize=unreachable``. Some
- sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery,
- and always crash the program after the issue is detected.
+ sanitizers may not support recovery (or not support it by default
+ e.g. :doc:`AddressSanitizer`), and always crash the program after the issue
+ is detected.
Note that the ``-fsanitize-trap`` flag has precedence over this flag.
This means that if a check has been configured to trap elsewhere on the
@@ -1117,23 +1015,44 @@
be used (for instance, when building libc or a kernel module), or where
the binary size increase caused by the sanitizer runtime is a concern.
- This flag is only compatible with ``local-bounds``,
- ``unsigned-integer-overflow``, sanitizers in the ``cfi`` group and
- sanitizers in the ``undefined`` group other than ``vptr``. If this flag
+ This flag is only compatible with :doc:`control flow integrity
+ <ControlFlowIntegrity>` schemes and :doc:`UndefinedBehaviorSanitizer`
+ checks other than ``vptr``. If this flag
is supplied together with ``-fsanitize=undefined``, the ``vptr`` sanitizer
will be implicitly disabled.
This flag is enabled by default for sanitizers in the ``cfi`` group.
+.. option:: -fsanitize-blacklist=/path/to/blacklist/file
+
+ Disable or modify sanitizer checks for objects (source files, functions,
+ variables, types) listed in the file. See
+ :doc:`SanitizerSpecialCaseList` for file format description.
+
+.. option:: -fno-sanitize-blacklist
+
+ Don't use blacklist file, if it was specified earlier in the command line.
+
**-f[no-]sanitize-coverage=[type,features,...]**
Enable simple code coverage in addition to certain sanitizers.
See :doc:`SanitizerCoverage` for more details.
+**-f[no-]sanitize-stats**
+
+ Enable simple statistics gathering for the enabled sanitizers.
+ See :doc:`SanitizerStats` for more details.
+
.. option:: -fsanitize-undefined-trap-on-error
Deprecated alias for ``-fsanitize-trap=undefined``.
+.. option:: -fsanitize-cfi-cross-dso
+
+ Enable cross-DSO control flow integrity checks. This flag modifies
+ the behavior of sanitizers in the ``cfi`` group to allow checking
+ of cross-DSO virtual and indirect calls.
+
.. option:: -fno-assume-sane-operator-new
Don't assume that the C++'s new operator is sane.
@@ -1200,7 +1119,7 @@
This option restricts the generated code to use general registers
only. This only applies to the AArch64 architecture.
-**-f[no-]max-unknown-pointer-align=[number]**
+**-f[no-]max-type-align=[number]**
Instruct the code generator to not enforce a higher alignment than the given
number (of bytes) when accessing memory via an opaque pointer or reference.
This cap is ignored when directly accessing a variable or when the pointee
@@ -1228,7 +1147,7 @@
void initialize_vector(__aligned_v16si *v) {
// The compiler may assume that ‘v’ is 64-byte aligned, regardless of the
- // value of -fmax-unknown-pointer-align.
+ // value of -fmax-type-align.
}
@@ -1600,8 +1519,11 @@
Note that these flags should appear after the corresponding profile
flags to have an effect.
+Controlling Debug Information
+-----------------------------
+
Controlling Size of Debug Information
--------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Debug info kind generated by Clang can be set by one of the flags listed
below. If multiple flags are present, the last one is used.
@@ -1645,6 +1567,21 @@
Generate complete debug info.
+Controlling Debugger "Tuning"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+While Clang generally emits standard DWARF debug info (http://dwarfstd.org),
+different debuggers may know how to take advantage of different specific DWARF
+features. You can "tune" the debug info for one of several different debuggers.
+
+.. option:: -ggdb, -glldb, -gsce
+
+ Tune the debug info for the ``gdb``, ``lldb``, or Sony Computer Entertainment
+ debugger, respectively. Each of these options implies **-g**. (Therefore, if
+ you want both **-gline-tables-only** and debugger tuning, the tuning option
+ must come first.)
+
+
Comment Parsing Options
-----------------------
@@ -1917,8 +1854,8 @@
array sections), ``#pragma omp cancel`` and ``#pragma omp cancellation point``
directives, and ``#pragma omp taskgroup`` directive.
-OpenMP support is disabled by default. Use :option:`-fopenmp=libomp` to enable
-it. Support for OpenMP can be disabled with :option:`-fno-openmp`.
+Use :option:`-fopenmp` to enable OpenMP. Support for OpenMP can be disabled with
+:option:`-fno-openmp`.
Controlling implementation limits
---------------------------------
@@ -2172,7 +2109,7 @@
/W1 Enable -Wall
/W2 Enable -Wall
/W3 Enable -Wall
- /W4 Enable -Wall
+ /W4 Enable -Wall and -Wextra
/Wall Enable -Wall
/WX- Do not treat warnings as errors
/WX Treat warnings as errors
diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst
index 14d6ae4..bfa3142 100644
--- a/docs/analyzer/DebugChecks.rst
+++ b/docs/analyzer/DebugChecks.rst
@@ -138,6 +138,64 @@
clang_analyzer_warnIfReached(); // no-warning
}
+- void clang_analyzer_warnOnDeadSymbol(int);
+
+ Subscribe for a delayed warning when the symbol that represents the value of
+ the argument is garbage-collected by the analyzer.
+
+ When calling 'clang_analyzer_warnOnDeadSymbol(x)', if value of 'x' is a
+ symbol, then this symbol is marked by the ExprInspection checker. Then,
+ during each garbage collection run, the checker sees if the marked symbol is
+ being collected and issues the 'SYMBOL DEAD' warning if it does.
+ This way you know where exactly, up to the line of code, the symbol dies.
+
+ It is unlikely that you call this function after the symbol is already dead,
+ because the very reference to it as the function argument prevents it from
+ dying. However, if the argument is not a symbol but a concrete value,
+ no warning would be issued.
+
+ Example usage::
+
+ do {
+ int x = generate_some_integer();
+ clang_analyzer_warnOnDeadSymbol(x);
+ } while(0); // expected-warning{{SYMBOL DEAD}}
+
+
+- void clang_analyzer_explain(a single argument of any type);
+
+ This function explains the value of its argument in a human-readable manner
+ in the warning message. You can make as many overrides of its prototype
+ in the test code as necessary to explain various integral, pointer,
+ or even record-type values.
+
+ Example usage::
+
+ void clang_analyzer_explain(int);
+ void clang_analyzer_explain(void *);
+
+ void foo(int param, void *ptr) {
+ clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
+ if (!ptr)
+ clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
+ }
+
+- size_t clang_analyzer_getExtent(void *);
+
+ This function returns the value that represents the extent of a memory region
+ pointed to by the argument. This value is often difficult to obtain otherwise,
+ because no valid code that produces this value. However, it may be useful
+ for testing purposes, to see how well does the analyzer model region extents.
+
+ Example usage::
+
+ void foo() {
+ int x, *y;
+ size_t xs = clang_analyzer_getExtent(&x);
+ clang_analyzer_explain(xs); // expected-warning{{'4'}}
+ size_t ys = clang_analyzer_getExtent(&y);
+ clang_analyzer_explain(ys); // expected-warning{{'8'}}
+ }
Statistics
==========
diff --git a/docs/conf.py b/docs/conf.py
index 6d53d94..1e8894a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -49,9 +49,9 @@
# built documents.
#
# The short X.Y version.
-version = '3.8'
+version = '3.9'
# The full version, including alpha/beta/rc tags.
-release = '3.8'
+release = '3.9'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index d50667d..81a15b8 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -24,9 +24,11 @@
AddressSanitizer
ThreadSanitizer
MemorySanitizer
+ UndefinedBehaviorSanitizer
DataFlowSanitizer
LeakSanitizer
SanitizerCoverage
+ SanitizerStats
SanitizerSpecialCaseList
ControlFlowIntegrity
SafeStack
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index 5812f86e..9ecff04 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -364,6 +364,6 @@
reference = re.sub(r'<!-- START_TRAVERSAL_MATCHERS.*END_TRAVERSAL_MATCHERS -->',
'%s', reference, flags=re.S) % traversal_matcher_table
-with open('../LibASTMatchersReference.html', 'w') as output:
+with open('../LibASTMatchersReference.html', 'wb') as output:
output.write(reference)
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index 5476052..b61d201 100755
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -188,6 +188,6 @@
contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
-with open(DOC_FILE, 'w') as output:
+with open(DOC_FILE, 'wb') as output:
output.write(contents)
diff --git a/include/clang-c/CXString.h b/include/clang-c/CXString.h
index a649cdf..68ab7bc 100644
--- a/include/clang-c/CXString.h
+++ b/include/clang-c/CXString.h
@@ -40,6 +40,11 @@
unsigned private_flags;
} CXString;
+typedef struct {
+ CXString *Strings;
+ unsigned Count;
+} CXStringSet;
+
/**
* \brief Retrieve the character data associated with the given string.
*/
@@ -51,6 +56,11 @@
CINDEX_LINKAGE void clang_disposeString(CXString string);
/**
+ * \brief Free the given string set.
+ */
+CINDEX_LINKAGE void clang_disposeStringSet(CXStringSet *set);
+
+/**
* @}
*/
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index cd5eb4e..69a98d7 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 31
+#define CINDEX_VERSION_MINOR 33
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -285,7 +285,6 @@
*/
typedef void *CXFile;
-
/**
* \brief Retrieve the complete file and path name of the given file.
*/
@@ -705,7 +704,6 @@
CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
unsigned Index);
-
/**
* \brief Describes the kind of error that occurred (if any) in a call to
* \c clang_loadDiagnostics.
@@ -1202,7 +1200,15 @@
* included into the set of code completions returned from this translation
* unit.
*/
- CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80
+ CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80,
+
+ /**
+ * \brief Used to indicate that the precompiled preamble should be created on
+ * the first parse. Otherwise it will be created on the first reparse. This
+ * trades runtime on the first parse (serializing the preamble takes time) for
+ * reduced runtime on the second parse (can now reuse the preamble).
+ */
+ CXTranslationUnit_CreatePreambleOnFirstParse = 0x100
};
/**
@@ -1289,6 +1295,17 @@
CXTranslationUnit *out_TU);
/**
+ * \brief Same as clang_parseTranslationUnit2 but requires a full command line
+ * for \c command_line_args including argv[0]. This is useful if the standard
+ * library paths are relative to the binary.
+ */
+CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2FullArgv(
+ CXIndex CIdx, const char *source_filename,
+ const char *const *command_line_args, int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
+ unsigned options, CXTranslationUnit *out_TU);
+
+/**
* \brief Flags that control how translation units are saved.
*
* The enumerators in this enumeration type are meant to be bitwise
@@ -2245,7 +2262,19 @@
*/
CXCursor_OMPTargetDataDirective = 257,
- CXCursor_LastStmt = CXCursor_OMPTargetDataDirective,
+ /** \brief OpenMP taskloop directive.
+ */
+ CXCursor_OMPTaskLoopDirective = 258,
+
+ /** \brief OpenMP taskloop simd directive.
+ */
+ CXCursor_OMPTaskLoopSimdDirective = 259,
+
+ /** \brief OpenMP distribute directive.
+ */
+ CXCursor_OMPDistributeDirective = 260,
+
+ CXCursor_LastStmt = CXCursor_OMPDistributeDirective,
/**
* \brief Cursor that represents the translation unit itself.
@@ -2280,7 +2309,9 @@
CXCursor_CUDAHostAttr = 415,
CXCursor_CUDASharedAttr = 416,
CXCursor_VisibilityAttr = 417,
- CXCursor_LastAttr = CXCursor_VisibilityAttr,
+ CXCursor_DLLExport = 418,
+ CXCursor_DLLImport = 419,
+ CXCursor_LastAttr = CXCursor_DLLImport,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -2296,8 +2327,9 @@
* \brief A module import declaration.
*/
CXCursor_ModuleImportDecl = 600,
+ CXCursor_TypeAliasTemplateDecl = 601,
CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
- CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl,
+ CXCursor_LastExtraDecl = CXCursor_TypeAliasTemplateDecl,
/**
* \brief A code completion overload candidate.
@@ -2399,6 +2431,11 @@
CINDEX_LINKAGE unsigned clang_isAttribute(enum CXCursorKind);
/**
+ * \brief Determine whether the given cursor has any attributes.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_hasAttrs(CXCursor C);
+
+/**
* \brief Determine whether the given cursor kind represents an invalid
* cursor.
*/
@@ -2448,6 +2485,32 @@
*/
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
+enum CXVisibilityKind {
+ /** \brief This value indicates that no visibility information is available
+ * for a provided CXCursor. */
+ CXVisibility_Invalid,
+
+ /** \brief Symbol not seen by the linker. */
+ CXVisibility_Hidden,
+ /** \brief Symbol seen by the linker but resolves to a symbol inside this object. */
+ CXVisibility_Protected,
+ /** \brief Symbol seen by the linker and acts like a normal symbol. */
+ CXVisibility_Default
+};
+
+/**
+ * \brief Describe the visibility of the entity referred to by a cursor.
+ *
+ * This returns the default visibility if not explicitly specified by
+ * a visibility attribute. The default visibility may be changed by
+ * commandline arguments.
+ *
+ * \param cursor The cursor to query.
+ *
+ * \returns The visibility of the cursor.
+ */
+CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor);
+
/**
* \brief Determine the availability of the entity that this cursor refers to,
* taking the current target platform into account.
@@ -2567,7 +2630,6 @@
*/
CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor);
-
/**
* \brief A fast container representing a set of CXCursors.
*/
@@ -2860,7 +2922,8 @@
CXType_IncompleteArray = 114,
CXType_VariableArray = 115,
CXType_DependentSizedArray = 116,
- CXType_MemberPointer = 117
+ CXType_MemberPointer = 117,
+ CXType_Auto = 118
};
/**
@@ -2885,7 +2948,6 @@
CXCallingConv_Unexposed = 200
};
-
/**
* \brief The type of an element in the abstract syntax tree.
*
@@ -3113,6 +3175,24 @@
CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T);
/**
+ * \brief Determine whether a CXCursor that is a macro, is
+ * function like.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isMacroFunctionLike(CXCursor C);
+
+/**
+ * \brief Determine whether a CXCursor that is a macro, is a
+ * builtin one.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isMacroBuiltin(CXCursor C);
+
+/**
+ * \brief Determine whether a CXCursor that is a function declaration, is an
+ * inline declaration.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C);
+
+/**
* \brief Determine whether a CXType has the "volatile" qualifier set,
* without looking through typedefs that may have added "volatile" at
* a different level.
@@ -3142,6 +3222,11 @@
CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C);
/**
+ * Returns the Objective-C type encoding for the specified CXType.
+ */
+CINDEX_LINKAGE CXString clang_Type_getObjCEncoding(CXType type);
+
+/**
* \brief Retrieve the spelling of a given CXTypeKind.
*/
CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K);
@@ -3323,7 +3408,6 @@
*/
CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C);
-
enum CXRefQualifierKind {
/** \brief No ref-qualifier was provided. */
CXRefQualifier_None = 0,
@@ -3452,7 +3536,6 @@
* @{
*/
-
/**
* \brief For cursors representing an iboutletcollection attribute,
* this function returns the collection element type.
@@ -3606,7 +3689,6 @@
CINDEX_LINKAGE CXString
clang_constructUSR_ObjCProtocol(const char *protocol_name);
-
/**
* \brief Construct a USR for a specified Objective-C instance variable and
* the USR for its containing class.
@@ -3732,7 +3814,6 @@
*/
CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
-
/**
* \brief If the cursor points to a selector identifier in an Objective-C
* method or message expression, this returns the selector index.
@@ -3863,6 +3944,12 @@
CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor);
/**
+ * \brief Retrieve the CXStrings representing the mangled symbols of the C++
+ * constructor or destructor at the cursor.
+ */
+CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
+
+/**
* @}
*/
@@ -4953,8 +5040,7 @@
*/
CINDEX_LINKAGE
CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results);
-
-
+
/**
* \brief Returns the currently-entered selector for an Objective-C message
* send, formatted like "initWithFoo:bar:". Only guaranteed to return a
@@ -4973,7 +5059,6 @@
* @}
*/
-
/**
* \defgroup CINDEX_MISC Miscellaneous utility functions
*
@@ -4986,7 +5071,6 @@
*/
CINDEX_LINKAGE CXString clang_getClangVersion(void);
-
/**
* \brief Enable/disable crash recovery.
*
@@ -5021,6 +5105,59 @@
CXInclusionVisitor visitor,
CXClientData client_data);
+typedef enum {
+ CXEval_Int = 1 ,
+ CXEval_Float = 2,
+ CXEval_ObjCStrLiteral = 3,
+ CXEval_StrLiteral = 4,
+ CXEval_CFStr = 5,
+ CXEval_Other = 6,
+
+ CXEval_UnExposed = 0
+
+} CXEvalResultKind ;
+
+/**
+ * \brief Evaluation result of a cursor
+ */
+typedef void * CXEvalResult;
+
+/**
+ * \brief If cursor is a statement declaration tries to evaluate the
+ * statement and if its variable, tries to evaluate its initializer,
+ * into its corresponding type.
+ */
+CINDEX_LINKAGE CXEvalResult clang_Cursor_Evaluate(CXCursor C);
+
+/**
+ * \brief Returns the kind of the evaluated result.
+ */
+CINDEX_LINKAGE CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as integer if the
+ * kind is Int.
+ */
+CINDEX_LINKAGE int clang_EvalResult_getAsInt(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as double if the
+ * kind is double.
+ */
+CINDEX_LINKAGE double clang_EvalResult_getAsDouble(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as a constant string if the
+ * kind is other than Int or float. User must not free this pointer,
+ * instead call clang_EvalResult_dispose on the CXEvalResult returned
+ * by clang_Cursor_Evaluate.
+ */
+CINDEX_LINKAGE const char* clang_EvalResult_getAsStr(CXEvalResult E);
+
+/**
+ * \brief Disposes the created Eval memory.
+ */
+CINDEX_LINKAGE void clang_EvalResult_dispose(CXEvalResult E);
/**
* @}
*/
@@ -5673,6 +5810,18 @@
unsigned TU_options);
/**
+ * \brief Same as clang_indexSourceFile but requires a full command line
+ * for \c command_line_args including argv[0]. This is useful if the standard
+ * library paths are relative to the binary.
+ */
+CINDEX_LINKAGE int clang_indexSourceFileFullArgv(
+ CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size, unsigned index_options,
+ const char *source_filename, const char *const *command_line_args,
+ int num_command_line_args, struct CXUnsavedFile *unsaved_files,
+ unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options);
+
+/**
* \brief Index the given translation unit via callbacks implemented through
* #IndexerCallbacks.
*
@@ -5753,7 +5902,6 @@
CXFieldVisitor visitor,
CXClientData client_data);
-
/**
* @}
*/
@@ -5766,4 +5914,3 @@
}
#endif
#endif
-
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index b2730e46..02f64a6 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -94,9 +94,10 @@
/// The default implementation passes it to HandleTopLevelDecl.
virtual void HandleImplicitImportDecl(ImportDecl *D);
- /// \brief Handle a pragma that appends to Linker Options. Currently this
- /// only exists to support Microsoft's #pragma comment(linker, "/foo").
- virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
+ /// \brief Handle a pragma or command line flag that appends to Linker
+ /// Options. This exists to support Microsoft's
+ /// #pragma comment(linker, "/foo") and the frontend flag --linker-option=.
+ virtual void HandleLinkerOption(llvm::StringRef Opts) {}
/// \brief Handle a pragma that emits a mismatch identifier and value to the
/// object file for the linker to work with. Currently, this only exists to
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 72bbb60..438e676 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -28,6 +28,7 @@
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SanitizerBlacklist.h"
@@ -130,6 +131,7 @@
mutable llvm::FoldingSet<AutoType> AutoTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
+ mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -251,8 +253,9 @@
mutable IdentifierInfo *MakeIntegerSeqName = nullptr;
QualType ObjCConstantStringType;
- mutable RecordDecl *CFConstantStringTypeDecl;
-
+ mutable RecordDecl *CFConstantStringTagDecl;
+ mutable TypedefDecl *CFConstantStringTypeDecl;
+
mutable QualType ObjCSuperType;
QualType ObjCNSStringType;
@@ -1078,6 +1081,9 @@
/// blocks.
QualType getBlockDescriptorType() const;
+ /// \brief Return pipe type for the specified type.
+ QualType getPipeType(QualType T) const;
+
/// Gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
@@ -1299,7 +1305,7 @@
UnaryTransformType::UTTKind UKind) const;
/// \brief C++11 deduced auto type.
- QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
+ QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
bool IsDependent) const;
/// \brief C++11 deduction pattern for 'auto' type.
@@ -1376,10 +1382,12 @@
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
if (CFConstantStringTypeDecl)
- return getTagDeclType(CFConstantStringTypeDecl);
+ return getTypedefType(CFConstantStringTypeDecl);
return QualType();
}
void setCFConstantStringType(QualType T);
+ TypedefDecl *getCFConstantStringDecl() const;
+ RecordDecl *getCFConstantStringTagDecl() const;
// This setter/getter represents the ObjC type for an NSConstantString.
void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl);
@@ -2256,9 +2264,7 @@
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType);
- void ResetObjCLayout(const ObjCContainerDecl *CD) {
- ObjCLayouts[CD] = nullptr;
- }
+ void ResetObjCLayout(const ObjCContainerDecl *CD);
//===--------------------------------------------------------------------===//
// Integer Predicates
@@ -2274,25 +2280,19 @@
QualType getCorrespondingUnsignedType(QualType T) const;
//===--------------------------------------------------------------------===//
- // Type Iterators.
- //===--------------------------------------------------------------------===//
- typedef llvm::iterator_range<SmallVectorImpl<Type *>::const_iterator>
- type_const_range;
-
- type_const_range types() const {
- return type_const_range(Types.begin(), Types.end());
- }
-
- //===--------------------------------------------------------------------===//
// Integer Values
//===--------------------------------------------------------------------===//
/// \brief Make an APSInt of the appropriate width and signedness for the
/// given \p Value and integer \p Type.
llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const {
- llvm::APSInt Res(getIntWidth(Type),
- !Type->isSignedIntegerOrEnumerationType());
+ // If Type is a signed integer type larger than 64 bits, we need to be sure
+ // to sign extend Res appropriately.
+ llvm::APSInt Res(64, !Type->isSignedIntegerOrEnumerationType());
Res = Value;
+ unsigned Width = getIntWidth(Type);
+ if (Width != Res.getBitWidth())
+ return Res.extOrTrunc(Width);
return Res;
}
@@ -2319,16 +2319,11 @@
/// \brief Get the duplicate declaration of a ObjCMethod in the same
/// interface, or null if none exists.
- const ObjCMethodDecl *getObjCMethodRedeclaration(
- const ObjCMethodDecl *MD) const {
- return ObjCMethodRedecls.lookup(MD);
- }
+ const ObjCMethodDecl *
+ getObjCMethodRedeclaration(const ObjCMethodDecl *MD) const;
void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
- const ObjCMethodDecl *Redecl) {
- assert(!getObjCMethodRedeclaration(MD) && "MD already has a redeclaration");
- ObjCMethodRedecls[MD] = Redecl;
- }
+ const ObjCMethodDecl *Redecl);
/// \brief Returns the Objective-C interface that \p ND belongs to if it is
/// an Objective-C method/property/ivar etc. that is part of an interface,
@@ -2524,9 +2519,15 @@
/// \brief A set of deallocations that should be performed when the
/// ASTContext is destroyed.
- typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
- DeallocationMap;
- DeallocationMap Deallocations;
+ // FIXME: We really should have a better mechanism in the ASTContext to
+ // manage running destructors for types which do variable sized allocation
+ // within the AST. In some places we thread the AST bump pointer allocator
+ // into the datastructures which avoids this mess during deallocation but is
+ // wasteful of memory, and here we require a lot of error prone book keeping
+ // in order to track and run destructors while we're tearing things down.
+ typedef llvm::SmallVector<std::pair<void (*)(void *), void *>, 16>
+ DeallocationFunctionsAndArguments;
+ DeallocationFunctionsAndArguments Deallocations;
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 3ff392d..cf3b55d 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -29,6 +29,7 @@
class ObjCContainerDecl;
class ObjCInterfaceDecl;
class ObjCPropertyDecl;
+ class ParmVarDecl;
class QualType;
class RecordDecl;
class TagDecl;
@@ -88,6 +89,9 @@
/// \brief A function template's definition was instantiated.
virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {}
+ /// \brief A default argument was instantiated.
+ virtual void DefaultArgumentInstantiated(const ParmVarDecl *D) {}
+
/// \brief A new objc category class was added for an interface.
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {}
diff --git a/include/clang/AST/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h
index 50ad953..dcaac80 100644
--- a/include/clang/AST/ASTTypeTraits.h
+++ b/include/clang/AST/ASTTypeTraits.h
@@ -271,6 +271,10 @@
if (!NodeKind.isSame(Other.NodeKind))
return NodeKind < Other.NodeKind;
+ if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
+ return getUnchecked<QualType>().getAsOpaquePtr() <
+ Other.getUnchecked<QualType>().getAsOpaquePtr();
+
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) {
auto TLA = getUnchecked<TypeLoc>();
auto TLB = Other.getUnchecked<TypeLoc>();
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index 85e237a..a08a683 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -1,4 +1,4 @@
-//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===//
+//===-- BuiltinTypes.def - Metadata about BuiltinTypes ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 1d22bcc..3a819d5 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -133,7 +133,7 @@
/// Test whether this is a multiple of the other value.
///
/// Among other things, this promises that
- /// self.RoundUpToAlignment(N) will just return self.
+ /// self.alignTo(N) will just return self.
bool isMultipleOf(CharUnits N) const {
return (*this % N) == 0;
}
@@ -170,12 +170,11 @@
/// getQuantity - Get the raw integer representation of this quantity.
QuantityType getQuantity() const { return Quantity; }
- /// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
+ /// alignTo - Returns the next integer (mod 2**64) that is
/// greater than or equal to this quantity and is a multiple of \p Align.
/// Align must be non-zero.
- CharUnits RoundUpToAlignment(const CharUnits &Align) const {
- return CharUnits(llvm::RoundUpToAlignment(Quantity,
- Align.Quantity));
+ CharUnits alignTo(const CharUnits &Align) const {
+ return CharUnits(llvm::alignTo(Quantity, Align.Quantity));
}
/// Given that this is a non-zero alignment value, what is the
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
deleted file mode 100644
index cc80a68..0000000
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ /dev/null
@@ -1,2735 +0,0 @@
-//===--- DataRecursiveASTVisitor.h - Data-Recursive AST Visitor -*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the DataRecursiveASTVisitor interface, which recursively
-// traverses the entire AST, using data recursion for Stmts/Exprs.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_DATARECURSIVEASTVISITOR_H
-#define LLVM_CLANG_AST_DATARECURSIVEASTVISITOR_H
-
-#include "clang/AST/Attr.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclFriend.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclOpenMP.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprOpenMP.h"
-#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/StmtOpenMP.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeLoc.h"
-
-// The following three macros are used for meta programming. The code
-// using them is responsible for defining macro OPERATOR().
-
-// All unary operators.
-#define UNARYOP_LIST() \
- OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \
- OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \
- OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \
- OPERATOR(Extension) OPERATOR(Coawait)
-
-// All binary operators (excluding compound assign operators).
-#define BINOP_LIST() \
- OPERATOR(PtrMemD) OPERATOR(PtrMemI) OPERATOR(Mul) OPERATOR(Div) \
- OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) OPERATOR(Shr) \
- OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) OPERATOR(GE) OPERATOR(EQ) \
- OPERATOR(NE) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) OPERATOR(LAnd) \
- OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma)
-
-// All compound assign operators.
-#define CAO_LIST() \
- OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) \
- OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor)
-
-namespace clang {
-
-// Reduce the diff between RecursiveASTVisitor / DataRecursiveASTVisitor to
-// make it easier to track changes and keep the two in sync.
-#define RecursiveASTVisitor DataRecursiveASTVisitor
-
-// A helper macro to implement short-circuiting when recursing. It
-// invokes CALL_EXPR, which must be a method call, on the derived
-// object (s.t. a user of RecursiveASTVisitor can override the method
-// in CALL_EXPR).
-#define TRY_TO(CALL_EXPR) \
- do { \
- if (!getDerived().CALL_EXPR) \
- return false; \
- } while (0)
-
-/// \brief A class that does preorder depth-first traversal on the
-/// entire Clang AST and visits each node.
-///
-/// This class performs three distinct tasks:
-/// 1. traverse the AST (i.e. go to each node);
-/// 2. at a given node, walk up the class hierarchy, starting from
-/// the node's dynamic type, until the top-most class (e.g. Stmt,
-/// Decl, or Type) is reached.
-/// 3. given a (node, class) combination, where 'class' is some base
-/// class of the dynamic type of 'node', call a user-overridable
-/// function to actually visit the node.
-///
-/// These tasks are done by three groups of methods, respectively:
-/// 1. TraverseDecl(Decl *x) does task #1. It is the entry point
-/// for traversing an AST rooted at x. This method simply
-/// dispatches (i.e. forwards) to TraverseFoo(Foo *x) where Foo
-/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and
-/// then recursively visits the child nodes of x.
-/// TraverseStmt(Stmt *x) and TraverseType(QualType x) work
-/// similarly.
-/// 2. WalkUpFromFoo(Foo *x) does task #2. It does not try to visit
-/// any child node of x. Instead, it first calls WalkUpFromBar(x)
-/// where Bar is the direct parent class of Foo (unless Foo has
-/// no parent), and then calls VisitFoo(x) (see the next list item).
-/// 3. VisitFoo(Foo *x) does task #3.
-///
-/// These three method groups are tiered (Traverse* > WalkUpFrom* >
-/// Visit*). A method (e.g. Traverse*) may call methods from the same
-/// tier (e.g. other Traverse*) or one tier lower (e.g. WalkUpFrom*).
-/// It may not call methods from a higher tier.
-///
-/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
-/// is Foo's super class) before calling VisitFoo(), the result is
-/// that the Visit*() methods for a given node are called in the
-/// top-down order (e.g. for a node of type NamespaceDecl, the order will
-/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
-///
-/// This scheme guarantees that all Visit*() calls for the same AST
-/// node are grouped together. In other words, Visit*() methods for
-/// different nodes are never interleaved.
-///
-/// Stmts are traversed internally using a data queue to avoid a stack overflow
-/// with hugely nested ASTs.
-///
-/// Clients of this visitor should subclass the visitor (providing
-/// themselves as the template argument, using the curiously recurring
-/// template pattern) and override any of the Traverse*, WalkUpFrom*,
-/// and Visit* methods for declarations, types, statements,
-/// expressions, or other AST nodes where the visitor should customize
-/// behavior. Most users only need to override Visit*. Advanced
-/// users may override Traverse* and WalkUpFrom* to implement custom
-/// traversal strategies. Returning false from one of these overridden
-/// functions will abort the entire traversal.
-///
-/// By default, this visitor tries to visit every part of the explicit
-/// source code exactly once. The default policy towards templates
-/// is to descend into the 'pattern' class or function body, not any
-/// explicit or implicit instantiations. Explicit specializations
-/// are still visited, and the patterns of partial specializations
-/// are visited separately. This behavior can be changed by
-/// overriding shouldVisitTemplateInstantiations() in the derived class
-/// to return true, in which case all known implicit and explicit
-/// instantiations will be visited at the same time as the pattern
-/// from which they were produced.
-template <typename Derived> class RecursiveASTVisitor {
-public:
- /// \brief Return a reference to the derived class.
- Derived &getDerived() { return *static_cast<Derived *>(this); }
-
- /// \brief Return whether this visitor should recurse into
- /// template instantiations.
- bool shouldVisitTemplateInstantiations() const { return false; }
-
- /// \brief Return whether this visitor should recurse into the types of
- /// TypeLocs.
- bool shouldWalkTypesOfTypeLocs() const { return true; }
-
- /// \brief Recursively visit a statement or expression, by
- /// dispatching to Traverse*() based on the argument's dynamic type.
- ///
- /// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is NULL).
- bool TraverseStmt(Stmt *S);
-
- /// \brief Recursively visit a type, by dispatching to
- /// Traverse*Type() based on the argument's getTypeClass() property.
- ///
- /// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is a Null type).
- bool TraverseType(QualType T);
-
- /// \brief Recursively visit a type with location, by dispatching to
- /// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
- ///
- /// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is a Null type location).
- bool TraverseTypeLoc(TypeLoc TL);
-
- /// \brief Recursively visit an attribute, by dispatching to
- /// Traverse*Attr() based on the argument's dynamic type.
- ///
- /// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is a Null type location).
- bool TraverseAttr(Attr *At);
-
- /// \brief Recursively visit a declaration, by dispatching to
- /// Traverse*Decl() based on the argument's dynamic type.
- ///
- /// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is NULL).
- bool TraverseDecl(Decl *D);
-
- /// \brief Recursively visit a C++ nested-name-specifier.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
-
- /// \brief Recursively visit a C++ nested-name-specifier with location
- /// information.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
-
- /// \brief Recursively visit a name with its location information.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);
-
- /// \brief Recursively visit a template name and dispatch to the
- /// appropriate method.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseTemplateName(TemplateName Template);
-
- /// \brief Recursively visit a template argument and dispatch to the
- /// appropriate method for the argument type.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- // FIXME: migrate callers to TemplateArgumentLoc instead.
- bool TraverseTemplateArgument(const TemplateArgument &Arg);
-
- /// \brief Recursively visit a template argument location and dispatch to the
- /// appropriate method for the argument type.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc);
-
- /// \brief Recursively visit a set of template arguments.
- /// This can be overridden by a subclass, but it's not expected that
- /// will be needed -- this visitor always dispatches to another.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead.
- bool TraverseTemplateArguments(const TemplateArgument *Args,
- unsigned NumArgs);
-
- /// \brief Recursively visit a constructor initializer. This
- /// automatically dispatches to another visitor for the initializer
- /// expression, but not for the name of the initializer, so may
- /// be overridden for clients that need access to the name.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
-
- /// \brief Recursively visit a lambda capture.
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
-
- /// \brief Recursively visit the body of a lambda expression.
- ///
- /// This provides a hook for visitors that need more context when visiting
- /// \c LE->getBody().
- ///
- /// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseLambdaBody(LambdaExpr *LE);
-
- // ---- Methods on Attrs ----
-
- // \brief Visit an attribute.
- bool VisitAttr(Attr *A) { return true; }
-
-// Declare Traverse* and empty Visit* for all Attr classes.
-#define ATTR_VISITOR_DECLS_ONLY
-#include "clang/AST/AttrVisitor.inc"
-#undef ATTR_VISITOR_DECLS_ONLY
-
-// ---- Methods on Stmts ----
-
-// Declare Traverse*() for all concrete Stmt classes.
-#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) bool Traverse##CLASS(CLASS *S);
-#include "clang/AST/StmtNodes.inc"
- // The above header #undefs ABSTRACT_STMT and STMT upon exit.
-
- // Define WalkUpFrom*() and empty Visit*() for all Stmt classes.
- bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); }
- bool VisitStmt(Stmt *S) { return true; }
-#define STMT(CLASS, PARENT) \
- bool WalkUpFrom##CLASS(CLASS *S) { \
- TRY_TO(WalkUpFrom##PARENT(S)); \
- TRY_TO(Visit##CLASS(S)); \
- return true; \
- } \
- bool Visit##CLASS(CLASS *S) { return true; }
-#include "clang/AST/StmtNodes.inc"
-
-// Define Traverse*(), WalkUpFrom*(), and Visit*() for unary
-// operator methods. Unary operators are not classes in themselves
-// (they're all opcodes in UnaryOperator) but do have visitors.
-#define OPERATOR(NAME) \
- bool TraverseUnary##NAME(UnaryOperator *S) { \
- TRY_TO(WalkUpFromUnary##NAME(S)); \
- StmtQueueAction StmtQueue(*this); \
- StmtQueue.queue(S->getSubExpr()); \
- return true; \
- } \
- bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
- TRY_TO(WalkUpFromUnaryOperator(S)); \
- TRY_TO(VisitUnary##NAME(S)); \
- return true; \
- } \
- bool VisitUnary##NAME(UnaryOperator *S) { return true; }
-
- UNARYOP_LIST()
-#undef OPERATOR
-
-// Define Traverse*(), WalkUpFrom*(), and Visit*() for binary
-// operator methods. Binary operators are not classes in themselves
-// (they're all opcodes in BinaryOperator) but do have visitors.
-#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \
- bool TraverseBin##NAME(BINOP_TYPE *S) { \
- TRY_TO(WalkUpFromBin##NAME(S)); \
- StmtQueueAction StmtQueue(*this); \
- StmtQueue.queue(S->getLHS()); \
- StmtQueue.queue(S->getRHS()); \
- return true; \
- } \
- bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
- TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \
- TRY_TO(VisitBin##NAME(S)); \
- return true; \
- } \
- bool VisitBin##NAME(BINOP_TYPE *S) { return true; }
-
-#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator)
- BINOP_LIST()
-#undef OPERATOR
-
-// Define Traverse*(), WalkUpFrom*(), and Visit*() for compound
-// assignment methods. Compound assignment operators are not
-// classes in themselves (they're all opcodes in
-// CompoundAssignOperator) but do have visitors.
-#define OPERATOR(NAME) \
- GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator)
-
- CAO_LIST()
-#undef OPERATOR
-#undef GENERAL_BINOP_FALLBACK
-
-// ---- Methods on Types ----
-// FIXME: revamp to take TypeLoc's rather than Types.
-
-// Declare Traverse*() for all concrete Type classes.
-#define ABSTRACT_TYPE(CLASS, BASE)
-#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T);
-#include "clang/AST/TypeNodes.def"
- // The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
-
- // Define WalkUpFrom*() and empty Visit*() for all Type classes.
- bool WalkUpFromType(Type *T) { return getDerived().VisitType(T); }
- bool VisitType(Type *T) { return true; }
-#define TYPE(CLASS, BASE) \
- bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \
- TRY_TO(WalkUpFrom##BASE(T)); \
- TRY_TO(Visit##CLASS##Type(T)); \
- return true; \
- } \
- bool Visit##CLASS##Type(CLASS##Type *T) { return true; }
-#include "clang/AST/TypeNodes.def"
-
-// ---- Methods on TypeLocs ----
-// FIXME: this currently just calls the matching Type methods
-
-// Declare Traverse*() for all concrete TypeLoc classes.
-#define ABSTRACT_TYPELOC(CLASS, BASE)
-#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
-#include "clang/AST/TypeLocNodes.def"
- // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit.
-
- // Define WalkUpFrom*() and empty Visit*() for all TypeLoc classes.
- bool WalkUpFromTypeLoc(TypeLoc TL) { return getDerived().VisitTypeLoc(TL); }
- bool VisitTypeLoc(TypeLoc TL) { return true; }
-
- // QualifiedTypeLoc and UnqualTypeLoc are not declared in
- // TypeNodes.def and thus need to be handled specially.
- bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) {
- return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc());
- }
- bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; }
- bool WalkUpFromUnqualTypeLoc(UnqualTypeLoc TL) {
- return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc());
- }
- bool VisitUnqualTypeLoc(UnqualTypeLoc TL) { return true; }
-
-// Note that BASE includes trailing 'Type' which CLASS doesn't.
-#define TYPE(CLASS, BASE) \
- bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
- TRY_TO(WalkUpFrom##BASE##Loc(TL)); \
- TRY_TO(Visit##CLASS##TypeLoc(TL)); \
- return true; \
- } \
- bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; }
-#include "clang/AST/TypeNodes.def"
-
-// ---- Methods on Decls ----
-
-// Declare Traverse*() for all concrete Decl classes.
-#define ABSTRACT_DECL(DECL)
-#define DECL(CLASS, BASE) bool Traverse##CLASS##Decl(CLASS##Decl *D);
-#include "clang/AST/DeclNodes.inc"
- // The above header #undefs ABSTRACT_DECL and DECL upon exit.
-
- // Define WalkUpFrom*() and empty Visit*() for all Decl classes.
- bool WalkUpFromDecl(Decl *D) { return getDerived().VisitDecl(D); }
- bool VisitDecl(Decl *D) { return true; }
-#define DECL(CLASS, BASE) \
- bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \
- TRY_TO(WalkUpFrom##BASE(D)); \
- TRY_TO(Visit##CLASS##Decl(D)); \
- return true; \
- } \
- bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; }
-#include "clang/AST/DeclNodes.inc"
-
-private:
- // These are helper methods used by more than one Traverse* method.
- bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
- bool TraverseClassInstantiations(ClassTemplateDecl *D);
- bool TraverseVariableInstantiations(VarTemplateDecl *D);
- bool TraverseFunctionInstantiations(FunctionTemplateDecl *D);
- bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
- unsigned Count);
- bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
- bool TraverseRecordHelper(RecordDecl *D);
- bool TraverseCXXRecordHelper(CXXRecordDecl *D);
- bool TraverseDeclaratorHelper(DeclaratorDecl *D);
- bool TraverseDeclContextHelper(DeclContext *DC);
- bool TraverseFunctionHelper(FunctionDecl *D);
- bool TraverseVarHelper(VarDecl *D);
- bool TraverseOMPExecutableDirective(OMPExecutableDirective *S);
- bool TraverseOMPLoopDirective(OMPLoopDirective *S);
- bool TraverseOMPClause(OMPClause *C);
-#define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C);
-#include "clang/Basic/OpenMPKinds.def"
- /// \brief Process clauses with list of variables.
- template <typename T> bool VisitOMPClauseList(T *Node);
-
- typedef SmallVector<Stmt *, 16> StmtsTy;
- typedef SmallVector<StmtsTy *, 4> QueuesTy;
-
- QueuesTy Queues;
-
- class NewQueueRAII {
- RecursiveASTVisitor &RAV;
-
- public:
- NewQueueRAII(StmtsTy &queue, RecursiveASTVisitor &RAV) : RAV(RAV) {
- RAV.Queues.push_back(&queue);
- }
- ~NewQueueRAII() { RAV.Queues.pop_back(); }
- };
-
- StmtsTy &getCurrentQueue() {
- assert(!Queues.empty() && "base TraverseStmt was never called?");
- return *Queues.back();
- }
-
-public:
- class StmtQueueAction {
- StmtsTy &CurrQueue;
-
- public:
- explicit StmtQueueAction(RecursiveASTVisitor &RAV)
- : CurrQueue(RAV.getCurrentQueue()) {}
-
- void queue(Stmt *S) { CurrQueue.push_back(S); }
- };
-};
-
-#define DISPATCH(NAME, CLASS, VAR) \
- return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
- if (!S)
- return true;
-
- StmtsTy Queue, StmtsToEnqueue;
- Queue.push_back(S);
- NewQueueRAII NQ(StmtsToEnqueue, *this);
-
- while (!Queue.empty()) {
- S = Queue.pop_back_val();
- if (!S)
- continue;
-
- StmtsToEnqueue.clear();
-
-#define DISPATCH_STMT(NAME, CLASS, VAR) \
- TRY_TO(Traverse##NAME(static_cast<CLASS *>(VAR))); \
- break
-
- // If we have a binary expr, dispatch to the subcode of the binop. A smart
- // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
- // below.
- if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
- switch (BinOp->getOpcode()) {
-#define OPERATOR(NAME) \
- case BO_##NAME: \
- DISPATCH_STMT(Bin##NAME, BinaryOperator, S);
-
- BINOP_LIST()
-#undef OPERATOR
-#undef BINOP_LIST
-
-#define OPERATOR(NAME) \
- case BO_##NAME##Assign: \
- DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S);
-
- CAO_LIST()
-#undef OPERATOR
-#undef CAO_LIST
- }
- } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
- switch (UnOp->getOpcode()) {
-#define OPERATOR(NAME) \
- case UO_##NAME: \
- DISPATCH_STMT(Unary##NAME, UnaryOperator, S);
-
- UNARYOP_LIST()
-#undef OPERATOR
-#undef UNARYOP_LIST
- }
- } else {
-
- // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
- switch (S->getStmtClass()) {
- case Stmt::NoStmtClass:
- break;
-#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) \
- case Stmt::CLASS##Class: \
- DISPATCH_STMT(CLASS, CLASS, S);
-#include "clang/AST/StmtNodes.inc"
- }
- }
-
- Queue.append(StmtsToEnqueue.rbegin(), StmtsToEnqueue.rend());
- }
-
- return true;
-}
-
-#undef DISPATCH_STMT
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
- if (T.isNull())
- return true;
-
- switch (T->getTypeClass()) {
-#define ABSTRACT_TYPE(CLASS, BASE)
-#define TYPE(CLASS, BASE) \
- case Type::CLASS: \
- DISPATCH(CLASS##Type, CLASS##Type, const_cast<Type *>(T.getTypePtr()));
-#include "clang/AST/TypeNodes.def"
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
- if (TL.isNull())
- return true;
-
- switch (TL.getTypeLocClass()) {
-#define ABSTRACT_TYPELOC(CLASS, BASE)
-#define TYPELOC(CLASS, BASE) \
- case TypeLoc::CLASS: \
- return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>());
-#include "clang/AST/TypeLocNodes.def"
- }
-
- return true;
-}
-
-// Define the Traverse*Attr(Attr* A) methods
-#define VISITORCLASS RecursiveASTVisitor
-#include "clang/AST/AttrVisitor.inc"
-#undef VISITORCLASS
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
- if (!D)
- return true;
-
- // As a syntax visitor, we want to ignore declarations for
- // implicitly-defined declarations (ones not typed explicitly by the
- // user).
- if (D->isImplicit())
- return true;
-
- switch (D->getKind()) {
-#define ABSTRACT_DECL(DECL)
-#define DECL(CLASS, BASE) \
- case Decl::CLASS: \
- if (!getDerived().Traverse##CLASS##Decl(static_cast<CLASS##Decl *>(D))) \
- return false; \
- break;
-#include "clang/AST/DeclNodes.inc"
- }
-
- // Visit any attributes attached to this declaration.
- for (auto *I : D->attrs()) {
- if (!getDerived().TraverseAttr(I))
- return false;
- }
- return true;
-}
-
-#undef DISPATCH
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
- NestedNameSpecifier *NNS) {
- if (!NNS)
- return true;
-
- if (NNS->getPrefix())
- TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix()));
-
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::NamespaceAlias:
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- return true;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- TRY_TO(TraverseType(QualType(NNS->getAsType(), 0)));
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
- NestedNameSpecifierLoc NNS) {
- if (!NNS)
- return true;
-
- if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
- TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
-
- switch (NNS.getNestedNameSpecifier()->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::NamespaceAlias:
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- return true;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
- break;
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
- DeclarationNameInfo NameInfo) {
- switch (NameInfo.getName().getNameKind()) {
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
- TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
-
- break;
-
- case DeclarationName::Identifier:
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- case DeclarationName::CXXOperatorName:
- case DeclarationName::CXXLiteralOperatorName:
- case DeclarationName::CXXUsingDirective:
- break;
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
- if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
- TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier()));
- else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
- const TemplateArgument &Arg) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::NullPtr:
- return true;
-
- case TemplateArgument::Type:
- return getDerived().TraverseType(Arg.getAsType());
-
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- return getDerived().TraverseTemplateName(
- Arg.getAsTemplateOrTemplatePattern());
-
- case TemplateArgument::Expression:
- return getDerived().TraverseStmt(Arg.getAsExpr());
-
- case TemplateArgument::Pack:
- return getDerived().TraverseTemplateArguments(Arg.pack_begin(),
- Arg.pack_size());
- }
-
- return true;
-}
-
-// FIXME: no template name location?
-// FIXME: no source locations for a template argument pack?
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
- const TemplateArgumentLoc &ArgLoc) {
- const TemplateArgument &Arg = ArgLoc.getArgument();
-
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::NullPtr:
- return true;
-
- case TemplateArgument::Type: {
- // FIXME: how can TSI ever be NULL?
- if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo())
- return getDerived().TraverseTypeLoc(TSI->getTypeLoc());
- else
- return getDerived().TraverseType(Arg.getAsType());
- }
-
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- if (ArgLoc.getTemplateQualifierLoc())
- TRY_TO(getDerived().TraverseNestedNameSpecifierLoc(
- ArgLoc.getTemplateQualifierLoc()));
- return getDerived().TraverseTemplateName(
- Arg.getAsTemplateOrTemplatePattern());
-
- case TemplateArgument::Expression:
- return getDerived().TraverseStmt(ArgLoc.getSourceExpression());
-
- case TemplateArgument::Pack:
- return getDerived().TraverseTemplateArguments(Arg.pack_begin(),
- Arg.pack_size());
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
- const TemplateArgument *Args, unsigned NumArgs) {
- for (unsigned I = 0; I != NumArgs; ++I) {
- TRY_TO(TraverseTemplateArgument(Args[I]));
- }
-
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
- CXXCtorInitializer *Init) {
- if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
- TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
-
- if (Init->isWritten())
- TRY_TO(TraverseStmt(Init->getInit()));
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
- const LambdaCapture *C) {
- if (LE->isInitCapture(C))
- TRY_TO(TraverseDecl(C->getCapturedVar()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
- StmtQueueAction StmtQueue(*this);
- StmtQueue.queue(LE->getBody());
- return true;
-}
-
-// ----------------- Type traversal -----------------
-
-// This macro makes available a variable T, the passed-in type.
-#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
- template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T) { \
- TRY_TO(WalkUpFrom##TYPE(T)); \
- { CODE; } \
- return true; \
- }
-
-DEF_TRAVERSE_TYPE(BuiltinType, {})
-
-DEF_TRAVERSE_TYPE(ComplexType, { TRY_TO(TraverseType(T->getElementType())); })
-
-DEF_TRAVERSE_TYPE(PointerType, { TRY_TO(TraverseType(T->getPointeeType())); })
-
-DEF_TRAVERSE_TYPE(BlockPointerType,
- { TRY_TO(TraverseType(T->getPointeeType())); })
-
-DEF_TRAVERSE_TYPE(LValueReferenceType,
- { TRY_TO(TraverseType(T->getPointeeType())); })
-
-DEF_TRAVERSE_TYPE(RValueReferenceType,
- { TRY_TO(TraverseType(T->getPointeeType())); })
-
-DEF_TRAVERSE_TYPE(MemberPointerType, {
- TRY_TO(TraverseType(QualType(T->getClass(), 0)));
- TRY_TO(TraverseType(T->getPointeeType()));
-})
-
-DEF_TRAVERSE_TYPE(AdjustedType, { TRY_TO(TraverseType(T->getOriginalType())); })
-
-DEF_TRAVERSE_TYPE(DecayedType, { TRY_TO(TraverseType(T->getOriginalType())); })
-
-DEF_TRAVERSE_TYPE(ConstantArrayType,
- { TRY_TO(TraverseType(T->getElementType())); })
-
-DEF_TRAVERSE_TYPE(IncompleteArrayType,
- { TRY_TO(TraverseType(T->getElementType())); })
-
-DEF_TRAVERSE_TYPE(VariableArrayType, {
- TRY_TO(TraverseType(T->getElementType()));
- TRY_TO(TraverseStmt(T->getSizeExpr()));
-})
-
-DEF_TRAVERSE_TYPE(DependentSizedArrayType, {
- TRY_TO(TraverseType(T->getElementType()));
- if (T->getSizeExpr())
- TRY_TO(TraverseStmt(T->getSizeExpr()));
-})
-
-DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, {
- if (T->getSizeExpr())
- TRY_TO(TraverseStmt(T->getSizeExpr()));
- TRY_TO(TraverseType(T->getElementType()));
-})
-
-DEF_TRAVERSE_TYPE(VectorType, { TRY_TO(TraverseType(T->getElementType())); })
-
-DEF_TRAVERSE_TYPE(ExtVectorType, { TRY_TO(TraverseType(T->getElementType())); })
-
-DEF_TRAVERSE_TYPE(FunctionNoProtoType,
- { TRY_TO(TraverseType(T->getReturnType())); })
-
-DEF_TRAVERSE_TYPE(FunctionProtoType, {
- TRY_TO(TraverseType(T->getReturnType()));
-
- for (const auto &A : T->param_types()) {
- TRY_TO(TraverseType(A));
- }
-
- for (const auto &E : T->exceptions()) {
- TRY_TO(TraverseType(E));
- }
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
-})
-
-DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
-DEF_TRAVERSE_TYPE(TypedefType, {})
-
-DEF_TRAVERSE_TYPE(TypeOfExprType,
- { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
-
-DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnderlyingType())); })
-
-DEF_TRAVERSE_TYPE(DecltypeType,
- { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
-
-DEF_TRAVERSE_TYPE(UnaryTransformType, {
- TRY_TO(TraverseType(T->getBaseType()));
- TRY_TO(TraverseType(T->getUnderlyingType()));
-})
-
-DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
-
-DEF_TRAVERSE_TYPE(RecordType, {})
-DEF_TRAVERSE_TYPE(EnumType, {})
-DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {})
-
-DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(T->getTemplateName()));
- TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
-})
-
-DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
-
-DEF_TRAVERSE_TYPE(AttributedType,
- { TRY_TO(TraverseType(T->getModifiedType())); })
-
-DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); })
-
-DEF_TRAVERSE_TYPE(ElaboratedType, {
- if (T->getQualifier()) {
- TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
- }
- TRY_TO(TraverseType(T->getNamedType()));
-})
-
-DEF_TRAVERSE_TYPE(DependentNameType,
- { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); })
-
-DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
- TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
- TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
-})
-
-DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); })
-
-DEF_TRAVERSE_TYPE(ObjCInterfaceType, {})
-
-DEF_TRAVERSE_TYPE(ObjCObjectType, {
- // We have to watch out here because an ObjCInterfaceType's base
- // type is itself.
- if (T->getBaseType().getTypePtr() != T)
- TRY_TO(TraverseType(T->getBaseType()));
- for (auto typeArg : T->getTypeArgsAsWritten()) {
- TRY_TO(TraverseType(typeArg));
- }
-})
-
-DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
- { TRY_TO(TraverseType(T->getPointeeType())); })
-
-DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); })
-
-#undef DEF_TRAVERSE_TYPE
-
-// ----------------- TypeLoc traversal -----------------
-
-// This macro makes available a variable TL, the passed-in TypeLoc.
-// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
-// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
-// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods
-// continue to work.
-#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
- template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \
- if (getDerived().shouldWalkTypesOfTypeLocs()) \
- TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE *>(TL.getTypePtr()))); \
- TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
- { CODE; } \
- return true; \
- }
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
- // Move this over to the 'main' typeloc tree. Note that this is a
- // move -- we pretend that we were really looking at the unqualified
- // typeloc all along -- rather than a recursion, so we don't follow
- // the normal CRTP plan of going through
- // getDerived().TraverseTypeLoc. If we did, we'd be traversing
- // twice for the same type (once as a QualifiedTypeLoc version of
- // the type, once as an UnqualifiedTypeLoc version of the type),
- // which in effect means we'd call VisitTypeLoc twice with the
- // 'same' type. This solves that problem, at the cost of never
- // seeing the qualified version of the type (unless the client
- // subclasses TraverseQualifiedTypeLoc themselves). It's not a
- // perfect solution. A perfect solution probably requires making
- // QualifiedTypeLoc a wrapper around TypeLoc -- like QualType is a
- // wrapper around Type* -- rather than being its own class in the
- // type hierarchy.
- return TraverseTypeLoc(TL.getUnqualifiedLoc());
-}
-
-DEF_TRAVERSE_TYPELOC(BuiltinType, {})
-
-// FIXME: ComplexTypeLoc is unfinished
-DEF_TRAVERSE_TYPELOC(ComplexType, {
- TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
-})
-
-DEF_TRAVERSE_TYPELOC(PointerType,
- { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); })
-
-DEF_TRAVERSE_TYPELOC(BlockPointerType,
- { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); })
-
-DEF_TRAVERSE_TYPELOC(LValueReferenceType,
- { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); })
-
-DEF_TRAVERSE_TYPELOC(RValueReferenceType,
- { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); })
-
-// FIXME: location of base class?
-// We traverse this in the type case as well, but how is it not reached through
-// the pointee type?
-DEF_TRAVERSE_TYPELOC(MemberPointerType, {
- TRY_TO(TraverseType(QualType(TL.getTypePtr()->getClass(), 0)));
- TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
-})
-
-DEF_TRAVERSE_TYPELOC(AdjustedType,
- { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); })
-
-DEF_TRAVERSE_TYPELOC(DecayedType,
- { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); })
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
- // This isn't available for ArrayType, but is for the ArrayTypeLoc.
- TRY_TO(TraverseStmt(TL.getSizeExpr()));
- return true;
-}
-
-DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
- TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
- return TraverseArrayTypeLocHelper(TL);
-})
-
-DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
- TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
- return TraverseArrayTypeLocHelper(TL);
-})
-
-DEF_TRAVERSE_TYPELOC(VariableArrayType, {
- TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
- return TraverseArrayTypeLocHelper(TL);
-})
-
-DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, {
- TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
- return TraverseArrayTypeLocHelper(TL);
-})
-
-// FIXME: order? why not size expr first?
-// FIXME: base VectorTypeLoc is unfinished
-DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, {
- if (TL.getTypePtr()->getSizeExpr())
- TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr()));
- TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
-})
-
-// FIXME: VectorTypeLoc is unfinished
-DEF_TRAVERSE_TYPELOC(VectorType, {
- TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
-})
-
-// FIXME: size and attributes
-// FIXME: base VectorTypeLoc is unfinished
-DEF_TRAVERSE_TYPELOC(ExtVectorType, {
- TRY_TO(TraverseType(TL.getTypePtr()->getElementType()));
-})
-
-DEF_TRAVERSE_TYPELOC(FunctionNoProtoType,
- { TRY_TO(TraverseTypeLoc(TL.getReturnLoc())); })
-
-// FIXME: location of exception specifications (attributes?)
-DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
- TRY_TO(TraverseTypeLoc(TL.getReturnLoc()));
-
- const FunctionProtoType *T = TL.getTypePtr();
-
- for (unsigned I = 0, E = TL.getNumParams(); I != E; ++I) {
- if (TL.getParam(I)) {
- TRY_TO(TraverseDecl(TL.getParam(I)));
- } else if (I < T->getNumParams()) {
- TRY_TO(TraverseType(T->getParamType(I)));
- }
- }
-
- for (const auto &E : T->exceptions()) {
- TRY_TO(TraverseType(E));
- }
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
-})
-
-DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
-DEF_TRAVERSE_TYPELOC(TypedefType, {})
-
-DEF_TRAVERSE_TYPELOC(TypeOfExprType,
- { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); })
-
-DEF_TRAVERSE_TYPELOC(TypeOfType, {
- TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
-})
-
-// FIXME: location of underlying expr
-DEF_TRAVERSE_TYPELOC(DecltypeType, {
- TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
-})
-
-DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
- TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_TYPELOC(AutoType, {
- TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
-})
-
-DEF_TRAVERSE_TYPELOC(RecordType, {})
-DEF_TRAVERSE_TYPELOC(EnumType, {})
-DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {})
-
-// FIXME: use the loc for the template name?
-DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
- }
-})
-
-DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {})
-
-DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
-
-DEF_TRAVERSE_TYPELOC(AttributedType,
- { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); })
-
-DEF_TRAVERSE_TYPELOC(ElaboratedType, {
- if (TL.getQualifierLoc()) {
- TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
- }
- TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc()));
-})
-
-DEF_TRAVERSE_TYPELOC(DependentNameType, {
- TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
-})
-
-DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
- if (TL.getQualifierLoc()) {
- TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
- }
-
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
- }
-})
-
-DEF_TRAVERSE_TYPELOC(PackExpansionType,
- { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); })
-
-DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, {})
-
-DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
- // We have to watch out here because an ObjCInterfaceType's base
- // type is itself.
- if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
- TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
- for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
- TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc()));
-})
-
-DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
- { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); })
-
-DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
-
-#undef DEF_TRAVERSE_TYPELOC
-
-// ----------------- Decl traversal -----------------
-//
-// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing
-// the children that come from the DeclContext associated with it.
-// Therefore each Traverse* only needs to worry about children other
-// than those.
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
- if (!DC)
- return true;
-
- for (auto *Child : DC->decls()) {
- // BlockDecls and CapturedDecls are traversed through BlockExprs and
- // CapturedStmts respectively.
- if (!isa<BlockDecl>(Child) && !isa<CapturedDecl>(Child))
- TRY_TO(TraverseDecl(Child));
- }
-
- return true;
-}
-
-// This macro makes available a variable D, the passed-in decl.
-#define DEF_TRAVERSE_DECL(DECL, CODE) \
- template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##DECL(DECL *D) { \
- TRY_TO(WalkUpFrom##DECL(D)); \
- { CODE; } \
- TRY_TO(TraverseDeclContextHelper(dyn_cast<DeclContext>(D))); \
- return true; \
- }
-
-DEF_TRAVERSE_DECL(AccessSpecDecl, {})
-
-DEF_TRAVERSE_DECL(BlockDecl, {
- if (TypeSourceInfo *TInfo = D->getSignatureAsWritten())
- TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
- TRY_TO(TraverseStmt(D->getBody()));
- for (const auto &I : D->captures()) {
- if (I.hasCopyExpr()) {
- TRY_TO(TraverseStmt(I.getCopyExpr()));
- }
- }
- // This return statement makes sure the traversal of nodes in
- // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
- // is skipped - don't remove it.
- return true;
-})
-
-DEF_TRAVERSE_DECL(CapturedDecl, {
- TRY_TO(TraverseStmt(D->getBody()));
- // This return statement makes sure the traversal of nodes in
- // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
- // is skipped - don't remove it.
- return true;
-})
-
-DEF_TRAVERSE_DECL(EmptyDecl, {})
-
-DEF_TRAVERSE_DECL(FileScopeAsmDecl,
- { TRY_TO(TraverseStmt(D->getAsmString())); })
-
-DEF_TRAVERSE_DECL(ImportDecl, {})
-
-DEF_TRAVERSE_DECL(FriendDecl, {
- // Friend is either decl or a type.
- if (D->getFriendType())
- TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
- else
- TRY_TO(TraverseDecl(D->getFriendDecl()));
-})
-
-DEF_TRAVERSE_DECL(FriendTemplateDecl, {
- if (D->getFriendType())
- TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
- else
- TRY_TO(TraverseDecl(D->getFriendDecl()));
- for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
- TemplateParameterList *TPL = D->getTemplateParameterList(I);
- for (TemplateParameterList::iterator ITPL = TPL->begin(), ETPL = TPL->end();
- ITPL != ETPL; ++ITPL) {
- TRY_TO(TraverseDecl(*ITPL));
- }
- }
-})
-
-DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl,
- { TRY_TO(TraverseDecl(D->getSpecialization())); })
-
-DEF_TRAVERSE_DECL(LinkageSpecDecl, {})
-
-DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {// FIXME: implement this
- })
-
-DEF_TRAVERSE_DECL(StaticAssertDecl, {
- TRY_TO(TraverseStmt(D->getAssertExpr()));
- TRY_TO(TraverseStmt(D->getMessage()));
-})
-
-DEF_TRAVERSE_DECL(
- TranslationUnitDecl,
- {// Code in an unnamed namespace shows up automatically in
- // decls_begin()/decls_end(). Thus we don't need to recurse on
- // D->getAnonymousNamespace().
- })
-
-DEF_TRAVERSE_DECL(ExternCContextDecl, {})
-
-DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
- // We shouldn't traverse an aliased namespace, since it will be
- // defined (and, therefore, traversed) somewhere else.
- //
- // This return statement makes sure the traversal of nodes in
- // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
- // is skipped - don't remove it.
- return true;
-})
-
-DEF_TRAVERSE_DECL(LabelDecl, {// There is no code in a LabelDecl.
- })
-
-DEF_TRAVERSE_DECL(
- NamespaceDecl,
- {// Code in an unnamed namespace shows up automatically in
- // decls_begin()/decls_end(). Thus we don't need to recurse on
- // D->getAnonymousNamespace().
- })
-
-DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
- })
-
-DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
- if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
- for (auto typeParam : *typeParamList) {
- TRY_TO(TraverseObjCTypeParamDecl(typeParam));
- }
- }
- return true;
-})
-
-DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
- })
-
-DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
- })
-
-DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
- if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
- for (auto typeParam : *typeParamList) {
- TRY_TO(TraverseObjCTypeParamDecl(typeParam));
- }
- }
-
- if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) {
- TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc()));
- }
-})
-
-DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
- })
-
-DEF_TRAVERSE_DECL(ObjCMethodDecl, {
- if (D->getReturnTypeSourceInfo()) {
- TRY_TO(TraverseTypeLoc(D->getReturnTypeSourceInfo()->getTypeLoc()));
- }
- for (ObjCMethodDecl::param_iterator I = D->param_begin(), E = D->param_end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
- }
- if (D->isThisDeclarationADefinition()) {
- TRY_TO(TraverseStmt(D->getBody()));
- }
- return true;
-})
-
-DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
- if (D->hasExplicitBound()) {
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
- // We shouldn't traverse D->getTypeForDecl(); it's a result of
- // declaring the type alias, not something that was written in the
- // source.
- }
-})
-
-DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
- if (D->getTypeSourceInfo())
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
- else
- TRY_TO(TraverseType(D->getType()));
- return true;
-})
-
-DEF_TRAVERSE_DECL(UsingDecl, {
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
-})
-
-DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
-})
-
-DEF_TRAVERSE_DECL(UsingShadowDecl, {})
-
-DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
- for (auto *I : D->varlists()) {
- TRY_TO(TraverseStmt(I));
- }
-})
-
-// A helper method for TemplateDecl's children.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
- TemplateParameterList *TPL) {
- if (TPL) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
- }
- }
- return true;
-}
-
-// A helper method for traversing the implicit instantiations of a
-// class template.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
- ClassTemplateDecl *D) {
- for (auto *SD : D->specializations()) {
- for (auto *RD : SD->redecls()) {
- // We don't want to visit injected-class-names in this traversal.
- if (cast<CXXRecordDecl>(RD)->isInjectedClassName())
- continue;
-
- switch (
- cast<ClassTemplateSpecializationDecl>(RD)->getSpecializationKind()) {
- // Visit the implicit instantiations with the requested pattern.
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- TRY_TO(TraverseDecl(RD));
- break;
-
- // We don't need to do anything on an explicit instantiation
- // or explicit specialization because there will be an explicit
- // node for it elsewhere.
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitSpecialization:
- break;
- }
- }
- }
-
- return true;
-}
-
-DEF_TRAVERSE_DECL(ClassTemplateDecl, {
- CXXRecordDecl *TempDecl = D->getTemplatedDecl();
- TRY_TO(TraverseDecl(TempDecl));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
- // By default, we do not traverse the instantiations of
- // class templates since they do not appear in the user code. The
- // following code optionally traverses them.
- //
- // We only traverse the class instantiations when we see the canonical
- // declaration of the template, to ensure we only visit them once.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D == D->getCanonicalDecl())
- TRY_TO(TraverseClassInstantiations(D));
-
- // Note that getInstantiatedFromMemberTemplate() is just a link
- // from a template instantiation back to the template from which
- // it was instantiated, and thus should not be traversed.
-})
-
-// A helper method for traversing the implicit instantiations of a
-// class template.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseVariableInstantiations(
- VarTemplateDecl *D) {
- for (auto *SD : D->specializations()) {
- for (auto *RD : SD->redecls()) {
- switch (
- cast<VarTemplateSpecializationDecl>(RD)->getSpecializationKind()) {
- // Visit the implicit instantiations with the requested pattern.
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- TRY_TO(TraverseDecl(RD));
- break;
-
- // We don't need to do anything on an explicit instantiation
- // or explicit specialization because there will be an explicit
- // node for it elsewhere.
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitSpecialization:
- break;
- }
- }
- }
-
- return true;
-}
-
-DEF_TRAVERSE_DECL(VarTemplateDecl, {
- VarDecl *TempDecl = D->getTemplatedDecl();
- TRY_TO(TraverseDecl(TempDecl));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
- // By default, we do not traverse the instantiations of
- // variable templates since they do not appear in the user code. The
- // following code optionally traverses them.
- //
- // We only traverse the variable instantiations when we see the canonical
- // declaration of the template, to ensure we only visit them once.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D == D->getCanonicalDecl())
- TRY_TO(TraverseVariableInstantiations(D));
-
- // Note that getInstantiatedFromMemberTemplate() is just a link
- // from a template instantiation back to the template from which
- // it was instantiated, and thus should not be traversed.
-})
-
-// A helper method for traversing the instantiations of a
-// function while skipping its specializations.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
- FunctionTemplateDecl *D) {
- for (auto *FD : D->specializations()) {
- for (auto *RD : FD->redecls()) {
- switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- // We don't know what kind of FunctionDecl this is.
- TRY_TO(TraverseDecl(RD));
- break;
-
- // No need to visit explicit instantiations, we'll find the node
- // eventually.
- // FIXME: This is incorrect; there is no other node for an explicit
- // instantiation of a function template specialization.
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- break;
-
- case TSK_ExplicitSpecialization:
- break;
- }
- }
- }
-
- return true;
-}
-
-DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
- TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
- // By default, we do not traverse the instantiations of
- // function templates since they do not appear in the user code. The
- // following code optionally traverses them.
- //
- // We only traverse the function instantiations when we see the canonical
- // declaration of the template, to ensure we only visit them once.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D == D->getCanonicalDecl())
- TRY_TO(TraverseFunctionInstantiations(D));
-})
-
-DEF_TRAVERSE_DECL(BuiltinTemplateDecl, {
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-})
-
-DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
- // D is the "T" in something like
- // template <template <typename> class T> class container { };
- TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- if (D->hasDefaultArgument()) {
- TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
- }
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-})
-
-DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
- // D is the "T" in something like "template<typename T> class vector;"
- if (D->getTypeForDecl())
- TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
- if (D->hasDefaultArgument())
- TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_DECL(TypedefDecl, {
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
- // We shouldn't traverse D->getTypeForDecl(); it's a result of
- // declaring the typedef, not something that was written in the
- // source.
-})
-
-DEF_TRAVERSE_DECL(TypeAliasDecl, {
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
- // We shouldn't traverse D->getTypeForDecl(); it's a result of
- // declaring the type alias, not something that was written in the
- // source.
-})
-
-DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
- TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-})
-
-DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
- // A dependent using declaration which was marked with 'typename'.
- // template<class T> class A : public B<T> { using typename B<T>::foo; };
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- // We shouldn't traverse D->getTypeForDecl(); it's a result of
- // declaring the type, not something that was written in the
- // source.
-})
-
-DEF_TRAVERSE_DECL(EnumDecl, {
- if (D->getTypeForDecl())
- TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
-
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- // The enumerators are already traversed by
- // decls_begin()/decls_end().
-})
-
-// Helper methods for RecordDecl and its children.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) {
- // We shouldn't traverse D->getTypeForDecl(); it's a result of
- // declaring the type, not something that was written in the source.
-
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(CXXRecordDecl *D) {
- if (!TraverseRecordHelper(D))
- return false;
- if (D->isCompleteDefinition()) {
- for (const auto &I : D->bases()) {
- TRY_TO(TraverseTypeLoc(I.getTypeSourceInfo()->getTypeLoc()));
- }
- // We don't traverse the friends or the conversions, as they are
- // already in decls_begin()/decls_end().
- }
- return true;
-}
-
-DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })
-
-DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
-
-DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
- // For implicit instantiations ("set<int> x;"), we don't want to
- // recurse at all, since the instatiated class isn't written in
- // the source code anywhere. (Note the instatiated *type* --
- // set<int> -- is written, and will still get a callback of
- // TemplateSpecializationType). For explicit instantiations
- // ("template set<int>;"), we do need a callback, since this
- // is the only callback that's made for this instantiation.
- // We use getTypeAsWritten() to distinguish.
- if (TypeSourceInfo *TSI = D->getTypeAsWritten())
- TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-
- if (!getDerived().shouldVisitTemplateInstantiations() &&
- D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
- // Returning from here skips traversing the
- // declaration context of the ClassTemplateSpecializationDecl
- // (embedded in the DEF_TRAVERSE_DECL() macro)
- // which contains the instantiated members of the class.
- return true;
-})
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
- const TemplateArgumentLoc *TAL, unsigned Count) {
- for (unsigned I = 0; I < Count; ++I) {
- TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
- }
- return true;
-}
-
-DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
- // The partial specialization.
- if (TemplateParameterList *TPL = D->getTemplateParameters()) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
- }
- }
- // The args that remains unspecialized.
- TRY_TO(TraverseTemplateArgumentLocsHelper(
- D->getTemplateArgsAsWritten()->getTemplateArgs(),
- D->getTemplateArgsAsWritten()->NumTemplateArgs));
-
- // Don't need the ClassTemplatePartialSpecializationHelper, even
- // though that's our parent class -- we already visit all the
- // template args here.
- TRY_TO(TraverseCXXRecordHelper(D));
-
- // Instantiations will have been visited with the primary template.
-})
-
-DEF_TRAVERSE_DECL(EnumConstantDecl, { TRY_TO(TraverseStmt(D->getInitExpr())); })
-
-DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
- // Like UnresolvedUsingTypenameDecl, but without the 'typename':
- // template <class T> Class A : public Base<T> { using Base<T>::foo; };
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
-})
-
-DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- if (D->getTypeSourceInfo())
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
- else
- TRY_TO(TraverseType(D->getType()));
- return true;
-}
-
-DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
-
-DEF_TRAVERSE_DECL(FieldDecl, {
- TRY_TO(TraverseDeclaratorHelper(D));
- if (D->isBitField())
- TRY_TO(TraverseStmt(D->getBitWidth()));
- else if (D->hasInClassInitializer())
- TRY_TO(TraverseStmt(D->getInClassInitializer()));
-})
-
-DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, {
- TRY_TO(TraverseDeclaratorHelper(D));
- if (D->isBitField())
- TRY_TO(TraverseStmt(D->getBitWidth()));
- // FIXME: implement the rest.
-})
-
-DEF_TRAVERSE_DECL(ObjCIvarDecl, {
- TRY_TO(TraverseDeclaratorHelper(D));
- if (D->isBitField())
- TRY_TO(TraverseStmt(D->getBitWidth()));
- // FIXME: implement the rest.
-})
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
- TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
-
- // If we're an explicit template specialization, iterate over the
- // template args that were explicitly specified. If we were doing
- // this in typing order, we'd do it between the return type and
- // the function args, but both are handled by the FunctionTypeLoc
- // above, so we have to choose one side. I've decided to do before.
- if (const FunctionTemplateSpecializationInfo *FTSI =
- D->getTemplateSpecializationInfo()) {
- if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared &&
- FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
- // A specialization might not have explicit template arguments if it has
- // a templated return type and concrete arguments.
- if (const ASTTemplateArgumentListInfo *TALI =
- FTSI->TemplateArgumentsAsWritten) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(),
- TALI->NumTemplateArgs));
- }
- }
- }
-
- // Visit the function type itself, which can be either
- // FunctionNoProtoType or FunctionProtoType, or a typedef. This
- // also covers the return type and the function parameters,
- // including exception specifications.
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
-
- if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
- // Constructor initializers.
- for (auto *I : Ctor->inits()) {
- TRY_TO(TraverseConstructorInitializer(I));
- }
- }
-
- if (D->isThisDeclarationADefinition()) {
- TRY_TO(TraverseStmt(D->getBody())); // Function body.
- }
- return true;
-}
-
-DEF_TRAVERSE_DECL(FunctionDecl, {
- // We skip decls_begin/decls_end, which are already covered by
- // TraverseFunctionHelper().
- return TraverseFunctionHelper(D);
-})
-
-DEF_TRAVERSE_DECL(CXXMethodDecl, {
- // We skip decls_begin/decls_end, which are already covered by
- // TraverseFunctionHelper().
- return TraverseFunctionHelper(D);
-})
-
-DEF_TRAVERSE_DECL(CXXConstructorDecl, {
- // We skip decls_begin/decls_end, which are already covered by
- // TraverseFunctionHelper().
- return TraverseFunctionHelper(D);
-})
-
-// CXXConversionDecl is the declaration of a type conversion operator.
-// It's not a cast expression.
-DEF_TRAVERSE_DECL(CXXConversionDecl, {
- // We skip decls_begin/decls_end, which are already covered by
- // TraverseFunctionHelper().
- return TraverseFunctionHelper(D);
-})
-
-DEF_TRAVERSE_DECL(CXXDestructorDecl, {
- // We skip decls_begin/decls_end, which are already covered by
- // TraverseFunctionHelper().
- return TraverseFunctionHelper(D);
-})
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
- TRY_TO(TraverseDeclaratorHelper(D));
- // Default params are taken care of when we traverse the ParmVarDecl.
- if (!isa<ParmVarDecl>(D))
- TRY_TO(TraverseStmt(D->getInit()));
- return true;
-}
-
-DEF_TRAVERSE_DECL(VarDecl, { TRY_TO(TraverseVarHelper(D)); })
-
-DEF_TRAVERSE_DECL(VarTemplateSpecializationDecl, {
- // For implicit instantiations, we don't want to
- // recurse at all, since the instatiated class isn't written in
- // the source code anywhere.
- if (TypeSourceInfo *TSI = D->getTypeAsWritten())
- TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-
- if (!getDerived().shouldVisitTemplateInstantiations() &&
- D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
- // Returning from here skips traversing the
- // declaration context of the VarTemplateSpecializationDecl
- // (embedded in the DEF_TRAVERSE_DECL() macro).
- return true;
-})
-
-DEF_TRAVERSE_DECL(VarTemplatePartialSpecializationDecl, {
- // The partial specialization.
- if (TemplateParameterList *TPL = D->getTemplateParameters()) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
- }
- }
- // The args that remains unspecialized.
- TRY_TO(TraverseTemplateArgumentLocsHelper(
- D->getTemplateArgsAsWritten()->getTemplateArgs(),
- D->getTemplateArgsAsWritten()->NumTemplateArgs));
-
- // Don't need the VarTemplatePartialSpecializationHelper, even
- // though that's our parent class -- we already visit all the
- // template args here.
- TRY_TO(TraverseVarHelper(D));
-
- // Instantiations will have been visited with the primary
- // template.
-})
-
-DEF_TRAVERSE_DECL(ImplicitParamDecl, { TRY_TO(TraverseVarHelper(D)); })
-
-DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
- // A non-type template parameter, e.g. "S" in template<int S> class Foo ...
- TRY_TO(TraverseDeclaratorHelper(D));
- TRY_TO(TraverseStmt(D->getDefaultArgument()));
-})
-
-DEF_TRAVERSE_DECL(ParmVarDecl, {
- TRY_TO(TraverseVarHelper(D));
-
- if (D->hasDefaultArg() && D->hasUninstantiatedDefaultArg() &&
- !D->hasUnparsedDefaultArg())
- TRY_TO(TraverseStmt(D->getUninstantiatedDefaultArg()));
-
- if (D->hasDefaultArg() && !D->hasUninstantiatedDefaultArg() &&
- !D->hasUnparsedDefaultArg())
- TRY_TO(TraverseStmt(D->getDefaultArg()));
-})
-
-#undef DEF_TRAVERSE_DECL
-
-// ----------------- Stmt traversal -----------------
-//
-// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating
-// over the children defined in children() (every stmt defines these,
-// though sometimes the range is empty). Each individual Traverse*
-// method only needs to worry about children other than those. To see
-// what children() does for a given class, see, e.g.,
-// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html
-
-// This macro makes available a variable S, the passed-in stmt.
-#define DEF_TRAVERSE_STMT(STMT, CODE) \
- template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##STMT(STMT *S) { \
- TRY_TO(WalkUpFrom##STMT(S)); \
- StmtQueueAction StmtQueue(*this); \
- { CODE; } \
- for (Stmt *SubStmt : S->children()) { \
- StmtQueue.queue(SubStmt); \
- } \
- return true; \
- }
-
-DEF_TRAVERSE_STMT(GCCAsmStmt, {
- StmtQueue.queue(S->getAsmString());
- for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
- StmtQueue.queue(S->getInputConstraintLiteral(I));
- }
- for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
- StmtQueue.queue(S->getOutputConstraintLiteral(I));
- }
- for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- StmtQueue.queue(S->getClobberStringLiteral(I));
- }
- // children() iterates over inputExpr and outputExpr.
-})
-
-DEF_TRAVERSE_STMT(
- MSAsmStmt,
- {// FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc. Once
- // added this needs to be implemented.
- })
-
-DEF_TRAVERSE_STMT(CXXCatchStmt, {
- TRY_TO(TraverseDecl(S->getExceptionDecl()));
- // children() iterates over the handler block.
-})
-
-DEF_TRAVERSE_STMT(DeclStmt, {
- for (auto *I : S->decls()) {
- TRY_TO(TraverseDecl(I));
- }
- // Suppress the default iteration over children() by
- // returning. Here's why: A DeclStmt looks like 'type var [=
- // initializer]'. The decls above already traverse over the
- // initializers, so we don't have to do it again (which
- // children() would do).
- return true;
-})
-
-// These non-expr stmts (most of them), do not need any action except
-// iterating over the children.
-DEF_TRAVERSE_STMT(BreakStmt, {})
-DEF_TRAVERSE_STMT(CXXTryStmt, {})
-DEF_TRAVERSE_STMT(CaseStmt, {})
-DEF_TRAVERSE_STMT(CompoundStmt, {})
-DEF_TRAVERSE_STMT(ContinueStmt, {})
-DEF_TRAVERSE_STMT(DefaultStmt, {})
-DEF_TRAVERSE_STMT(DoStmt, {})
-DEF_TRAVERSE_STMT(ForStmt, {})
-DEF_TRAVERSE_STMT(GotoStmt, {})
-DEF_TRAVERSE_STMT(IfStmt, {})
-DEF_TRAVERSE_STMT(IndirectGotoStmt, {})
-DEF_TRAVERSE_STMT(LabelStmt, {})
-DEF_TRAVERSE_STMT(AttributedStmt, {})
-DEF_TRAVERSE_STMT(NullStmt, {})
-DEF_TRAVERSE_STMT(ObjCAtCatchStmt, {})
-DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, {})
-DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, {})
-DEF_TRAVERSE_STMT(ObjCAtThrowStmt, {})
-DEF_TRAVERSE_STMT(ObjCAtTryStmt, {})
-DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {})
-DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {})
-DEF_TRAVERSE_STMT(CXXForRangeStmt, {})
-DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
-})
-DEF_TRAVERSE_STMT(ReturnStmt, {})
-DEF_TRAVERSE_STMT(SwitchStmt, {})
-DEF_TRAVERSE_STMT(WhileStmt, {})
-
-DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
- if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
- S->getNumTemplateArgs()));
- }
-})
-
-DEF_TRAVERSE_STMT(DeclRefExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
- S->getNumTemplateArgs()));
-})
-
-DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
- if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(
- S->getExplicitTemplateArgs().getTemplateArgs(),
- S->getNumTemplateArgs()));
- }
-})
-
-DEF_TRAVERSE_STMT(MemberExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
- S->getNumTemplateArgs()));
-})
-
-DEF_TRAVERSE_STMT(
- ImplicitCastExpr,
- {// We don't traverse the cast type, as it's not written in the
- // source code.
- })
-
-DEF_TRAVERSE_STMT(CStyleCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXConstCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXDynamicCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-
-// InitListExpr is a tricky one, because we want to do all our work on
-// the syntactic form of the listexpr, but this method takes the
-// semantic form by default. We can't use the macro helper because it
-// calls WalkUp*() on the semantic form, before our code can convert
-// to the syntactic form.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
- if (InitListExpr *Syn = S->getSyntacticForm())
- S = Syn;
- TRY_TO(WalkUpFromInitListExpr(S));
- StmtQueueAction StmtQueue(*this);
- // All we need are the default actions. FIXME: use a helper function.
- for (Stmt *SubStmt : S->children()) {
- StmtQueue.queue(SubStmt);
- }
- return true;
-}
-
-// GenericSelectionExpr is a special case because the types and expressions
-// are interleaved. We also need to watch out for null types (default
-// generic associations).
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseGenericSelectionExpr(
- GenericSelectionExpr *S) {
- TRY_TO(WalkUpFromGenericSelectionExpr(S));
- StmtQueueAction StmtQueue(*this);
- StmtQueue.queue(S->getControllingExpr());
- for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
- if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
- TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
- StmtQueue.queue(S->getAssocExpr(i));
- }
- return true;
-}
-
-// PseudoObjectExpr is a special case because of the wierdness with
-// syntactic expressions and opaque values.
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraversePseudoObjectExpr(PseudoObjectExpr *S) {
- TRY_TO(WalkUpFromPseudoObjectExpr(S));
- StmtQueueAction StmtQueue(*this);
- StmtQueue.queue(S->getSyntacticForm());
- for (PseudoObjectExpr::semantics_iterator i = S->semantics_begin(),
- e = S->semantics_end();
- i != e; ++i) {
- Expr *sub = *i;
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
- sub = OVE->getSourceExpr();
- StmtQueue.queue(sub);
- }
- return true;
-}
-
-DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
- // This is called for code like 'return T()' where T is a built-in
- // (i.e. non-class) type.
- TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXNewExpr, {
- // The child-iterator will pick up the other arguments.
- TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(OffsetOfExpr, {
- // The child-iterator will pick up the expression representing
- // the field.
- // FIMXE: for code like offsetof(Foo, a.b.c), should we get
- // making a MemberExpr callbacks for Foo.a, Foo.a.b, and Foo.a.b.c?
- TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, {
- // The child-iterator will pick up the arg if it's an expression,
- // but not if it's a type.
- if (S->isArgumentType())
- TRY_TO(TraverseTypeLoc(S->getArgumentTypeInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXTypeidExpr, {
- // The child-iterator will pick up the arg if it's an expression,
- // but not if it's a type.
- if (S->isTypeOperand())
- TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(MSPropertyRefExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXUuidofExpr, {
- // The child-iterator will pick up the arg if it's an expression,
- // but not if it's a type.
- if (S->isTypeOperand())
- TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(TypeTraitExpr, {
- for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
- TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
- TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(ExpressionTraitExpr,
- { StmtQueue.queue(S->getQueriedExpression()); })
-
-DEF_TRAVERSE_STMT(VAArgExpr, {
- // The child-iterator will pick up the expression argument.
- TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
-})
-
-DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
- // This is called for code like 'return T()' where T is a class type.
- TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
-})
-
-// Walk only the visible parts of lambda expressions.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
- TRY_TO(WalkUpFromLambdaExpr(S));
-
- for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
- CEnd = S->explicit_capture_end();
- C != CEnd; ++C) {
- TRY_TO(TraverseLambdaCapture(S, C));
- }
-
- TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
-
- if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
- // Visit the whole type.
- TRY_TO(TraverseTypeLoc(TL));
- } else {
- if (S->hasExplicitParameters()) {
- // Visit parameters.
- for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
- TRY_TO(TraverseDecl(Proto.getParam(I)));
- }
- } else if (S->hasExplicitResultType()) {
- TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
- }
-
- auto *T = Proto.getTypePtr();
- for (const auto &E : T->exceptions()) {
- TRY_TO(TraverseType(E));
- }
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
- }
-
- TRY_TO(TraverseLambdaBody(S));
- return true;
-}
-
-DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
- // This is called for code like 'T()', where T is a template argument.
- TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
-})
-
-// These expressions all might take explicit template arguments.
-// We traverse those if so. FIXME: implement these.
-DEF_TRAVERSE_STMT(CXXConstructExpr, {})
-DEF_TRAVERSE_STMT(CallExpr, {})
-DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
-
-// These exprs (most of them), do not need any action except iterating
-// over the children.
-DEF_TRAVERSE_STMT(AddrLabelExpr, {})
-DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
-DEF_TRAVERSE_STMT(OMPArraySectionExpr, {})
-DEF_TRAVERSE_STMT(BlockExpr, {
- TRY_TO(TraverseDecl(S->getBlockDecl()));
- return true; // no child statements to loop through.
-})
-DEF_TRAVERSE_STMT(ChooseExpr, {})
-DEF_TRAVERSE_STMT(CompoundLiteralExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
-})
-DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, {})
-DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, {})
-DEF_TRAVERSE_STMT(CXXDefaultArgExpr, {})
-DEF_TRAVERSE_STMT(CXXDefaultInitExpr, {})
-DEF_TRAVERSE_STMT(CXXDeleteExpr, {})
-DEF_TRAVERSE_STMT(ExprWithCleanups, {})
-DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, {})
-DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, {})
-DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
- TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
- if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo())
- TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc()));
-})
-DEF_TRAVERSE_STMT(CXXThisExpr, {})
-DEF_TRAVERSE_STMT(CXXThrowExpr, {})
-DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
-DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
-DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
-DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
-DEF_TRAVERSE_STMT(GNUNullExpr, {})
-DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
-DEF_TRAVERSE_STMT(NoInitExpr, {})
-DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
-DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
- if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
- TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
-})
-DEF_TRAVERSE_STMT(ObjCIsaExpr, {})
-DEF_TRAVERSE_STMT(ObjCIvarRefExpr, {})
-DEF_TRAVERSE_STMT(ObjCMessageExpr, {
- if (TypeSourceInfo *TInfo = S->getClassReceiverTypeInfo())
- TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
-})
-DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, {})
-DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, {})
-DEF_TRAVERSE_STMT(ObjCProtocolExpr, {})
-DEF_TRAVERSE_STMT(ObjCSelectorExpr, {})
-DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, {})
-DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
- TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
-})
-DEF_TRAVERSE_STMT(ParenExpr, {})
-DEF_TRAVERSE_STMT(ParenListExpr, {})
-DEF_TRAVERSE_STMT(PredefinedExpr, {})
-DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
-DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
-DEF_TRAVERSE_STMT(StmtExpr, {})
-DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
- S->getNumTemplateArgs()));
- }
-})
-
-DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
- TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
- if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
- S->getNumTemplateArgs()));
- }
-})
-
-DEF_TRAVERSE_STMT(SEHTryStmt, {})
-DEF_TRAVERSE_STMT(SEHExceptStmt, {})
-DEF_TRAVERSE_STMT(SEHFinallyStmt, {})
-DEF_TRAVERSE_STMT(SEHLeaveStmt, {})
-DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
-
-DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
-DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
-DEF_TRAVERSE_STMT(TypoExpr, {})
-DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
-
-// These operators (all of them) do not need any action except
-// iterating over the children.
-DEF_TRAVERSE_STMT(BinaryConditionalOperator, {})
-DEF_TRAVERSE_STMT(ConditionalOperator, {})
-DEF_TRAVERSE_STMT(UnaryOperator, {})
-DEF_TRAVERSE_STMT(BinaryOperator, {})
-DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
-DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
-DEF_TRAVERSE_STMT(PackExpansionExpr, {})
-DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
-DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
-DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
-DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
-DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
-DEF_TRAVERSE_STMT(CXXFoldExpr, {})
-DEF_TRAVERSE_STMT(AtomicExpr, {})
-
-// Coroutine support.
-DEF_TRAVERSE_STMT(CoroutineBodyStmt, {})
-DEF_TRAVERSE_STMT(CoreturnStmt, {})
-DEF_TRAVERSE_STMT(CoawaitExpr, {})
-DEF_TRAVERSE_STMT(CoyieldExpr, {})
-
-// These literals (all of them) do not need any action.
-DEF_TRAVERSE_STMT(IntegerLiteral, {})
-DEF_TRAVERSE_STMT(CharacterLiteral, {})
-DEF_TRAVERSE_STMT(FloatingLiteral, {})
-DEF_TRAVERSE_STMT(ImaginaryLiteral, {})
-DEF_TRAVERSE_STMT(StringLiteral, {})
-DEF_TRAVERSE_STMT(ObjCStringLiteral, {})
-DEF_TRAVERSE_STMT(ObjCBoxedExpr, {})
-DEF_TRAVERSE_STMT(ObjCArrayLiteral, {})
-DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, {})
-
-// Traverse OpenCL: AsType, Convert.
-DEF_TRAVERSE_STMT(AsTypeExpr, {})
-
-// OpenMP directives.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective(
- OMPExecutableDirective *S) {
- for (auto *C : S->clauses()) {
- TRY_TO(TraverseOMPClause(C));
- }
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) {
- return TraverseOMPExecutableDirective(S);
-}
-
-DEF_TRAVERSE_STMT(OMPParallelDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPSimdDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPForDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPForSimdDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPSectionsDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPSectionDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPSingleDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPMasterDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPCriticalDirective, {
- TRY_TO(TraverseDeclarationNameInfo(S->getDirectiveName()));
- TRY_TO(TraverseOMPExecutableDirective(S));
-})
-
-DEF_TRAVERSE_STMT(OMPParallelForDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPParallelForSimdDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPParallelSectionsDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTaskDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTaskyieldDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPBarrierDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTaskgroupDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPCancellationPointDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPCancelDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPFlushDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPOrderedDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPAtomicDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTargetDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTargetDataDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-DEF_TRAVERSE_STMT(OMPTeamsDirective,
- { TRY_TO(TraverseOMPExecutableDirective(S)); })
-
-// OpenMP clauses.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
- if (!C)
- return true;
- switch (C->getClauseKind()) {
-#define OPENMP_CLAUSE(Name, Class) \
- case OMPC_##Name: \
- TRY_TO(Visit##Class(static_cast<Class *>(C))); \
- break;
-#include "clang/Basic/OpenMPKinds.def"
- case OMPC_threadprivate:
- case OMPC_unknown:
- break;
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) {
- TRY_TO(TraverseStmt(C->getCondition()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
- TRY_TO(TraverseStmt(C->getCondition()));
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
- TRY_TO(TraverseStmt(C->getNumThreads()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) {
- TRY_TO(TraverseStmt(C->getSafelen()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPSimdlenClause(OMPSimdlenClause *C) {
- TRY_TO(TraverseStmt(C->getSimdlen()));
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
- TRY_TO(TraverseStmt(C->getNumForLoops()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) {
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
- TRY_TO(TraverseStmt(C->getChunkSize()));
- TRY_TO(TraverseStmt(C->getHelperChunkSize()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) {
- TRY_TO(TraverseStmt(C->getNumForLoops()));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPNowaitClause(OMPNowaitClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPUntiedClause(OMPUntiedClause *) {
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) {
- return true;
-}
-
-template <typename Derived>
-template <typename T>
-bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
- for (auto *E : Node->varlists()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->private_copies()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
- OMPFirstprivateClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->private_copies()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->inits()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
- OMPLastprivateClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->private_copies()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->source_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->destination_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->assignment_ops()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
- TRY_TO(TraverseStmt(C->getStep()));
- TRY_TO(TraverseStmt(C->getCalcStep()));
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->privates()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->inits()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->updates()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->finals()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPAlignedClause(OMPAlignedClause *C) {
- TRY_TO(TraverseStmt(C->getAlignment()));
- TRY_TO(VisitOMPClauseList(C));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->source_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->destination_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->assignment_ops()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
- OMPCopyprivateClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->source_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->destination_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->assignment_ops()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
- TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
- TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
- TRY_TO(VisitOMPClauseList(C));
- for (auto *E : C->privates()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->lhs_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->rhs_exprs()) {
- TRY_TO(TraverseStmt(E));
- }
- for (auto *E : C->reduction_ops()) {
- TRY_TO(TraverseStmt(E));
- }
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) {
- TRY_TO(VisitOMPClauseList(C));
- return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) {
- TRY_TO(TraverseStmt(C->getDevice()));
- return true;
-}
-
-// FIXME: look at the following tricky-seeming exprs to see if we
-// need to recurse on anything. These are ones that have methods
-// returning decls or qualtypes or nestednamespecifier -- though I'm
-// not sure if they own them -- or just seemed very complicated, or
-// had lots of sub-types to explore.
-//
-// VisitOverloadExpr and its children: recurse on template args? etc?
-
-// FIXME: go through all the stmts and exprs again, and see which of them
-// create new types, and recurse on the types (TypeLocs?) of those.
-// Candidates:
-//
-// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html
-// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html
-// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html
-// Every class that has getQualifier.
-
-#undef DEF_TRAVERSE_STMT
-
-#undef TRY_TO
-
-#undef RecursiveASTVisitor
-
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIBCLANG_RECURSIVEASTVISITOR_H
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 434b456..29b19f2 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -21,6 +21,7 @@
#include "clang/AST/Redeclarable.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Linkage.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
@@ -38,7 +39,6 @@
class FunctionTemplateSpecializationInfo;
class LabelStmt;
class MemberSpecializationInfo;
-class Module;
class NestedNameSpecifier;
class ParmVarDecl;
class Stmt;
@@ -319,7 +319,8 @@
NamedDecl *getUnderlyingDecl() {
// Fast-path the common case.
if (this->getKind() != UsingShadow &&
- this->getKind() != ObjCCompatibleAlias)
+ this->getKind() != ObjCCompatibleAlias &&
+ this->getKind() != NamespaceAlias)
return this;
return getUnderlyingDeclImpl();
@@ -463,25 +464,15 @@
}
/// \brief Get the original (first) namespace declaration.
- NamespaceDecl *getOriginalNamespace() {
- if (isFirstDecl())
- return this;
-
- return AnonOrFirstNamespaceAndInline.getPointer();
- }
+ NamespaceDecl *getOriginalNamespace();
/// \brief Get the original (first) namespace declaration.
- const NamespaceDecl *getOriginalNamespace() const {
- if (isFirstDecl())
- return this;
-
- return AnonOrFirstNamespaceAndInline.getPointer();
- }
+ const NamespaceDecl *getOriginalNamespace() const;
/// \brief Return true if this declaration is an original (first) declaration
/// of the namespace. This is false for non-original (subsequent) namespace
/// declarations and anonymous namespaces.
- bool isOriginalNamespace() const { return isFirstDecl(); }
+ bool isOriginalNamespace() const;
/// \brief Retrieve the anonymous namespace nested inside this namespace,
/// if any.
@@ -728,17 +719,14 @@
};
protected:
- /// \brief Placeholder type used in Init to denote an unparsed C++ default
- /// argument.
- struct UnparsedDefaultArgument;
-
- /// \brief Placeholder type used in Init to denote an uninstantiated C++
- /// default argument.
- struct UninstantiatedDefaultArgument;
-
- typedef llvm::PointerUnion4<Stmt *, EvaluatedStmt *,
- UnparsedDefaultArgument *,
- UninstantiatedDefaultArgument *> InitType;
+ // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we
+ // have allocated the auxilliary struct of information there.
+ //
+ // TODO: It is a bit unfortunate to use a PointerUnion inside the VarDecl for
+ // this as *many* VarDecls are ParmVarDecls that don't have default
+ // arguments. We could save some space by moving this pointer union to be
+ // allocated in trailing space when necessary.
+ typedef llvm::PointerUnion<Stmt *, EvaluatedStmt *> InitType;
/// \brief The initializer for this variable or, for a ParmVarDecl, the
/// C++ default argument.
@@ -762,6 +750,13 @@
protected:
enum { NumParameterIndexBits = 8 };
+ enum DefaultArgKind {
+ DAK_None,
+ DAK_Unparsed,
+ DAK_Uninstantiated,
+ DAK_Normal
+ };
+
class ParmVarDeclBitfields {
friend class ParmVarDecl;
friend class ASTDeclReader;
@@ -772,6 +767,12 @@
/// prior declaration.
unsigned HasInheritedDefaultArg : 1;
+ /// Describes the kind of default argument for this parameter. By default
+ /// this is none. If this is normal, then the default argument is stored in
+ /// the \c VarDecl initalizer expression unless we were unble to parse
+ /// (even an invalid) expression for the default argument.
+ unsigned DefaultArgKind : 2;
+
/// Whether this parameter undergoes K&R argument promotion.
unsigned IsKNRPromoted : 1;
@@ -1065,47 +1066,14 @@
/// declaration it is attached to. Also get that declaration.
const Expr *getAnyInitializer(const VarDecl *&D) const;
- bool hasInit() const {
- return !Init.isNull() && (Init.is<Stmt *>() || Init.is<EvaluatedStmt *>());
- }
+ bool hasInit() const;
const Expr *getInit() const {
- if (Init.isNull())
- return nullptr;
-
- const Stmt *S = Init.dyn_cast<Stmt *>();
- if (!S) {
- if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
- S = ES->Value;
- }
- return (const Expr*) S;
+ return const_cast<VarDecl *>(this)->getInit();
}
- Expr *getInit() {
- if (Init.isNull())
- return nullptr;
-
- Stmt *S = Init.dyn_cast<Stmt *>();
- if (!S) {
- if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
- S = ES->Value;
- }
-
- return (Expr*) S;
- }
+ Expr *getInit();
/// \brief Retrieve the address of the initializer expression.
- Stmt **getInitAddress() {
- if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
- return &ES->Value;
-
- // This union hack tip-toes around strict-aliasing rules.
- union {
- InitType *InitPtr;
- Stmt **StmtPtr;
- };
-
- InitPtr = &Init;
- return StmtPtr;
- }
+ Stmt **getInitAddress();
void setInit(Expr *I);
@@ -1127,33 +1095,18 @@
/// \brief Return the already-evaluated value of this variable's
/// initializer, or NULL if the value is not yet known. Returns pointer
/// to untyped APValue if the value could not be evaluated.
- APValue *getEvaluatedValue() const {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
- if (Eval->WasEvaluated)
- return &Eval->Evaluated;
-
- return nullptr;
- }
+ APValue *getEvaluatedValue() const;
/// \brief Determines whether it is already known whether the
/// initializer is an integral constant expression or not.
- bool isInitKnownICE() const {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
- return Eval->CheckedICE;
-
- return false;
- }
+ bool isInitKnownICE() const;
/// \brief Determines whether the initializer is an integral constant
/// expression, or in C++11, whether the initializer is a constant
/// expression.
///
/// \pre isInitKnownICE()
- bool isInitICE() const {
- assert(isInitKnownICE() &&
- "Check whether we already know that the initializer is an ICE");
- return Init.get<EvaluatedStmt *>()->IsICE;
- }
+ bool isInitICE() const;
/// \brief Determine whether the value of the initializer attached to this
/// declaration is an integral constant expression.
@@ -1354,6 +1307,7 @@
TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
: VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) {
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
+ assert(ParmVarDeclBits.DefaultArgKind == DAK_None);
assert(ParmVarDeclBits.IsKNRPromoted == false);
assert(ParmVarDeclBits.IsObjCMethodParam == false);
setDefaultArg(DefArg);
@@ -1428,29 +1382,20 @@
return const_cast<ParmVarDecl *>(this)->getDefaultArg();
}
- void setDefaultArg(Expr *defarg) {
- Init = reinterpret_cast<Stmt *>(defarg);
- }
+ void setDefaultArg(Expr *defarg);
/// \brief Retrieve the source range that covers the entire default
/// argument.
SourceRange getDefaultArgRange() const;
- void setUninstantiatedDefaultArg(Expr *arg) {
- Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg);
- }
- Expr *getUninstantiatedDefaultArg() {
- return (Expr *)Init.get<UninstantiatedDefaultArgument *>();
- }
+ void setUninstantiatedDefaultArg(Expr *arg);
+ Expr *getUninstantiatedDefaultArg();
const Expr *getUninstantiatedDefaultArg() const {
- return (const Expr *)Init.get<UninstantiatedDefaultArgument *>();
+ return const_cast<ParmVarDecl *>(this)->getUninstantiatedDefaultArg();
}
/// hasDefaultArg - Determines whether this parameter has a default argument,
/// either parsed or not.
- bool hasDefaultArg() const {
- return getInit() || hasUnparsedDefaultArg() ||
- hasUninstantiatedDefaultArg();
- }
+ bool hasDefaultArg() const;
/// hasUnparsedDefaultArg - Determines whether this parameter has a
/// default argument that has not yet been parsed. This will occur
@@ -1463,11 +1408,11 @@
/// }; // x has a regular default argument now
/// @endcode
bool hasUnparsedDefaultArg() const {
- return Init.is<UnparsedDefaultArgument*>();
+ return ParmVarDeclBits.DefaultArgKind == DAK_Unparsed;
}
bool hasUninstantiatedDefaultArg() const {
- return Init.is<UninstantiatedDefaultArgument*>();
+ return ParmVarDeclBits.DefaultArgKind == DAK_Uninstantiated;
}
/// setUnparsedDefaultArg - Specify that this parameter has an
@@ -1475,7 +1420,9 @@
/// real default argument via setDefaultArg when the class
/// definition enclosing the function declaration that owns this
/// default argument is completed.
- void setUnparsedDefaultArg() { Init = (UnparsedDefaultArgument *)nullptr; }
+ void setUnparsedDefaultArg() {
+ ParmVarDeclBits.DefaultArgKind = DAK_Unparsed;
+ }
bool hasInheritedDefaultArg() const {
return ParmVarDeclBits.HasInheritedDefaultArg;
@@ -1558,25 +1505,25 @@
LazyDeclStmtPtr Body;
- // FIXME: This can be packed into the bitfields in Decl.
- // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
+ // FIXME: This can be packed into the bitfields in DeclContext.
+ // NOTE: VC++ packs bitfields poorly if the types differ.
unsigned SClass : 2;
- bool IsInline : 1;
- bool IsInlineSpecified : 1;
- bool IsVirtualAsWritten : 1;
- bool IsPure : 1;
- bool HasInheritedPrototype : 1;
- bool HasWrittenPrototype : 1;
- bool IsDeleted : 1;
- bool IsTrivial : 1; // sunk from CXXMethodDecl
- bool IsDefaulted : 1; // sunk from CXXMethoDecl
- bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
- bool HasImplicitReturnZero : 1;
- bool IsLateTemplateParsed : 1;
- bool IsConstexpr : 1;
+ unsigned IsInline : 1;
+ unsigned IsInlineSpecified : 1;
+ unsigned IsVirtualAsWritten : 1;
+ unsigned IsPure : 1;
+ unsigned HasInheritedPrototype : 1;
+ unsigned HasWrittenPrototype : 1;
+ unsigned IsDeleted : 1;
+ unsigned IsTrivial : 1; // sunk from CXXMethodDecl
+ unsigned IsDefaulted : 1; // sunk from CXXMethoDecl
+ unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
+ unsigned HasImplicitReturnZero : 1;
+ unsigned IsLateTemplateParsed : 1;
+ unsigned IsConstexpr : 1;
/// \brief Indicates if the function uses __try.
- bool UsesSEHTry : 1;
+ unsigned UsesSEHTry : 1;
/// \brief Indicates if the function was a definition but its body was
/// skipped.
@@ -2007,6 +1954,7 @@
unsigned getMinRequiredArguments() const;
QualType getReturnType() const {
+ assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
return getType()->getAs<FunctionType>()->getReturnType();
}
@@ -2017,6 +1965,7 @@
/// \brief Determine the type of an expression that calls this function.
QualType getCallResultType() const {
+ assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
}
@@ -2096,9 +2045,7 @@
/// \brief If this function is an instantiation of a member function of a
/// class template specialization, retrieves the member specialization
/// information.
- MemberSpecializationInfo *getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
- }
+ MemberSpecializationInfo *getMemberSpecializationInfo() const;
/// \brief Specify that this record is an instantiation of the
/// member function FD.
@@ -2119,13 +2066,9 @@
/// FunctionDecl that describes the function template,
/// getDescribedFunctionTemplate() retrieves the
/// FunctionTemplateDecl from a FunctionDecl.
- FunctionTemplateDecl *getDescribedFunctionTemplate() const {
- return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>();
- }
+ FunctionTemplateDecl *getDescribedFunctionTemplate() const;
- void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
- TemplateOrSpecialization = Template;
- }
+ void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
/// \brief Determine whether this function is a function template
/// specialization.
@@ -2140,10 +2083,7 @@
/// \brief If this function is actually a function template specialization,
/// retrieve information about this function template specialization.
/// Otherwise, returns NULL.
- FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const {
- return TemplateOrSpecialization.
- dyn_cast<FunctionTemplateSpecializationInfo*>();
- }
+ FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const;
/// \brief Determines whether this function is a function template
/// specialization or a member of a class template specialization that can
@@ -2220,10 +2160,7 @@
const TemplateArgumentListInfo &TemplateArgs);
DependentFunctionTemplateSpecializationInfo *
- getDependentSpecializationInfo() const {
- return TemplateOrSpecialization.
- dyn_cast<DependentFunctionTemplateSpecializationInfo*>();
- }
+ getDependentSpecializationInfo() const;
/// \brief Determine what kind of template instantiation this function
/// represents.
@@ -2505,10 +2442,9 @@
NamedDecl **Chaining;
unsigned ChainingSize;
- IndirectFieldDecl(DeclContext *DC, SourceLocation L,
+ IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName N, QualType T,
- NamedDecl **CH, unsigned CHS)
- : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {}
+ NamedDecl **CH, unsigned CHS);
public:
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
@@ -3284,9 +3220,6 @@
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
- bool hasLoadedFieldsFromExternalStorage() const { return LoadedFieldsFromExternalStorage; }
- void setHasLoadedFieldsFromExternalStorage(bool V) { LoadedFieldsFromExternalStorage = V; }
-
/// isAnonymousStructOrUnion - Whether this is an anonymous struct
/// or union. To be an anonymous struct or union, it must have been
/// declared without a name and there must be no objects of this
@@ -3309,7 +3242,14 @@
bool hasVolatileMember() const { return HasVolatileMember; }
void setHasVolatileMember (bool val) { HasVolatileMember = val; }
-
+
+ bool hasLoadedFieldsFromExternalStorage() const {
+ return LoadedFieldsFromExternalStorage;
+ }
+ void setHasLoadedFieldsFromExternalStorage(bool val) {
+ LoadedFieldsFromExternalStorage = val;
+ }
+
/// \brief Determines whether this declaration represents the
/// injected class name.
///
@@ -3636,9 +3576,7 @@
/// \brief The body of the outlined function.
llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow;
- explicit CapturedDecl(DeclContext *DC, unsigned NumParams)
- : Decl(Captured, DC, SourceLocation()), DeclContext(Captured),
- NumParams(NumParams), ContextParam(0), BodyAndNothrow(nullptr, false) { }
+ explicit CapturedDecl(DeclContext *DC, unsigned NumParams);
ImplicitParamDecl *const *getParams() const {
return getTrailingObjects<ImplicitParamDecl *>();
@@ -3654,11 +3592,11 @@
static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumParams);
- Stmt *getBody() const override { return BodyAndNothrow.getPointer(); }
- void setBody(Stmt *B) { BodyAndNothrow.setPointer(B); }
+ Stmt *getBody() const override;
+ void setBody(Stmt *B);
- bool isNothrow() const { return BodyAndNothrow.getInt(); }
- void setNothrow(bool Nothrow = true) { BodyAndNothrow.setInt(Nothrow); }
+ bool isNothrow() const;
+ void setNothrow(bool Nothrow = true);
unsigned getNumParams() const { return NumParams; }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 9250a9d..184b92e 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -114,6 +114,9 @@
/// Tags, declared with 'struct foo;' and referenced with
/// 'struct foo'. All tags are also types. This is what
/// elaborated-type-specifiers look for in C.
+ /// This also contains names that conflict with tags in the
+ /// same scope but that are otherwise ordinary names (non-type
+ /// template parameters and indirect field declarations).
IDNS_Tag = 0x0002,
/// Types, declared with 'struct foo', typedefs, etc.
@@ -132,7 +135,7 @@
IDNS_Namespace = 0x0010,
/// Ordinary names. In C, everything that's not a label, tag,
- /// or member ends up here.
+ /// member, or function-local extern ends up here.
IDNS_Ordinary = 0x0020,
/// Objective C \@protocol.
@@ -161,7 +164,9 @@
/// This declaration is a function-local extern declaration of a
/// variable or function. This may also be IDNS_Ordinary if it
- /// has been declared outside any function.
+ /// has been declared outside any function. These act mostly like
+ /// invisible friend declarations, but are also visible to unqualified
+ /// lookup within the scope of the declaring function.
IDNS_LocalExtern = 0x0800
};
@@ -476,8 +481,7 @@
template <typename T>
llvm::iterator_range<specific_attr_iterator<T>> specific_attrs() const {
- return llvm::iterator_range<specific_attr_iterator<T>>(
- specific_attr_begin<T>(), specific_attr_end<T>());
+ return llvm::make_range(specific_attr_begin<T>(), specific_attr_end<T>());
}
template <typename T>
@@ -1147,6 +1151,11 @@
/// that are missing from the lookup table.
mutable bool HasLazyExternalLexicalLookups : 1;
+ /// \brief If \c true, lookups should only return identifier from
+ /// DeclContext scope (for example TranslationUnit). Used in
+ /// LookupQualifiedName()
+ mutable bool UseQualifiedLookup : 1;
+
/// \brief Pointer to the data structure used to lookup declarations
/// within this context (or a DependentStoredDeclsMap if this is a
/// dependent context). We maintain the invariant that, if the map
@@ -1181,6 +1190,7 @@
ExternalVisibleStorage(false),
NeedToReconcileExternalVisibleStorage(false),
HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
+ UseQualifiedLookup(false),
LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
public:
@@ -1761,6 +1771,16 @@
D == LastDecl);
}
+ bool setUseQualifiedLookup(bool use = true) {
+ bool old_value = UseQualifiedLookup;
+ UseQualifiedLookup = use;
+ return old_value;
+ }
+
+ bool shouldUseQualifiedLookup() const {
+ return UseQualifiedLookup;
+ }
+
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 1c54e1b..7c54901 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1344,9 +1344,7 @@
/// \brief If this class is an instantiation of a member class of a
/// class template specialization, retrieves the member specialization
/// information.
- MemberSpecializationInfo *getMemberSpecializationInfo() const {
- return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
- }
+ MemberSpecializationInfo *getMemberSpecializationInfo() const;
/// \brief Specify that this record is an instantiation of the
/// member class \p RD.
@@ -1364,13 +1362,9 @@
/// CXXRecordDecl that from a ClassTemplateDecl, while
/// getDescribedClassTemplate() retrieves the ClassTemplateDecl from
/// a CXXRecordDecl.
- ClassTemplateDecl *getDescribedClassTemplate() const {
- return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>();
- }
+ ClassTemplateDecl *getDescribedClassTemplate() const;
- void setDescribedClassTemplate(ClassTemplateDecl *Template) {
- TemplateOrInstantiation = Template;
- }
+ void setDescribedClassTemplate(ClassTemplateDecl *Template);
/// \brief Determine whether this particular class is a specialization or
/// instantiation of a class template or member class of a class template,
@@ -1888,7 +1882,8 @@
/// B(A& a) : A(a), f(3.14159) { }
/// };
/// \endcode
-class CXXCtorInitializer {
+class CXXCtorInitializer final
+ : private llvm::TrailingObjects<CXXCtorInitializer, VarDecl *> {
/// \brief Either the base class name/delegating constructor type (stored as
/// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
/// (IndirectFieldDecl*) being initialized.
@@ -2104,24 +2099,26 @@
/// describe an array member initialization.
VarDecl *getArrayIndex(unsigned I) {
assert(I < getNumArrayIndices() && "Out of bounds member array index");
- return reinterpret_cast<VarDecl **>(this + 1)[I];
+ return getTrailingObjects<VarDecl *>()[I];
}
const VarDecl *getArrayIndex(unsigned I) const {
assert(I < getNumArrayIndices() && "Out of bounds member array index");
- return reinterpret_cast<const VarDecl * const *>(this + 1)[I];
+ return getTrailingObjects<VarDecl *>()[I];
}
void setArrayIndex(unsigned I, VarDecl *Index) {
assert(I < getNumArrayIndices() && "Out of bounds member array index");
- reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
+ getTrailingObjects<VarDecl *>()[I] = Index;
}
ArrayRef<VarDecl *> getArrayIndexes() {
assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init");
- return llvm::makeArrayRef(reinterpret_cast<VarDecl **>(this + 1),
+ return llvm::makeArrayRef(getTrailingObjects<VarDecl *>(),
getNumArrayIndices());
}
/// \brief Get the initializer.
Expr *getInit() const { return static_cast<Expr*>(Init); }
+
+ friend TrailingObjects;
};
/// \brief Represents a C++ constructor within a class.
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 12b93b4..27b0388 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -37,7 +37,9 @@
/// @endcode
///
/// The semantic context of a friend decl is its declaring class.
-class FriendDecl : public Decl {
+class FriendDecl final
+ : public Decl,
+ private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
virtual void anchor();
public:
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
@@ -62,14 +64,6 @@
// template <class T> friend class A<T>::B;
unsigned NumTPLists : 31;
- // The tail-allocated friend type template parameter lists (if any).
- TemplateParameterList* const *getTPLists() const {
- return reinterpret_cast<TemplateParameterList* const *>(this + 1);
- }
- TemplateParameterList **getTPLists() {
- return reinterpret_cast<TemplateParameterList**>(this + 1);
- }
-
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
@@ -83,7 +77,7 @@
UnsupportedFriend(false),
NumTPLists(FriendTypeTPLists.size()) {
for (unsigned i = 0; i < NumTPLists; ++i)
- getTPLists()[i] = FriendTypeTPLists[i];
+ getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i];
}
FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
@@ -118,7 +112,7 @@
}
TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
assert(N < NumTPLists);
- return getTPLists()[N];
+ return getTrailingObjects<TemplateParameterList *>()[N];
}
/// If this friend declaration doesn't name a type, return the inner
@@ -148,9 +142,10 @@
return SourceRange(getFriendLoc(), ND->getLocEnd());
}
else if (TypeSourceInfo *TInfo = getFriendType()) {
- SourceLocation StartL = (NumTPLists == 0)
- ? getFriendLoc()
- : getTPLists()[0]->getTemplateLoc();
+ SourceLocation StartL =
+ (NumTPLists == 0) ? getFriendLoc()
+ : getTrailingObjects<TemplateParameterList *>()[0]
+ ->getTemplateLoc();
return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc());
}
else
@@ -171,6 +166,7 @@
friend class ASTDeclReader;
friend class ASTDeclWriter;
+ friend TrailingObjects;
};
/// An iterator over the friend declarations of a class.
diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h
index bd3dbd8..c84bb5e 100644
--- a/include/clang/AST/DeclGroup.h
+++ b/include/clang/AST/DeclGroup.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_DECLGROUP_H
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/TrailingObjects.h"
#include <cassert>
namespace clang {
@@ -24,13 +25,9 @@
class DeclGroup;
class DeclGroupIterator;
-class DeclGroup {
+class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> {
// FIXME: Include a TypeSpecifier object.
- union {
- unsigned NumDecls;
-
- Decl *Aligner;
- };
+ unsigned NumDecls;
private:
DeclGroup() : NumDecls(0) {}
@@ -43,13 +40,15 @@
Decl*& operator[](unsigned i) {
assert (i < NumDecls && "Out-of-bounds access.");
- return ((Decl**) (this+1))[i];
+ return getTrailingObjects<Decl *>()[i];
}
Decl* const& operator[](unsigned i) const {
assert (i < NumDecls && "Out-of-bounds access.");
- return ((Decl* const*) (this+1))[i];
+ return getTrailingObjects<Decl *>()[i];
}
+
+ friend TrailingObjects;
};
class DeclGroupRef {
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 833683f..f89717f 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -612,7 +612,8 @@
/// @interface NSArray<T> // stores the <T>
/// @end
/// \endcode
-class ObjCTypeParamList {
+class ObjCTypeParamList final
+ : private llvm::TrailingObjects<ObjCTypeParamList, ObjCTypeParamDecl *> {
/// Stores the components of a SourceRange as a POD.
struct PODSourceRange {
unsigned Begin;
@@ -644,7 +645,7 @@
/// Iterate through the type parameters in the list.
typedef ObjCTypeParamDecl **iterator;
- iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
+ iterator begin() { return getTrailingObjects<ObjCTypeParamDecl *>(); }
iterator end() { return begin() + size(); }
@@ -655,7 +656,7 @@
typedef ObjCTypeParamDecl * const *const_iterator;
const_iterator begin() const {
- return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
+ return getTrailingObjects<ObjCTypeParamDecl *>();
}
const_iterator end() const {
@@ -685,6 +686,217 @@
/// Gather the default set of type arguments to be substituted for
/// these type parameters when dealing with an unspecialized type.
void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const;
+ friend TrailingObjects;
+};
+
+enum class ObjCPropertyQueryKind : uint8_t {
+ OBJC_PR_query_unknown = 0x00,
+ OBJC_PR_query_instance,
+ OBJC_PR_query_class
+};
+
+/// \brief Represents one property declaration in an Objective-C interface.
+///
+/// For example:
+/// \code{.mm}
+/// \@property (assign, readwrite) int MyProperty;
+/// \endcode
+class ObjCPropertyDecl : public NamedDecl {
+ void anchor() override;
+public:
+ enum PropertyAttributeKind {
+ OBJC_PR_noattr = 0x00,
+ OBJC_PR_readonly = 0x01,
+ OBJC_PR_getter = 0x02,
+ OBJC_PR_assign = 0x04,
+ OBJC_PR_readwrite = 0x08,
+ OBJC_PR_retain = 0x10,
+ OBJC_PR_copy = 0x20,
+ OBJC_PR_nonatomic = 0x40,
+ OBJC_PR_setter = 0x80,
+ OBJC_PR_atomic = 0x100,
+ OBJC_PR_weak = 0x200,
+ OBJC_PR_strong = 0x400,
+ OBJC_PR_unsafe_unretained = 0x800,
+ /// Indicates that the nullability of the type was spelled with a
+ /// property attribute rather than a type qualifier.
+ OBJC_PR_nullability = 0x1000,
+ OBJC_PR_null_resettable = 0x2000,
+ OBJC_PR_class = 0x4000
+ // Adding a property should change NumPropertyAttrsBits
+ };
+
+ enum {
+ /// \brief Number of bits fitting all the property attributes.
+ NumPropertyAttrsBits = 15
+ };
+
+ enum SetterKind { Assign, Retain, Copy, Weak };
+ enum PropertyControl { None, Required, Optional };
+private:
+ SourceLocation AtLoc; // location of \@property
+ SourceLocation LParenLoc; // location of '(' starting attribute list or null.
+ QualType DeclType;
+ TypeSourceInfo *DeclTypeSourceInfo;
+ unsigned PropertyAttributes : NumPropertyAttrsBits;
+ unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
+ // \@required/\@optional
+ unsigned PropertyImplementation : 2;
+
+ Selector GetterName; // getter name of NULL if no getter
+ Selector SetterName; // setter name of NULL if no setter
+
+ ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
+ ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
+ ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property
+
+ ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ SourceLocation AtLocation, SourceLocation LParenLocation,
+ QualType T, TypeSourceInfo *TSI,
+ PropertyControl propControl)
+ : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
+ LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI),
+ PropertyAttributes(OBJC_PR_noattr),
+ PropertyAttributesAsWritten(OBJC_PR_noattr),
+ PropertyImplementation(propControl),
+ GetterName(Selector()),
+ SetterName(Selector()),
+ GetterMethodDecl(nullptr), SetterMethodDecl(nullptr),
+ PropertyIvarDecl(nullptr) {}
+
+public:
+ static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id, SourceLocation AtLocation,
+ SourceLocation LParenLocation,
+ QualType T,
+ TypeSourceInfo *TSI,
+ PropertyControl propControl = None);
+
+ static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+ void setAtLoc(SourceLocation L) { AtLoc = L; }
+
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+
+ TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; }
+
+ QualType getType() const { return DeclType; }
+
+ void setType(QualType T, TypeSourceInfo *TSI) {
+ DeclType = T;
+ DeclTypeSourceInfo = TSI;
+ }
+
+ /// Retrieve the type when this property is used with a specific base object
+ /// type.
+ QualType getUsageType(QualType objectType) const;
+
+ PropertyAttributeKind getPropertyAttributes() const {
+ return PropertyAttributeKind(PropertyAttributes);
+ }
+ void setPropertyAttributes(PropertyAttributeKind PRVal) {
+ PropertyAttributes |= PRVal;
+ }
+ void overwritePropertyAttributes(unsigned PRVal) {
+ PropertyAttributes = PRVal;
+ }
+
+ PropertyAttributeKind getPropertyAttributesAsWritten() const {
+ return PropertyAttributeKind(PropertyAttributesAsWritten);
+ }
+
+ void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
+ PropertyAttributesAsWritten = PRVal;
+ }
+
+ // Helper methods for accessing attributes.
+
+ /// isReadOnly - Return true iff the property has a setter.
+ bool isReadOnly() const {
+ return (PropertyAttributes & OBJC_PR_readonly);
+ }
+
+ /// isAtomic - Return true if the property is atomic.
+ bool isAtomic() const {
+ return (PropertyAttributes & OBJC_PR_atomic);
+ }
+
+ /// isRetaining - Return true if the property retains its value.
+ bool isRetaining() const {
+ return (PropertyAttributes &
+ (OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy));
+ }
+
+ bool isInstanceProperty() const { return !isClassProperty(); }
+ bool isClassProperty() const { return PropertyAttributes & OBJC_PR_class; }
+ ObjCPropertyQueryKind getQueryKind() const {
+ return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :
+ ObjCPropertyQueryKind::OBJC_PR_query_instance;
+ }
+ static ObjCPropertyQueryKind getQueryKind(bool isClassProperty) {
+ return isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
+ ObjCPropertyQueryKind::OBJC_PR_query_instance;
+ }
+
+ /// getSetterKind - Return the method used for doing assignment in
+ /// the property setter. This is only valid if the property has been
+ /// defined to have a setter.
+ SetterKind getSetterKind() const {
+ if (PropertyAttributes & OBJC_PR_strong)
+ return getType()->isBlockPointerType() ? Copy : Retain;
+ if (PropertyAttributes & OBJC_PR_retain)
+ return Retain;
+ if (PropertyAttributes & OBJC_PR_copy)
+ return Copy;
+ if (PropertyAttributes & OBJC_PR_weak)
+ return Weak;
+ return Assign;
+ }
+
+ Selector getGetterName() const { return GetterName; }
+ void setGetterName(Selector Sel) { GetterName = Sel; }
+
+ Selector getSetterName() const { return SetterName; }
+ void setSetterName(Selector Sel) { SetterName = Sel; }
+
+ ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
+ void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
+
+ ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
+ void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; }
+
+ // Related to \@optional/\@required declared in \@protocol
+ void setPropertyImplementation(PropertyControl pc) {
+ PropertyImplementation = pc;
+ }
+ PropertyControl getPropertyImplementation() const {
+ return PropertyControl(PropertyImplementation);
+ }
+
+ void setPropertyIvarDecl(ObjCIvarDecl *Ivar) {
+ PropertyIvarDecl = Ivar;
+ }
+ ObjCIvarDecl *getPropertyIvarDecl() const {
+ return PropertyIvarDecl;
+ }
+
+ SourceRange getSourceRange() const override LLVM_READONLY {
+ return SourceRange(AtLoc, getLocation());
+ }
+
+ /// Get the default name of the synthesized ivar.
+ IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
+
+ /// Lookup a property by name in the specified DeclContext.
+ static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
+ const IdentifierInfo *propertyID,
+ ObjCPropertyQueryKind queryKind);
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == ObjCProperty; }
};
/// ObjCContainerDecl - Represents a container for method declarations.
@@ -706,7 +918,7 @@
SourceLocation atStartLoc)
: NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {}
- // Iterator access to properties.
+ // Iterator access to instance/class properties.
typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator;
typedef llvm::iterator_range<specific_decl_iterator<ObjCPropertyDecl>>
prop_range;
@@ -719,6 +931,36 @@
return prop_iterator(decls_end());
}
+ typedef filtered_decl_iterator<ObjCPropertyDecl,
+ &ObjCPropertyDecl::isInstanceProperty>
+ instprop_iterator;
+ typedef llvm::iterator_range<instprop_iterator> instprop_range;
+
+ instprop_range instance_properties() const {
+ return instprop_range(instprop_begin(), instprop_end());
+ }
+ instprop_iterator instprop_begin() const {
+ return instprop_iterator(decls_begin());
+ }
+ instprop_iterator instprop_end() const {
+ return instprop_iterator(decls_end());
+ }
+
+ typedef filtered_decl_iterator<ObjCPropertyDecl,
+ &ObjCPropertyDecl::isClassProperty>
+ classprop_iterator;
+ typedef llvm::iterator_range<classprop_iterator> classprop_range;
+
+ classprop_range class_properties() const {
+ return classprop_range(classprop_begin(), classprop_end());
+ }
+ classprop_iterator classprop_begin() const {
+ return classprop_iterator(decls_begin());
+ }
+ classprop_iterator classprop_end() const {
+ return classprop_iterator(decls_end());
+ }
+
// Iterator access to instance/class methods.
typedef specific_decl_iterator<ObjCMethodDecl> method_iterator;
typedef llvm::iterator_range<specific_decl_iterator<ObjCMethodDecl>>
@@ -778,9 +1020,12 @@
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
ObjCPropertyDecl *
- FindPropertyDeclaration(const IdentifierInfo *PropertyId) const;
+ FindPropertyDeclaration(const IdentifierInfo *PropertyId,
+ ObjCPropertyQueryKind QueryKind) const;
- typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
+ typedef llvm::DenseMap<std::pair<IdentifierInfo*,
+ unsigned/*isClassProperty*/>,
+ ObjCPropertyDecl*> PropertyMap;
typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
ProtocolPropertyMap;
@@ -1461,7 +1706,8 @@
}
ObjCPropertyDecl
- *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
+ *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId,
+ ObjCPropertyQueryKind QueryKind) const;
void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const override;
@@ -1527,8 +1773,9 @@
/// including in all categories except for category passed
/// as argument.
ObjCMethodDecl *lookupPropertyAccessor(const Selector Sel,
- const ObjCCategoryDecl *Cat) const {
- return lookupMethod(Sel, true/*isInstance*/,
+ const ObjCCategoryDecl *Cat,
+ bool IsClassProperty) const {
+ return lookupMethod(Sel, !IsClassProperty/*isInstance*/,
false/*shallowCategoryLookup*/,
true /* followsSuper */,
Cat);
@@ -2097,7 +2344,8 @@
void addPropertyImplementation(ObjCPropertyImplDecl *property);
- ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const;
+ ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId,
+ ObjCPropertyQueryKind queryKind) const;
ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const;
// Iterator access to properties.
@@ -2405,200 +2653,6 @@
};
-/// \brief Represents one property declaration in an Objective-C interface.
-///
-/// For example:
-/// \code{.mm}
-/// \@property (assign, readwrite) int MyProperty;
-/// \endcode
-class ObjCPropertyDecl : public NamedDecl {
- void anchor() override;
-public:
- enum PropertyAttributeKind {
- OBJC_PR_noattr = 0x00,
- OBJC_PR_readonly = 0x01,
- OBJC_PR_getter = 0x02,
- OBJC_PR_assign = 0x04,
- OBJC_PR_readwrite = 0x08,
- OBJC_PR_retain = 0x10,
- OBJC_PR_copy = 0x20,
- OBJC_PR_nonatomic = 0x40,
- OBJC_PR_setter = 0x80,
- OBJC_PR_atomic = 0x100,
- OBJC_PR_weak = 0x200,
- OBJC_PR_strong = 0x400,
- OBJC_PR_unsafe_unretained = 0x800,
- /// Indicates that the nullability of the type was spelled with a
- /// property attribute rather than a type qualifier.
- OBJC_PR_nullability = 0x1000,
- OBJC_PR_null_resettable = 0x2000
- // Adding a property should change NumPropertyAttrsBits
- };
-
- enum {
- /// \brief Number of bits fitting all the property attributes.
- NumPropertyAttrsBits = 14
- };
-
- enum SetterKind { Assign, Retain, Copy, Weak };
- enum PropertyControl { None, Required, Optional };
-private:
- SourceLocation AtLoc; // location of \@property
- SourceLocation LParenLoc; // location of '(' starting attribute list or null.
- QualType DeclType;
- TypeSourceInfo *DeclTypeSourceInfo;
- unsigned PropertyAttributes : NumPropertyAttrsBits;
- unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
- // \@required/\@optional
- unsigned PropertyImplementation : 2;
-
- Selector GetterName; // getter name of NULL if no getter
- Selector SetterName; // setter name of NULL if no setter
-
- ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
- ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
- ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property
-
- ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- SourceLocation AtLocation, SourceLocation LParenLocation,
- QualType T, TypeSourceInfo *TSI,
- PropertyControl propControl)
- : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
- LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI),
- PropertyAttributes(OBJC_PR_noattr),
- PropertyAttributesAsWritten(OBJC_PR_noattr),
- PropertyImplementation(propControl),
- GetterName(Selector()),
- SetterName(Selector()),
- GetterMethodDecl(nullptr), SetterMethodDecl(nullptr),
- PropertyIvarDecl(nullptr) {}
-
-public:
- static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- IdentifierInfo *Id, SourceLocation AtLocation,
- SourceLocation LParenLocation,
- QualType T,
- TypeSourceInfo *TSI,
- PropertyControl propControl = None);
-
- static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
- SourceLocation getAtLoc() const { return AtLoc; }
- void setAtLoc(SourceLocation L) { AtLoc = L; }
-
- SourceLocation getLParenLoc() const { return LParenLoc; }
- void setLParenLoc(SourceLocation L) { LParenLoc = L; }
-
- TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; }
-
- QualType getType() const { return DeclType; }
-
- void setType(QualType T, TypeSourceInfo *TSI) {
- DeclType = T;
- DeclTypeSourceInfo = TSI;
- }
-
- /// Retrieve the type when this property is used with a specific base object
- /// type.
- QualType getUsageType(QualType objectType) const;
-
- PropertyAttributeKind getPropertyAttributes() const {
- return PropertyAttributeKind(PropertyAttributes);
- }
- void setPropertyAttributes(PropertyAttributeKind PRVal) {
- PropertyAttributes |= PRVal;
- }
-
- PropertyAttributeKind getPropertyAttributesAsWritten() const {
- return PropertyAttributeKind(PropertyAttributesAsWritten);
- }
-
- bool hasWrittenStorageAttribute() const {
- return PropertyAttributesAsWritten & (OBJC_PR_assign | OBJC_PR_copy |
- OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong |
- OBJC_PR_weak);
- }
-
- void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
- PropertyAttributesAsWritten = PRVal;
- }
-
- // Helper methods for accessing attributes.
-
- /// isReadOnly - Return true iff the property has a setter.
- bool isReadOnly() const {
- return (PropertyAttributes & OBJC_PR_readonly);
- }
-
- /// isAtomic - Return true if the property is atomic.
- bool isAtomic() const {
- return (PropertyAttributes & OBJC_PR_atomic);
- }
-
- /// isRetaining - Return true if the property retains its value.
- bool isRetaining() const {
- return (PropertyAttributes &
- (OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy));
- }
-
- /// getSetterKind - Return the method used for doing assignment in
- /// the property setter. This is only valid if the property has been
- /// defined to have a setter.
- SetterKind getSetterKind() const {
- if (PropertyAttributes & OBJC_PR_strong)
- return getType()->isBlockPointerType() ? Copy : Retain;
- if (PropertyAttributes & OBJC_PR_retain)
- return Retain;
- if (PropertyAttributes & OBJC_PR_copy)
- return Copy;
- if (PropertyAttributes & OBJC_PR_weak)
- return Weak;
- return Assign;
- }
-
- Selector getGetterName() const { return GetterName; }
- void setGetterName(Selector Sel) { GetterName = Sel; }
-
- Selector getSetterName() const { return SetterName; }
- void setSetterName(Selector Sel) { SetterName = Sel; }
-
- ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
- void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
-
- ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
- void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; }
-
- // Related to \@optional/\@required declared in \@protocol
- void setPropertyImplementation(PropertyControl pc) {
- PropertyImplementation = pc;
- }
- PropertyControl getPropertyImplementation() const {
- return PropertyControl(PropertyImplementation);
- }
-
- void setPropertyIvarDecl(ObjCIvarDecl *Ivar) {
- PropertyIvarDecl = Ivar;
- }
- ObjCIvarDecl *getPropertyIvarDecl() const {
- return PropertyIvarDecl;
- }
-
- SourceRange getSourceRange() const override LLVM_READONLY {
- return SourceRange(AtLoc, getLocation());
- }
-
- /// Get the default name of the synthesized ivar.
- IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
-
- /// Lookup a property by name in the specified DeclContext.
- static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
- const IdentifierInfo *propertyID);
-
- static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classofKind(Kind K) { return K == ObjCProperty; }
-};
-
/// ObjCPropertyImplDecl - Represents implementation declaration of a property
/// in a class or category implementation block. For example:
/// \@synthesize prop1 = ivar1;
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
index 7f0616f..598f418 100644
--- a/include/clang/AST/DeclOpenMP.h
+++ b/include/clang/AST/DeclOpenMP.h
@@ -33,8 +33,12 @@
/// };
/// \endcode
///
-class OMPThreadPrivateDecl : public Decl {
+class OMPThreadPrivateDecl final
+ : public Decl,
+ private llvm::TrailingObjects<OMPThreadPrivateDecl, Expr *> {
friend class ASTDeclReader;
+ friend TrailingObjects;
+
unsigned NumVars;
virtual void anchor();
@@ -43,14 +47,11 @@
Decl(DK, DC, L), NumVars(0) { }
ArrayRef<const Expr *> getVars() const {
- return llvm::makeArrayRef(reinterpret_cast<const Expr * const *>(this + 1),
- NumVars);
+ return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumVars);
}
MutableArrayRef<Expr *> getVars() {
- return MutableArrayRef<Expr *>(
- reinterpret_cast<Expr **>(this + 1),
- NumVars);
+ return MutableArrayRef<Expr *>(getTrailingObjects<Expr *>(), NumVars);
}
void setVars(ArrayRef<Expr *> VL);
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index a23fe4b..a9109ef 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -45,7 +45,7 @@
/// \brief Stores a list of template parameters for a TemplateDecl and its
/// derived classes.
-class LLVM_ALIGNAS(/*alignof(void*)*/ LLVM_PTR_SIZE) TemplateParameterList final
+class TemplateParameterList final
: private llvm::TrailingObjects<TemplateParameterList, NamedDecl *> {
/// The location of the 'template' keyword.
@@ -68,15 +68,13 @@
}
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
- NamedDecl **Params, unsigned NumParams,
- SourceLocation RAngleLoc);
+ ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc);
public:
static TemplateParameterList *Create(const ASTContext &C,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- NamedDecl **Params,
- unsigned NumParams,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc);
/// \brief Iterates through the template parameters in this list.
@@ -155,9 +153,9 @@
public:
FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- NamedDecl **Params,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc)
- : List(TemplateLoc, LAngleLoc, Params, N, RAngleLoc) {
+ : List(TemplateLoc, LAngleLoc, Params, RAngleLoc) {
// Because we're doing an evil layout hack above, have some
// asserts, just to double-check everything is laid out like
// expected.
@@ -171,7 +169,7 @@
};
/// \brief A template argument list.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) TemplateArgumentList final
+class TemplateArgumentList final
: private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> {
/// \brief The template argument list.
const TemplateArgument *Arguments;
@@ -448,17 +446,8 @@
/// explicit instantiation declaration, or explicit instantiation
/// definition.
bool isExplicitInstantiationOrSpecialization() const {
- switch (getTemplateSpecializationKind()) {
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- return true;
-
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- return false;
- }
- llvm_unreachable("bad template specialization kind");
+ return isTemplateExplicitInstantiationOrSpecialization(
+ getTemplateSpecializationKind());
}
/// \brief Set the template specialization kind.
@@ -564,8 +553,7 @@
/// friend void foo<>(T);
/// };
/// \endcode
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8)
- DependentFunctionTemplateSpecializationInfo final
+class DependentFunctionTemplateSpecializationInfo final
: private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo,
TemplateArgumentLoc,
FunctionTemplateDecl *> {
@@ -1644,17 +1632,8 @@
/// explicit instantiation declaration, or explicit instantiation
/// definition.
bool isExplicitInstantiationOrSpecialization() const {
- switch (getTemplateSpecializationKind()) {
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- return true;
-
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- return false;
- }
- llvm_unreachable("bad template specialization kind");
+ return isTemplateExplicitInstantiationOrSpecialization(
+ getTemplateSpecializationKind());
}
void setSpecializationKind(TemplateSpecializationKind TSK) {
@@ -2499,17 +2478,8 @@
/// explicit instantiation declaration, or explicit instantiation
/// definition.
bool isExplicitInstantiationOrSpecialization() const {
- switch (getTemplateSpecializationKind()) {
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- return true;
-
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- return false;
- }
- llvm_unreachable("bad template specialization kind");
+ return isTemplateExplicitInstantiationOrSpecialization(
+ getTemplateSpecializationKind());
}
void setSpecializationKind(TemplateSpecializationKind TSK) {
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index ec0fb0b..9482e83 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -395,7 +395,7 @@
// Locations (if any) for the tilde (destructor) or operator keyword
// (conversion) are stored elsewhere.
struct NT {
- TypeSourceInfo* TInfo;
+ TypeSourceInfo *TInfo;
};
// The location (if any) of the operator keyword is stored elsewhere.
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index cc1fc0a..bc5dab7 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -529,10 +529,15 @@
/// EvalStatus is a struct with detailed info about an evaluation in progress.
struct EvalStatus {
- /// HasSideEffects - Whether the evaluated expression has side effects.
+ /// \brief Whether the evaluated expression has side effects.
/// For example, (f() && 0) can be folded, but it still has side effects.
bool HasSideEffects;
+ /// \brief Whether the evaluation hit undefined behavior.
+ /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior.
+ /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
+ bool HasUndefinedBehavior;
+
/// Diag - If this is non-null, it will be filled in with a stack of notes
/// indicating why evaluation failed (or why it failed to produce a constant
/// expression).
@@ -542,7 +547,8 @@
/// expression *is* a constant expression, no notes will be produced.
SmallVectorImpl<PartialDiagnosticAt> *Diag;
- EvalStatus() : HasSideEffects(false), Diag(nullptr) {}
+ EvalStatus()
+ : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
// hasSideEffects - Return true if the evaluated expression has
// side effects.
@@ -575,7 +581,12 @@
/// side-effects.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
- enum SideEffectsKind { SE_NoSideEffects, SE_AllowSideEffects };
+ enum SideEffectsKind {
+ SE_NoSideEffects, ///< Strictly evaluate the expression.
+ SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not
+ ///< arbitrary unmodeled side effects.
+ SE_AllowSideEffects ///< Allow any unmodeled side effect.
+ };
/// EvaluateAsInt - Return true if this is a constant which we can fold and
/// convert to an integer, using any crazy technique that we want to.
@@ -584,7 +595,8 @@
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded without side-effects, but discard the result.
- bool isEvaluatable(const ASTContext &Ctx) const;
+ bool isEvaluatable(const ASTContext &Ctx,
+ SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
/// HasSideEffects - This routine returns true for all those expressions
/// which have any effect other than producing a value. Example is a function
@@ -628,6 +640,16 @@
const FunctionDecl *Callee,
ArrayRef<const Expr*> Args) const;
+ /// \brief If the current Expr is a pointer, this will try to statically
+ /// determine the number of bytes available where the pointer is pointing.
+ /// Returns true if all of the above holds and we were able to figure out the
+ /// size, false otherwise.
+ ///
+ /// \param Type - How to evaluate the size of the Expr, as defined by the
+ /// "type" parameter of __builtin_object_size
+ bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx,
+ unsigned Type) const;
+
/// \brief Enumeration used to describe the kind of Null pointer constant
/// returned from \c isNullPointerConstant().
enum NullPointerConstantKind {
@@ -897,7 +919,11 @@
/// DeclRefExprBits.RefersToEnclosingVariableOrCapture
/// Specifies when this declaration reference expression (validly)
/// refers to an enclosed local or a captured variable.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DeclRefExpr : public Expr {
+class DeclRefExpr final
+ : public Expr,
+ private llvm::TrailingObjects<DeclRefExpr, NestedNameSpecifierLoc,
+ NamedDecl *, ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc> {
/// \brief The declaration that we are referencing.
ValueDecl *D;
@@ -908,36 +934,22 @@
/// embedded in D.
DeclarationNameLoc DNLoc;
- /// \brief Helper to retrieve the optional NestedNameSpecifierLoc.
- NestedNameSpecifierLoc &getInternalQualifierLoc() {
- assert(hasQualifier());
- return *reinterpret_cast<NestedNameSpecifierLoc *>(this + 1);
+ size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
+ return hasQualifier() ? 1 : 0;
}
- /// \brief Helper to retrieve the optional NestedNameSpecifierLoc.
- const NestedNameSpecifierLoc &getInternalQualifierLoc() const {
- return const_cast<DeclRefExpr *>(this)->getInternalQualifierLoc();
+ size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
+ return hasFoundDecl() ? 1 : 0;
+ }
+
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return hasTemplateKWAndArgsInfo() ? 1 : 0;
}
/// \brief Test whether there is a distinct FoundDecl attached to the end of
/// this DRE.
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
- /// \brief Helper to retrieve the optional NamedDecl through which this
- /// reference occurred.
- NamedDecl *&getInternalFoundDecl() {
- assert(hasFoundDecl());
- if (hasQualifier())
- return *reinterpret_cast<NamedDecl **>(&getInternalQualifierLoc() + 1);
- return *reinterpret_cast<NamedDecl **>(this + 1);
- }
-
- /// \brief Helper to retrieve the optional NamedDecl through which this
- /// reference occurred.
- NamedDecl *getInternalFoundDecl() const {
- return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
- }
-
DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -1010,21 +1022,17 @@
bool hasQualifier() const { return DeclRefExprBits.HasQualifier; }
/// \brief If the name was qualified, retrieves the nested-name-specifier
- /// that precedes the name. Otherwise, returns NULL.
- NestedNameSpecifier *getQualifier() const {
- if (!hasQualifier())
- return nullptr;
-
- return getInternalQualifierLoc().getNestedNameSpecifier();
- }
-
- /// \brief If the name was qualified, retrieves the nested-name-specifier
/// that precedes the name, with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const {
if (!hasQualifier())
return NestedNameSpecifierLoc();
+ return *getTrailingObjects<NestedNameSpecifierLoc>();
+ }
- return getInternalQualifierLoc();
+ /// \brief If the name was qualified, retrieves the nested-name-specifier
+ /// that precedes the name. Otherwise, returns NULL.
+ NestedNameSpecifier *getQualifier() const {
+ return getQualifierLoc().getNestedNameSpecifier();
}
/// \brief Get the NamedDecl through which this reference occurred.
@@ -1032,64 +1040,40 @@
/// This Decl may be different from the ValueDecl actually referred to in the
/// presence of using declarations, etc. It always returns non-NULL, and may
/// simple return the ValueDecl when appropriate.
+
NamedDecl *getFoundDecl() {
- return hasFoundDecl() ? getInternalFoundDecl() : D;
+ return hasFoundDecl() ? *getTrailingObjects<NamedDecl *>() : D;
}
/// \brief Get the NamedDecl through which this reference occurred.
/// See non-const variant.
const NamedDecl *getFoundDecl() const {
- return hasFoundDecl() ? getInternalFoundDecl() : D;
+ return hasFoundDecl() ? *getTrailingObjects<NamedDecl *>() : D;
}
bool hasTemplateKWAndArgsInfo() const {
return DeclRefExprBits.HasTemplateKWAndArgsInfo;
}
- /// \brief Return the optional template keyword and arguments info.
- ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
- if (!hasTemplateKWAndArgsInfo())
- return nullptr;
-
- if (hasFoundDecl()) {
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
- llvm::alignAddr(&getInternalFoundDecl() + 1,
- llvm::alignOf<ASTTemplateKWAndArgsInfo>()));
- }
-
- if (hasQualifier()) {
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
- llvm::alignAddr(&getInternalQualifierLoc() + 1,
- llvm::alignOf<ASTTemplateKWAndArgsInfo>()));
- }
-
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1);
- }
-
- /// \brief Return the optional template keyword and arguments info.
- const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
- return const_cast<DeclRefExpr*>(this)->getTemplateKWAndArgsInfo();
- }
-
/// \brief Retrieve the location of the template keyword preceding
/// this name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
- return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// \brief Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the name, if any.
SourceLocation getLAngleLoc() const {
if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
- return getTemplateKWAndArgsInfo()->LAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// \brief Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the name, if any.
SourceLocation getRAngleLoc() const {
if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
- return getTemplateKWAndArgsInfo()->RAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
/// \brief Determines whether the name in this declaration reference
@@ -1100,32 +1084,12 @@
/// explicit template argument list.
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *getTemplateKWAndArgsInfo();
- }
-
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- return const_cast<DeclRefExpr *>(this)->getExplicitTemplateArgs();
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
- if (!hasExplicitTemplateArgs()) return nullptr;
- return &getExplicitTemplateArgs();
- }
-
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
if (hasExplicitTemplateArgs())
- getExplicitTemplateArgs().copyInto(List);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto(
+ getTrailingObjects<TemplateArgumentLoc>(), List);
}
/// \brief Retrieve the template arguments provided as part of this
@@ -1134,7 +1098,7 @@
if (!hasExplicitTemplateArgs())
return nullptr;
- return getExplicitTemplateArgs().getTemplateArgs();
+ return getTrailingObjects<TemplateArgumentLoc>();
}
/// \brief Retrieve the number of template arguments provided as part of this
@@ -1143,7 +1107,7 @@
if (!hasExplicitTemplateArgs())
return 0;
- return getExplicitTemplateArgs().NumTemplateArgs;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
/// \brief Returns true if this expression refers to a function that
@@ -1173,6 +1137,7 @@
return child_range(child_iterator(), child_iterator());
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -1327,6 +1292,7 @@
enum CharacterKind {
Ascii,
Wide,
+ UTF8,
UTF16,
UTF32
};
@@ -1609,13 +1575,15 @@
/// and can have escape sequences in them in addition to the usual trigraph
/// and escaped newline business. This routine handles this complexity.
///
- SourceLocation getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
- const LangOptions &Features,
- const TargetInfo &Target) const;
+ SourceLocation
+ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
+ const LangOptions &Features, const TargetInfo &Target,
+ unsigned *StartToken = nullptr,
+ unsigned *StartTokenByteOffset = nullptr) const;
typedef const SourceLocation *tokloc_iterator;
tokloc_iterator tokloc_begin() const { return TokLocs; }
- tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; }
+ tokloc_iterator tokloc_end() const { return TokLocs + NumConcatenated; }
SourceLocation getLocStart() const LLVM_READONLY { return TokLocs[0]; }
SourceLocation getLocEnd() const LLVM_READONLY {
@@ -1782,6 +1750,99 @@
child_range children() { return child_range(&Val, &Val+1); }
};
+/// Helper class for OffsetOfExpr.
+
+// __builtin_offsetof(type, identifier(.identifier|[expr])*)
+class OffsetOfNode {
+public:
+ /// \brief The kind of offsetof node we have.
+ enum Kind {
+ /// \brief An index into an array.
+ Array = 0x00,
+ /// \brief A field.
+ Field = 0x01,
+ /// \brief A field in a dependent type, known only by its name.
+ Identifier = 0x02,
+ /// \brief An implicit indirection through a C++ base class, when the
+ /// field found is in a base class.
+ Base = 0x03
+ };
+
+private:
+ enum { MaskBits = 2, Mask = 0x03 };
+
+ /// \brief The source range that covers this part of the designator.
+ SourceRange Range;
+
+ /// \brief The data describing the designator, which comes in three
+ /// different forms, depending on the lower two bits.
+ /// - An unsigned index into the array of Expr*'s stored after this node
+ /// in memory, for [constant-expression] designators.
+ /// - A FieldDecl*, for references to a known field.
+ /// - An IdentifierInfo*, for references to a field with a given name
+ /// when the class type is dependent.
+ /// - A CXXBaseSpecifier*, for references that look at a field in a
+ /// base class.
+ uintptr_t Data;
+
+public:
+ /// \brief Create an offsetof node that refers to an array element.
+ OffsetOfNode(SourceLocation LBracketLoc, unsigned Index,
+ SourceLocation RBracketLoc)
+ : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) {}
+
+ /// \brief Create an offsetof node that refers to a field.
+ OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, SourceLocation NameLoc)
+ : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc),
+ Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) {}
+
+ /// \brief Create an offsetof node that refers to an identifier.
+ OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc)
+ : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc),
+ Data(reinterpret_cast<uintptr_t>(Name) | Identifier) {}
+
+ /// \brief Create an offsetof node that refers into a C++ base class.
+ explicit OffsetOfNode(const CXXBaseSpecifier *Base)
+ : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
+
+ /// \brief Determine what kind of offsetof node this is.
+ Kind getKind() const { return static_cast<Kind>(Data & Mask); }
+
+ /// \brief For an array element node, returns the index into the array
+ /// of expressions.
+ unsigned getArrayExprIndex() const {
+ assert(getKind() == Array);
+ return Data >> 2;
+ }
+
+ /// \brief For a field offsetof node, returns the field.
+ FieldDecl *getField() const {
+ assert(getKind() == Field);
+ return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask);
+ }
+
+ /// \brief For a field or identifier offsetof node, returns the name of
+ /// the field.
+ IdentifierInfo *getFieldName() const;
+
+ /// \brief For a base class node, returns the base specifier.
+ CXXBaseSpecifier *getBase() const {
+ assert(getKind() == Base);
+ return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
+ }
+
+ /// \brief Retrieve the source range that covers this offsetof node.
+ ///
+ /// For an array element node, the source range contains the locations of
+ /// the square brackets. For a field or identifier node, the source range
+ /// contains the location of the period (if there is one) and the
+ /// identifier.
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
+};
+
/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form
/// offsetof(record-type, member-designator). For example, given:
/// @code
@@ -1796,104 +1857,9 @@
/// @endcode
/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d).
-class OffsetOfExpr : public Expr {
-public:
- // __builtin_offsetof(type, identifier(.identifier|[expr])*)
- class OffsetOfNode {
- public:
- /// \brief The kind of offsetof node we have.
- enum Kind {
- /// \brief An index into an array.
- Array = 0x00,
- /// \brief A field.
- Field = 0x01,
- /// \brief A field in a dependent type, known only by its name.
- Identifier = 0x02,
- /// \brief An implicit indirection through a C++ base class, when the
- /// field found is in a base class.
- Base = 0x03
- };
-
- private:
- enum { MaskBits = 2, Mask = 0x03 };
-
- /// \brief The source range that covers this part of the designator.
- SourceRange Range;
-
- /// \brief The data describing the designator, which comes in three
- /// different forms, depending on the lower two bits.
- /// - An unsigned index into the array of Expr*'s stored after this node
- /// in memory, for [constant-expression] designators.
- /// - A FieldDecl*, for references to a known field.
- /// - An IdentifierInfo*, for references to a field with a given name
- /// when the class type is dependent.
- /// - A CXXBaseSpecifier*, for references that look at a field in a
- /// base class.
- uintptr_t Data;
-
- public:
- /// \brief Create an offsetof node that refers to an array element.
- OffsetOfNode(SourceLocation LBracketLoc, unsigned Index,
- SourceLocation RBracketLoc)
- : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { }
-
- /// \brief Create an offsetof node that refers to a field.
- OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field,
- SourceLocation NameLoc)
- : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
- Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) { }
-
- /// \brief Create an offsetof node that refers to an identifier.
- OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name,
- SourceLocation NameLoc)
- : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
- Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { }
-
- /// \brief Create an offsetof node that refers into a C++ base class.
- explicit OffsetOfNode(const CXXBaseSpecifier *Base)
- : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
-
- /// \brief Determine what kind of offsetof node this is.
- Kind getKind() const {
- return static_cast<Kind>(Data & Mask);
- }
-
- /// \brief For an array element node, returns the index into the array
- /// of expressions.
- unsigned getArrayExprIndex() const {
- assert(getKind() == Array);
- return Data >> 2;
- }
-
- /// \brief For a field offsetof node, returns the field.
- FieldDecl *getField() const {
- assert(getKind() == Field);
- return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask);
- }
-
- /// \brief For a field or identifier offsetof node, returns the name of
- /// the field.
- IdentifierInfo *getFieldName() const;
-
- /// \brief For a base class node, returns the base specifier.
- CXXBaseSpecifier *getBase() const {
- assert(getKind() == Base);
- return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
- }
-
- /// \brief Retrieve the source range that covers this offsetof node.
- ///
- /// For an array element node, the source range contains the locations of
- /// the square brackets. For a field or identifier node, the source range
- /// contains the location of the period (if there is one) and the
- /// identifier.
- SourceRange getSourceRange() const LLVM_READONLY { return Range; }
- SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
- SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
- };
-
-private:
-
+class OffsetOfExpr final
+ : public Expr,
+ private llvm::TrailingObjects<OffsetOfExpr, OffsetOfNode, Expr *> {
SourceLocation OperatorLoc, RParenLoc;
// Base type;
TypeSourceInfo *TSInfo;
@@ -1902,6 +1868,10 @@
// Number of sub-expressions (i.e. array subscript expressions).
unsigned NumExprs;
+ size_t numTrailingObjects(OverloadToken<OffsetOfNode>) const {
+ return NumComps;
+ }
+
OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
@@ -1938,12 +1908,12 @@
const OffsetOfNode &getComponent(unsigned Idx) const {
assert(Idx < NumComps && "Subscript out of range");
- return reinterpret_cast<const OffsetOfNode *> (this + 1)[Idx];
+ return getTrailingObjects<OffsetOfNode>()[Idx];
}
void setComponent(unsigned Idx, OffsetOfNode ON) {
assert(Idx < NumComps && "Subscript out of range");
- reinterpret_cast<OffsetOfNode *> (this + 1)[Idx] = ON;
+ getTrailingObjects<OffsetOfNode>()[Idx] = ON;
}
unsigned getNumComponents() const {
@@ -1952,17 +1922,17 @@
Expr* getIndexExpr(unsigned Idx) {
assert(Idx < NumExprs && "Subscript out of range");
- return reinterpret_cast<Expr **>(
- reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx];
+ return getTrailingObjects<Expr *>()[Idx];
}
+
const Expr *getIndexExpr(unsigned Idx) const {
- return const_cast<OffsetOfExpr*>(this)->getIndexExpr(Idx);
+ assert(Idx < NumExprs && "Subscript out of range");
+ return getTrailingObjects<Expr *>()[Idx];
}
void setIndexExpr(unsigned Idx, Expr* E) {
assert(Idx < NumComps && "Subscript out of range");
- reinterpret_cast<Expr **>(
- reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx] = E;
+ getTrailingObjects<Expr *>()[Idx] = E;
}
unsigned getNumExpressions() const {
@@ -1978,11 +1948,10 @@
// Iterators
child_range children() {
- Stmt **begin =
- reinterpret_cast<Stmt**>(reinterpret_cast<OffsetOfNode*>(this + 1)
- + NumComps);
+ Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
return child_range(begin, begin + NumExprs);
}
+ friend TrailingObjects;
};
/// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated)
@@ -2168,11 +2137,15 @@
unsigned NumArgs;
SourceLocation RParenLoc;
+ void updateDependenciesFromArg(Expr *Arg);
+
protected:
// These versions of the constructor are for derived classes.
- CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation rparenloc);
+ CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
+ ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
+ ExprValueKind VK, SourceLocation rparenloc);
+ CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args,
+ QualType t, ExprValueKind VK, SourceLocation rparenloc);
CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty);
@@ -2222,7 +2195,8 @@
return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START);
}
const Expr *const *getArgs() const {
- return const_cast<CallExpr*>(this)->getArgs();
+ return reinterpret_cast<Expr **>(SubExprs + getNumPreArgs() +
+ PREARGS_START);
}
/// getArg - Return the specified argument.
@@ -2311,20 +2285,24 @@
}
};
+/// Extra data stored in some MemberExpr objects.
+struct MemberExprNameQualifier {
+ /// \brief The nested-name-specifier that qualifies the name, including
+ /// source-location information.
+ NestedNameSpecifierLoc QualifierLoc;
+
+ /// \brief The DeclAccessPair through which the MemberDecl was found due to
+ /// name qualifiers.
+ DeclAccessPair FoundDecl;
+};
+
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
///
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) MemberExpr : public Expr {
- /// Extra data stored in some member expressions.
- struct LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) MemberNameQualifier {
- /// \brief The nested-name-specifier that qualifies the name, including
- /// source-location information.
- NestedNameSpecifierLoc QualifierLoc;
-
- /// \brief The DeclAccessPair through which the MemberDecl was found due to
- /// name qualifiers.
- DeclAccessPair FoundDecl;
- };
-
+class MemberExpr final
+ : public Expr,
+ private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier,
+ ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc> {
/// Base - the expression for the base pointer or structure references. In
/// X.F, this is "X".
Stmt *Base;
@@ -2348,7 +2326,7 @@
/// \brief True if this member expression used a nested-name-specifier to
/// refer to the member, e.g., "x->Base::f", or found its member via a using
- /// declaration. When true, a MemberNameQualifier
+ /// declaration. When true, a MemberExprNameQualifier
/// structure is allocated immediately after the MemberExpr.
bool HasQualifierOrFoundDecl : 1;
@@ -2356,24 +2334,19 @@
/// and/or a template argument list explicitly, e.g., x->f<int>,
/// x->template f, x->template f<int>.
/// When true, an ASTTemplateKWAndArgsInfo structure and its
- /// TemplateArguments (if any) are allocated immediately after
- /// the MemberExpr or, if the member expression also has a qualifier,
- /// after the MemberNameQualifier structure.
+ /// TemplateArguments (if any) are present.
bool HasTemplateKWAndArgsInfo : 1;
/// \brief True if this member expression refers to a method that
/// was resolved from an overloaded set having size greater than 1.
bool HadMultipleCandidates : 1;
- /// \brief Retrieve the qualifier that preceded the member name, if any.
- MemberNameQualifier *getMemberQualifier() {
- assert(HasQualifierOrFoundDecl);
- return reinterpret_cast<MemberNameQualifier *> (this + 1);
+ size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const {
+ return HasQualifierOrFoundDecl ? 1 : 0;
}
- /// \brief Retrieve the qualifier that preceded the member name, if any.
- const MemberNameQualifier *getMemberQualifier() const {
- return const_cast<MemberExpr *>(this)->getMemberQualifier();
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return HasTemplateKWAndArgsInfo ? 1 : 0;
}
public:
@@ -2429,7 +2402,7 @@
if (!HasQualifierOrFoundDecl)
return DeclAccessPair::make(getMemberDecl(),
getMemberDecl()->getAccess());
- return getMemberQualifier()->FoundDecl;
+ return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl;
}
/// \brief Determines whether this member expression actually had
@@ -2438,61 +2411,41 @@
bool hasQualifier() const { return getQualifier() != nullptr; }
/// \brief If the member name was qualified, retrieves the
- /// nested-name-specifier that precedes the member name. Otherwise, returns
- /// NULL.
- NestedNameSpecifier *getQualifier() const {
- if (!HasQualifierOrFoundDecl)
- return nullptr;
-
- return getMemberQualifier()->QualifierLoc.getNestedNameSpecifier();
- }
-
- /// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name, with source-location
/// information.
NestedNameSpecifierLoc getQualifierLoc() const {
- if (!hasQualifier())
+ if (!HasQualifierOrFoundDecl)
return NestedNameSpecifierLoc();
- return getMemberQualifier()->QualifierLoc;
+ return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc;
}
- /// \brief Return the optional template keyword and arguments info.
- ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
- if (!HasTemplateKWAndArgsInfo)
- return nullptr;
-
- if (!HasQualifierOrFoundDecl)
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1);
-
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
- getMemberQualifier() + 1);
- }
-
- /// \brief Return the optional template keyword and arguments info.
- const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
- return const_cast<MemberExpr*>(this)->getTemplateKWAndArgsInfo();
+ /// \brief If the member name was qualified, retrieves the
+ /// nested-name-specifier that precedes the member name. Otherwise, returns
+ /// NULL.
+ NestedNameSpecifier *getQualifier() const {
+ return getQualifierLoc().getNestedNameSpecifier();
}
/// \brief Retrieve the location of the template keyword preceding
/// the member name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// \brief Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the member name, if any.
SourceLocation getLAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->LAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// \brief Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the member name, if any.
SourceLocation getRAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->RAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
/// Determines whether the member name was preceded by the template keyword.
@@ -2506,30 +2459,8 @@
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
if (hasExplicitTemplateArgs())
- getExplicitTemplateArgs().copyInto(List);
- }
-
- /// \brief Retrieve the explicit template argument list that
- /// follow the member template name. This must only be called on an
- /// expression with explicit template arguments.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *getTemplateKWAndArgsInfo();
- }
-
- /// \brief Retrieve the explicit template argument list that
- /// followed the member template name. This must only be called on
- /// an expression with explicit template arguments.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- return const_cast<MemberExpr *>(this)->getExplicitTemplateArgs();
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
- if (!hasExplicitTemplateArgs()) return nullptr;
- return &getExplicitTemplateArgs();
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto(
+ getTrailingObjects<TemplateArgumentLoc>(), List);
}
/// \brief Retrieve the template arguments provided as part of this
@@ -2538,7 +2469,7 @@
if (!hasExplicitTemplateArgs())
return nullptr;
- return getExplicitTemplateArgs().getTemplateArgs();
+ return getTrailingObjects<TemplateArgumentLoc>();
}
/// \brief Retrieve the number of template arguments provided as part of this
@@ -2547,7 +2478,7 @@
if (!hasExplicitTemplateArgs())
return 0;
- return getExplicitTemplateArgs().NumTemplateArgs;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
/// \brief Retrieve the member declaration name info.
@@ -2603,6 +2534,7 @@
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
+ friend TrailingObjects;
friend class ASTReader;
friend class ASTStmtWriter;
};
@@ -2752,8 +2684,6 @@
path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); }
- void setCastPath(const CXXCastPath &Path);
-
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant;
@@ -2783,7 +2713,9 @@
/// // to an xvalue of type Base
/// }
/// @endcode
-class ImplicitCastExpr : public CastExpr {
+class ImplicitCastExpr final
+ : public CastExpr,
+ private llvm::TrailingObjects<ImplicitCastExpr, CXXBaseSpecifier *> {
private:
ImplicitCastExpr(QualType ty, CastKind kind, Expr *op,
unsigned BasePathLength, ExprValueKind VK)
@@ -2819,6 +2751,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
inline Expr *Expr::IgnoreImpCasts() {
@@ -2878,7 +2813,9 @@
/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style
/// cast in C++ (C++ [expr.cast]), which uses the syntax
/// (Type)expr. For example: @c (int)f.
-class CStyleCastExpr : public ExplicitCastExpr {
+class CStyleCastExpr final
+ : public ExplicitCastExpr,
+ private llvm::TrailingObjects<CStyleCastExpr, CXXBaseSpecifier *> {
SourceLocation LPLoc; // the location of the left paren
SourceLocation RPLoc; // the location of the right paren
@@ -2916,6 +2853,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CStyleCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// \brief A builtin binary operation expression such as "x + y" or "x <= y".
@@ -3010,7 +2950,10 @@
/// predicates to categorize the respective opcodes.
bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; }
- bool isMultiplicativeOp() const { return Opc >= BO_Mul && Opc <= BO_Rem; }
+ static bool isMultiplicativeOp(Opcode Opc) {
+ return Opc >= BO_Mul && Opc <= BO_Rem;
+ }
+ bool isMultiplicativeOp() const { return isMultiplicativeOp(getOpcode()); }
static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; }
bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); }
static bool isShiftOp(Opcode Opc) { return Opc == BO_Shl || Opc == BO_Shr; }
@@ -3817,6 +3760,10 @@
/// \brief Retrieve the set of initializers.
Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); }
+ ArrayRef<Expr *> inits() {
+ return llvm::makeArrayRef(getInits(), getNumInits());
+ }
+
const Expr *getInit(unsigned Init) const {
assert(Init < getNumInits() && "Initializer access out of range!");
return cast_or_null<Expr>(InitExprs[Init]);
@@ -3985,7 +3932,9 @@
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
/// designators, one array designator for @c [2] followed by one field
/// designator for @c .y. The initialization expression will be 1.0.
-class DesignatedInitExpr : public Expr {
+class DesignatedInitExpr final
+ : public Expr,
+ private llvm::TrailingObjects<DesignatedInitExpr, Stmt *> {
public:
/// \brief Forward declaration of the Designator class.
class Designator;
@@ -4265,12 +4214,12 @@
Expr *getSubExpr(unsigned Idx) const {
assert(Idx < NumSubExprs && "Subscript out of range");
- return cast<Expr>(reinterpret_cast<Stmt *const *>(this + 1)[Idx]);
+ return cast<Expr>(getTrailingObjects<Stmt *>()[Idx]);
}
void setSubExpr(unsigned Idx, Expr *E) {
assert(Idx < NumSubExprs && "Subscript out of range");
- reinterpret_cast<Stmt **>(this + 1)[Idx] = E;
+ getTrailingObjects<Stmt *>()[Idx] = E;
}
/// \brief Replaces the designator at index @p Idx with the series
@@ -4289,9 +4238,11 @@
// Iterators
child_range children() {
- Stmt **begin = reinterpret_cast<Stmt**>(this + 1);
+ Stmt **begin = getTrailingObjects<Stmt *>();
return child_range(begin, begin + NumSubExprs);
}
+
+ friend TrailingObjects;
};
/// \brief Represents a place-holder for an object not to be initialized by
@@ -4427,6 +4378,10 @@
Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); }
+ ArrayRef<Expr *> exprs() {
+ return llvm::makeArrayRef(getExprs(), getNumExprs());
+ }
+
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
@@ -4738,7 +4693,9 @@
/// equivalent to a particular message send, and this is very much
/// part of the user model. The name of this class encourages this
/// modelling design.
-class PseudoObjectExpr : public Expr {
+class PseudoObjectExpr final
+ : public Expr,
+ private llvm::TrailingObjects<PseudoObjectExpr, Expr *> {
// PseudoObjectExprBits.NumSubExprs - The number of sub-expressions.
// Always at least two, because the first sub-expression is the
// syntactic form.
@@ -4750,13 +4707,11 @@
// in to Create, which is an index within the semantic forms.
// Note also that ASTStmtWriter assumes this encoding.
- Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); }
+ Expr **getSubExprsBuffer() { return getTrailingObjects<Expr *>(); }
const Expr * const *getSubExprsBuffer() const {
- return reinterpret_cast<const Expr * const *>(this + 1);
+ return getTrailingObjects<Expr *>();
}
- friend class ASTStmtReader;
-
PseudoObjectExpr(QualType type, ExprValueKind VK,
Expr *syntactic, ArrayRef<Expr*> semantic,
unsigned resultIndex);
@@ -4818,6 +4773,14 @@
const_semantics_iterator semantics_end() const {
return getSubExprsBuffer() + getNumSubExprs();
}
+
+ llvm::iterator_range<semantics_iterator> semantics() {
+ return llvm::make_range(semantics_begin(), semantics_end());
+ }
+ llvm::iterator_range<const_semantics_iterator> semantics() const {
+ return llvm::make_range(semantics_begin(), semantics_end());
+ }
+
Expr *getSemanticExpr(unsigned index) {
assert(index + 1 < getNumSubExprs());
return getSubExprsBuffer()[index + 1];
@@ -4845,6 +4808,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == PseudoObjectExprClass;
}
+
+ friend TrailingObjects;
+ friend class ASTStmtReader;
};
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index cd14afa..2b8c0ea 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -66,8 +66,7 @@
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation operatorloc, bool fpContractable)
- : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
- operatorloc),
+ : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
Operator(Op), FPContractable(fpContractable) {
Range = getSourceRangeImpl();
}
@@ -125,7 +124,7 @@
public:
CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation RP)
- : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {}
+ : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {}
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
@@ -160,9 +159,7 @@
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation RP)
- : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) {
- setConfig(Config);
- }
+ : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {}
CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { }
@@ -171,7 +168,20 @@
return cast_or_null<CallExpr>(getPreArg(CONFIG));
}
CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); }
- void setConfig(CallExpr *E) { setPreArg(CONFIG, E); }
+
+ /// \brief Sets the kernel configuration expression.
+ ///
+ /// Note that this method cannot be called if config has already been set to a
+ /// non-null value.
+ void setConfig(CallExpr *E) {
+ assert(!getConfig() &&
+ "Cannot call setConfig if config is not null");
+ setPreArg(CONFIG, E);
+ setInstantiationDependent(isInstantiationDependent() ||
+ E->isInstantiationDependent());
+ setContainsUnexpandedParameterPack(containsUnexpandedParameterPack() ||
+ E->containsUnexpandedParameterPack());
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CUDAKernelCallExprClass;
@@ -235,7 +245,9 @@
///
/// This expression node represents a C++ static cast, e.g.,
/// \c static_cast<int>(1.0).
-class CXXStaticCastExpr : public CXXNamedCastExpr {
+class CXXStaticCastExpr final
+ : public CXXNamedCastExpr,
+ private llvm::TrailingObjects<CXXStaticCastExpr, CXXBaseSpecifier *> {
CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op,
unsigned pathSize, TypeSourceInfo *writtenTy,
SourceLocation l, SourceLocation RParenLoc,
@@ -259,6 +271,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXStaticCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// \brief A C++ @c dynamic_cast expression (C++ [expr.dynamic.cast]).
@@ -266,7 +281,9 @@
/// This expression node represents a dynamic cast, e.g.,
/// \c dynamic_cast<Derived*>(BasePtr). Such a cast may perform a run-time
/// check to determine how to perform the type conversion.
-class CXXDynamicCastExpr : public CXXNamedCastExpr {
+class CXXDynamicCastExpr final
+ : public CXXNamedCastExpr,
+ private llvm::TrailingObjects<CXXDynamicCastExpr, CXXBaseSpecifier *> {
CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind,
Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy,
SourceLocation l, SourceLocation RParenLoc,
@@ -293,6 +310,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDynamicCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// \brief A C++ @c reinterpret_cast expression (C++ [expr.reinterpret.cast]).
@@ -303,7 +323,10 @@
/// A reinterpret_cast provides a differently-typed view of a value but
/// (in Clang, as in most C++ implementations) performs no actual work at
/// run time.
-class CXXReinterpretCastExpr : public CXXNamedCastExpr {
+class CXXReinterpretCastExpr final
+ : public CXXNamedCastExpr,
+ private llvm::TrailingObjects<CXXReinterpretCastExpr,
+ CXXBaseSpecifier *> {
CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind,
Expr *op, unsigned pathSize,
TypeSourceInfo *writtenTy, SourceLocation l,
@@ -328,6 +351,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXReinterpretCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// \brief A C++ \c const_cast expression (C++ [expr.const.cast]).
@@ -337,7 +363,9 @@
///
/// A const_cast can remove type qualifiers but does not change the underlying
/// value.
-class CXXConstCastExpr : public CXXNamedCastExpr {
+class CXXConstCastExpr final
+ : public CXXNamedCastExpr,
+ private llvm::TrailingObjects<CXXConstCastExpr, CXXBaseSpecifier *> {
CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op,
TypeSourceInfo *writtenTy, SourceLocation l,
SourceLocation RParenLoc, SourceRange AngleBrackets)
@@ -358,6 +386,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXConstCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// \brief A call to a literal operator (C++11 [over.literal])
@@ -377,7 +408,7 @@
UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
- : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
+ : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc),
UDSuffixLoc(SuffixLoc) {}
explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty)
: CallExpr(C, UserDefinedLiteralClass, Empty) {}
@@ -677,6 +708,69 @@
friend class ASTStmtReader;
};
+/// MS property subscript expression.
+/// MSVC supports 'property' attribute and allows to apply it to the
+/// declaration of an empty array in a class or structure definition.
+/// For example:
+/// \code
+/// __declspec(property(get=GetX, put=PutX)) int x[];
+/// \endcode
+/// The above statement indicates that x[] can be used with one or more array
+/// indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), and
+/// p->x[a][b] = i will be turned into p->PutX(a, b, i).
+/// This is a syntactic pseudo-object expression.
+class MSPropertySubscriptExpr : public Expr {
+ friend class ASTStmtReader;
+ enum { BASE_EXPR, IDX_EXPR, NUM_SUBEXPRS = 2 };
+ Stmt *SubExprs[NUM_SUBEXPRS];
+ SourceLocation RBracketLoc;
+
+ void setBase(Expr *Base) { SubExprs[BASE_EXPR] = Base; }
+ void setIdx(Expr *Idx) { SubExprs[IDX_EXPR] = Idx; }
+
+public:
+ MSPropertySubscriptExpr(Expr *Base, Expr *Idx, QualType Ty, ExprValueKind VK,
+ ExprObjectKind OK, SourceLocation RBracketLoc)
+ : Expr(MSPropertySubscriptExprClass, Ty, VK, OK, Idx->isTypeDependent(),
+ Idx->isValueDependent(), Idx->isInstantiationDependent(),
+ Idx->containsUnexpandedParameterPack()),
+ RBracketLoc(RBracketLoc) {
+ SubExprs[BASE_EXPR] = Base;
+ SubExprs[IDX_EXPR] = Idx;
+ }
+
+ /// \brief Create an empty array subscript expression.
+ explicit MSPropertySubscriptExpr(EmptyShell Shell)
+ : Expr(MSPropertySubscriptExprClass, Shell) {}
+
+ Expr *getBase() { return cast<Expr>(SubExprs[BASE_EXPR]); }
+ const Expr *getBase() const { return cast<Expr>(SubExprs[BASE_EXPR]); }
+
+ Expr *getIdx() { return cast<Expr>(SubExprs[IDX_EXPR]); }
+ const Expr *getIdx() const { return cast<Expr>(SubExprs[IDX_EXPR]); }
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getBase()->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; }
+
+ SourceLocation getRBracketLoc() const { return RBracketLoc; }
+ void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
+
+ SourceLocation getExprLoc() const LLVM_READONLY {
+ return getBase()->getExprLoc();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == MSPropertySubscriptExprClass;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(&SubExprs[0], &SubExprs[0] + NUM_SUBEXPRS);
+ }
+};
+
/// A Microsoft C++ @c __uuidof expression, which gets
/// the _GUID that corresponds to the supplied type or expression.
///
@@ -867,13 +961,9 @@
/// This wraps up a function call argument that was created from the
/// corresponding parameter's default argument, when the call did not
/// explicitly supply arguments for all of the parameters.
-class CXXDefaultArgExpr : public Expr {
+class CXXDefaultArgExpr final : public Expr {
/// \brief The parameter whose default is being used.
- ///
- /// When the bit is set, the subexpression is stored after the
- /// CXXDefaultArgExpr itself. When the bit is clear, the parameter's
- /// actual default expression is the subexpression.
- llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param;
+ ParmVarDecl *Param;
/// \brief The location where the default argument expression was used.
SourceLocation Loc;
@@ -885,16 +975,7 @@
: param->getDefaultArg()->getType(),
param->getDefaultArg()->getValueKind(),
param->getDefaultArg()->getObjectKind(), false, false, false, false),
- Param(param, false), Loc(Loc) { }
-
- CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param,
- Expr *SubExpr)
- : Expr(SC, SubExpr->getType(),
- SubExpr->getValueKind(), SubExpr->getObjectKind(),
- false, false, false, false),
- Param(param, true), Loc(Loc) {
- *reinterpret_cast<Expr **>(this + 1) = SubExpr;
- }
+ Param(param), Loc(Loc) { }
public:
CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
@@ -906,24 +987,15 @@
return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param);
}
- // \p Param is the parameter whose default argument is used by this
- // expression, and \p SubExpr is the expression that will actually be used.
- static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
- ParmVarDecl *Param, Expr *SubExpr);
-
// Retrieve the parameter that the argument was created from.
- const ParmVarDecl *getParam() const { return Param.getPointer(); }
- ParmVarDecl *getParam() { return Param.getPointer(); }
+ const ParmVarDecl *getParam() const { return Param; }
+ ParmVarDecl *getParam() { return Param; }
// Retrieve the actual argument to the function call.
const Expr *getExpr() const {
- if (Param.getInt())
- return *reinterpret_cast<Expr const * const*> (this + 1);
return getParam()->getDefaultArg();
}
Expr *getExpr() {
- if (Param.getInt())
- return *reinterpret_cast<Expr **> (this + 1);
return getParam()->getDefaultArg();
}
@@ -1250,7 +1322,9 @@
/// \code
/// x = int(0.5);
/// \endcode
-class CXXFunctionalCastExpr : public ExplicitCastExpr {
+class CXXFunctionalCastExpr final
+ : public ExplicitCastExpr,
+ private llvm::TrailingObjects<CXXFunctionalCastExpr, CXXBaseSpecifier *> {
SourceLocation LParenLoc;
SourceLocation RParenLoc;
@@ -1287,6 +1361,9 @@
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXFunctionalCastExprClass;
}
+
+ friend TrailingObjects;
+ friend class CastExpr;
};
/// @brief Represents a C++ functional cast expression that builds a
@@ -1352,7 +1429,9 @@
/// C++1y introduces a new form of "capture" called an init-capture that
/// includes an initializing expression (rather than capturing a variable),
/// and which can never occur implicitly.
-class LambdaExpr : public Expr {
+class LambdaExpr final
+ : public Expr,
+ private llvm::TrailingObjects<LambdaExpr, Stmt *, unsigned, VarDecl *> {
/// \brief The source range that covers the lambda introducer ([...]).
SourceRange IntroducerRange;
@@ -1387,23 +1466,21 @@
/// module file just to determine the source range.
SourceLocation ClosingBrace;
- // Note: The capture initializers are stored directly after the lambda
- // expression, along with the index variables used to initialize by-copy
- // array captures.
+ size_t numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumCaptures + 1;
+ }
- typedef LambdaCapture Capture;
+ size_t numTrailingObjects(OverloadToken<unsigned>) const {
+ return HasArrayIndexVars ? NumCaptures + 1 : 0;
+ }
/// \brief Construct a lambda expression.
LambdaExpr(QualType T, SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- SourceLocation CaptureDefaultLoc,
- ArrayRef<Capture> Captures,
- bool ExplicitParams,
- bool ExplicitResultType,
- ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts,
- SourceLocation ClosingBrace,
+ SourceLocation CaptureDefaultLoc, ArrayRef<LambdaCapture> Captures,
+ bool ExplicitParams, bool ExplicitResultType,
+ ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace,
bool ContainsUnexpandedParameterPack);
/// \brief Construct an empty lambda expression.
@@ -1414,53 +1491,35 @@
getStoredStmts()[NumCaptures] = nullptr;
}
- Stmt **getStoredStmts() { return reinterpret_cast<Stmt **>(this + 1); }
+ Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
- Stmt *const *getStoredStmts() const {
- return reinterpret_cast<Stmt *const *>(this + 1);
- }
+ Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); }
/// \brief Retrieve the mapping from captures to the first array index
/// variable.
- unsigned *getArrayIndexStarts() {
- return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1);
- }
+ unsigned *getArrayIndexStarts() { return getTrailingObjects<unsigned>(); }
const unsigned *getArrayIndexStarts() const {
- return reinterpret_cast<const unsigned *>(getStoredStmts() + NumCaptures +
- 1);
+ return getTrailingObjects<unsigned>();
}
/// \brief Retrieve the complete set of array-index variables.
- VarDecl **getArrayIndexVars() {
- unsigned ArrayIndexSize = llvm::RoundUpToAlignment(
- sizeof(unsigned) * (NumCaptures + 1), llvm::alignOf<VarDecl *>());
- return reinterpret_cast<VarDecl **>(
- reinterpret_cast<char *>(getArrayIndexStarts()) + ArrayIndexSize);
- }
+ VarDecl **getArrayIndexVars() { return getTrailingObjects<VarDecl *>(); }
VarDecl *const *getArrayIndexVars() const {
- unsigned ArrayIndexSize = llvm::RoundUpToAlignment(
- sizeof(unsigned) * (NumCaptures + 1), llvm::alignOf<VarDecl *>());
- return reinterpret_cast<VarDecl *const *>(
- reinterpret_cast<const char *>(getArrayIndexStarts()) + ArrayIndexSize);
+ return getTrailingObjects<VarDecl *>();
}
public:
/// \brief Construct a new lambda expression.
- static LambdaExpr *Create(const ASTContext &C,
- CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- LambdaCaptureDefault CaptureDefault,
- SourceLocation CaptureDefaultLoc,
- ArrayRef<Capture> Captures,
- bool ExplicitParams,
- bool ExplicitResultType,
- ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts,
- SourceLocation ClosingBrace,
- bool ContainsUnexpandedParameterPack);
+ static LambdaExpr *
+ Create(const ASTContext &C, CXXRecordDecl *Class, SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc,
+ ArrayRef<LambdaCapture> Captures, bool ExplicitParams,
+ bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts, SourceLocation ClosingBrace,
+ bool ContainsUnexpandedParameterPack);
/// \brief Construct a new lambda expression that will be deserialized from
/// an external source.
@@ -1483,7 +1542,7 @@
/// \brief An iterator that walks over the captures of the lambda,
/// both implicit and explicit.
- typedef const Capture *capture_iterator;
+ typedef const LambdaCapture *capture_iterator;
/// \brief An iterator over a range of lambda captures.
typedef llvm::iterator_range<capture_iterator> capture_range;
@@ -1533,14 +1592,12 @@
/// \brief Retrieve the initialization expressions for this lambda's captures.
llvm::iterator_range<capture_init_iterator> capture_inits() {
- return llvm::iterator_range<capture_init_iterator>(capture_init_begin(),
- capture_init_end());
+ return llvm::make_range(capture_init_begin(), capture_init_end());
}
/// \brief Retrieve the initialization expressions for this lambda's captures.
llvm::iterator_range<const_capture_init_iterator> capture_inits() const {
- return llvm::iterator_range<const_capture_init_iterator>(
- capture_init_begin(), capture_init_end());
+ return llvm::make_range(capture_init_begin(), capture_init_end());
}
/// \brief Retrieve the first initialization argument for this
@@ -1622,9 +1679,11 @@
SourceLocation getLocEnd() const LLVM_READONLY { return ClosingBrace; }
child_range children() {
+ // Includes initialization exprs plus body stmt
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1);
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -2139,7 +2198,9 @@
/// __is_enum(std::string) == false
/// __is_trivially_constructible(vector<int>, int*, int*)
/// \endcode
-class TypeTraitExpr : public Expr {
+class TypeTraitExpr final
+ : public Expr,
+ private llvm::TrailingObjects<TypeTraitExpr, TypeSourceInfo *> {
/// \brief The location of the type trait keyword.
SourceLocation Loc;
@@ -2156,16 +2217,10 @@
TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { }
- /// \brief Retrieve the argument types.
- TypeSourceInfo **getTypeSourceInfos() {
- return reinterpret_cast<TypeSourceInfo **>(this+1);
+ size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
+ return getNumArgs();
}
-
- /// \brief Retrieve the argument types.
- TypeSourceInfo * const *getTypeSourceInfos() const {
- return reinterpret_cast<TypeSourceInfo * const*>(this+1);
- }
-
+
public:
/// \brief Create a new type trait expression.
static TypeTraitExpr *Create(const ASTContext &C, QualType T,
@@ -2197,22 +2252,9 @@
}
/// \brief Retrieve the argument types.
- ArrayRef<TypeSourceInfo *> getArgs() const {
- return llvm::makeArrayRef(getTypeSourceInfos(), getNumArgs());
- }
-
- typedef TypeSourceInfo **arg_iterator;
- arg_iterator arg_begin() {
- return getTypeSourceInfos();
- }
- arg_iterator arg_end() {
- return getTypeSourceInfos() + getNumArgs();
- }
-
- typedef TypeSourceInfo const * const *arg_const_iterator;
- arg_const_iterator arg_begin() const { return getTypeSourceInfos(); }
- arg_const_iterator arg_end() const {
- return getTypeSourceInfos() + getNumArgs();
+ ArrayRef<TypeSourceInfo *> getArgs() const {
+ return llvm::makeArrayRef(getTrailingObjects<TypeSourceInfo *>(),
+ getNumArgs());
}
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
@@ -2227,9 +2269,9 @@
return child_range(child_iterator(), child_iterator());
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
-
};
/// \brief An Embarcadero array type trait, as used in the implementation of
@@ -2367,7 +2409,7 @@
/// \brief A reference to an overloaded function set, either an
/// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) OverloadExpr : public Expr {
+class OverloadExpr : public Expr {
/// \brief The common name of these declarations.
DeclarationNameInfo NameInfo;
@@ -2387,13 +2429,18 @@
bool HasTemplateKWAndArgsInfo;
/// \brief Return the optional template keyword and arguments info.
- ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo(); // defined far below.
+ ASTTemplateKWAndArgsInfo *
+ getTrailingASTTemplateKWAndArgsInfo(); // defined far below.
/// \brief Return the optional template keyword and arguments info.
- const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
- return const_cast<OverloadExpr*>(this)->getTemplateKWAndArgsInfo();
+ const ASTTemplateKWAndArgsInfo *getTrailingASTTemplateKWAndArgsInfo() const {
+ return const_cast<OverloadExpr *>(this)
+ ->getTrailingASTTemplateKWAndArgsInfo();
}
+ /// Return the optional template arguments.
+ TemplateArgumentLoc *getTrailingTemplateArgumentLoc(); // defined far below
+
OverloadExpr(StmtClass K, const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -2456,7 +2503,7 @@
return UnresolvedSetIterator(Results + NumResults);
}
llvm::iterator_range<decls_iterator> decls() const {
- return llvm::iterator_range<decls_iterator>(decls_begin(), decls_end());
+ return llvm::make_range(decls_begin(), decls_end());
}
/// \brief Gets the number of declarations in the unresolved set.
@@ -2484,21 +2531,21 @@
/// this name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ return getTrailingASTTemplateKWAndArgsInfo()->TemplateKWLoc;
}
/// \brief Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the name, if any.
SourceLocation getLAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->LAngleLoc;
+ return getTrailingASTTemplateKWAndArgsInfo()->LAngleLoc;
}
/// \brief Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the name, if any.
SourceLocation getRAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->RAngleLoc;
+ return getTrailingASTTemplateKWAndArgsInfo()->RAngleLoc;
}
/// \brief Determines whether the name was preceded by the template keyword.
@@ -2507,39 +2554,23 @@
/// \brief Determines whether this expression had explicit template arguments.
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
- // Note that, inconsistently with the explicit-template-argument AST
- // nodes, users are *forbidden* from calling these methods on objects
- // without explicit template arguments.
-
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *getTemplateKWAndArgsInfo();
- }
-
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs();
- }
-
TemplateArgumentLoc const *getTemplateArgs() const {
- return getExplicitTemplateArgs().getTemplateArgs();
+ if (!hasExplicitTemplateArgs())
+ return nullptr;
+ return const_cast<OverloadExpr *>(this)->getTrailingTemplateArgumentLoc();
}
unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs().NumTemplateArgs;
+ if (!hasExplicitTemplateArgs())
+ return 0;
+
+ return getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs;
}
/// \brief Copies the template arguments into the given structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs().copyInto(List);
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- ///
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
- if (!hasExplicitTemplateArgs()) return nullptr;
- return &getExplicitTemplateArgs();
+ if (hasExplicitTemplateArgs())
+ getTrailingASTTemplateKWAndArgsInfo()->copyInto(getTemplateArgs(), List);
}
static bool classof(const Stmt *T) {
@@ -2562,7 +2593,10 @@
///
/// These never include UnresolvedUsingValueDecls, which are always class
/// members and therefore appear only in UnresolvedMemberLookupExprs.
-class UnresolvedLookupExpr : public OverloadExpr {
+class UnresolvedLookupExpr final
+ : public OverloadExpr,
+ private llvm::TrailingObjects<
+ UnresolvedLookupExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
/// True if these lookup results should be extended by
/// argument-dependent lookup if this is the operand of a function
/// call.
@@ -2579,6 +2613,10 @@
/// against the qualified-lookup bits.
CXXRecordDecl *NamingClass;
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return HasTemplateKWAndArgsInfo ? 1 : 0;
+ }
+
UnresolvedLookupExpr(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
@@ -2598,6 +2636,8 @@
RequiresADL(false), Overloaded(false), NamingClass(nullptr)
{}
+ friend TrailingObjects;
+ friend class OverloadExpr;
friend class ASTStmtReader;
public:
@@ -2673,8 +2713,11 @@
/// qualifier (X<T>::) and the name of the entity being referenced
/// ("value"). Such expressions will instantiate to a DeclRefExpr once the
/// declaration can be found.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentScopeDeclRefExpr
- : public Expr {
+class DependentScopeDeclRefExpr final
+ : public Expr,
+ private llvm::TrailingObjects<DependentScopeDeclRefExpr,
+ ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc> {
/// \brief The nested-name-specifier that qualifies this unresolved
/// declaration name.
NestedNameSpecifierLoc QualifierLoc;
@@ -2686,15 +2729,8 @@
/// keyword and arguments.
bool HasTemplateKWAndArgsInfo;
- /// \brief Return the optional template keyword and arguments info.
- ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
- if (!HasTemplateKWAndArgsInfo) return nullptr;
- return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
- }
- /// \brief Return the optional template keyword and arguments info.
- const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
- return const_cast<DependentScopeDeclRefExpr*>(this)
- ->getTemplateKWAndArgsInfo();
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return HasTemplateKWAndArgsInfo ? 1 : 0;
}
DependentScopeDeclRefExpr(QualType T,
@@ -2739,21 +2775,21 @@
/// this name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// \brief Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the name, if any.
SourceLocation getLAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->LAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// \brief Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the name, if any.
SourceLocation getRAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->RAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
/// Determines whether the name was preceded by the template keyword.
@@ -2762,42 +2798,26 @@
/// Determines whether this lookup had explicit template arguments.
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
- // Note that, inconsistently with the explicit-template-argument AST
- // nodes, users are *forbidden* from calling these methods on objects
- // without explicit template arguments.
-
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
- }
-
- /// Gets a reference to the explicit template argument list.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- ///
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
- if (!hasExplicitTemplateArgs()) return nullptr;
- return &getExplicitTemplateArgs();
- }
-
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs().copyInto(List);
+ if (hasExplicitTemplateArgs())
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto(
+ getTrailingObjects<TemplateArgumentLoc>(), List);
}
TemplateArgumentLoc const *getTemplateArgs() const {
- return getExplicitTemplateArgs().getTemplateArgs();
+ if (!hasExplicitTemplateArgs())
+ return nullptr;
+
+ return getTrailingObjects<TemplateArgumentLoc>();
}
unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs().NumTemplateArgs;
+ if (!hasExplicitTemplateArgs())
+ return 0;
+
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
/// Note: getLocStart() is the start of the whole DependentScopeDeclRefExpr,
@@ -2819,6 +2839,7 @@
return child_range(child_iterator(), child_iterator());
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -2833,7 +2854,9 @@
/// This expression also tracks whether the sub-expression contains a
/// potentially-evaluated block literal. The lifetime of a block
/// literal is the extent of the enclosing scope.
-class ExprWithCleanups : public Expr {
+class ExprWithCleanups final
+ : public Expr,
+ private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> {
public:
/// The type of objects that are kept in the cleanup.
/// It's useful to remember the set of blocks; we could also
@@ -2847,12 +2870,7 @@
ExprWithCleanups(EmptyShell, unsigned NumObjects);
ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects);
- CleanupObject *getObjectsBuffer() {
- return reinterpret_cast<CleanupObject*>(this + 1);
- }
- const CleanupObject *getObjectsBuffer() const {
- return reinterpret_cast<const CleanupObject*>(this + 1);
- }
+ friend TrailingObjects;
friend class ASTStmtReader;
public:
@@ -2863,7 +2881,8 @@
ArrayRef<CleanupObject> objects);
ArrayRef<CleanupObject> getObjects() const {
- return llvm::makeArrayRef(getObjectsBuffer(), getNumObjects());
+ return llvm::makeArrayRef(getTrailingObjects<CleanupObject>(),
+ getNumObjects());
}
unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; }
@@ -2915,7 +2934,9 @@
/// When the returned expression is instantiated, it may resolve to a
/// constructor call, conversion function call, or some kind of type
/// conversion.
-class CXXUnresolvedConstructExpr : public Expr {
+class CXXUnresolvedConstructExpr final
+ : public Expr,
+ private llvm::TrailingObjects<CXXUnresolvedConstructExpr, Expr *> {
/// \brief The type being constructed.
TypeSourceInfo *Type;
@@ -2936,6 +2957,7 @@
CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs)
: Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { }
+ friend TrailingObjects;
friend class ASTStmtReader;
public:
@@ -2970,13 +2992,11 @@
unsigned arg_size() const { return NumArgs; }
typedef Expr** arg_iterator;
- arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); }
+ arg_iterator arg_begin() { return getTrailingObjects<Expr *>(); }
arg_iterator arg_end() { return arg_begin() + NumArgs; }
typedef const Expr* const * const_arg_iterator;
- const_arg_iterator arg_begin() const {
- return reinterpret_cast<const Expr* const *>(this + 1);
- }
+ const_arg_iterator arg_begin() const { return getTrailingObjects<Expr *>(); }
const_arg_iterator arg_end() const {
return arg_begin() + NumArgs;
}
@@ -3009,7 +3029,7 @@
// Iterators
child_range children() {
- Stmt **begin = reinterpret_cast<Stmt**>(this+1);
+ Stmt **begin = reinterpret_cast<Stmt **>(arg_begin());
return child_range(begin, begin + NumArgs);
}
};
@@ -3021,8 +3041,11 @@
/// Like UnresolvedMemberExprs, these can be either implicit or
/// explicit accesses. It is only possible to get one of these with
/// an implicit access if a qualifier is provided.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) CXXDependentScopeMemberExpr
- : public Expr {
+class CXXDependentScopeMemberExpr final
+ : public Expr,
+ private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
+ ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc> {
/// \brief The expression for the base pointer or class reference,
/// e.g., the \c x in x.f. Can be null in implicit accesses.
Stmt *Base;
@@ -3060,15 +3083,8 @@
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
- /// \brief Return the optional template keyword and arguments info.
- ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
- if (!HasTemplateKWAndArgsInfo) return nullptr;
- return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
- }
- /// \brief Return the optional template keyword and arguments info.
- const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
- return const_cast<CXXDependentScopeMemberExpr*>(this)
- ->getTemplateKWAndArgsInfo();
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return HasTemplateKWAndArgsInfo ? 1 : 0;
}
CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base,
@@ -3164,21 +3180,21 @@
/// member name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// \brief Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the member name, if any.
SourceLocation getLAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->LAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// \brief Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the member name, if any.
SourceLocation getRAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
- return getTemplateKWAndArgsInfo()->RAngleLoc;
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}
/// Determines whether the member name was preceded by the template keyword.
@@ -3188,50 +3204,30 @@
/// template argument list explicitly specified, e.g., x.f<int>.
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name, if any.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
- }
-
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name, if any.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- return const_cast<CXXDependentScopeMemberExpr *>(this)
- ->getExplicitTemplateArgs();
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- ///
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
- if (!hasExplicitTemplateArgs()) return nullptr;
- return &getExplicitTemplateArgs();
- }
-
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs().copyInto(List);
- }
-
- /// \brief Initializes the template arguments using the given structure.
- void initializeTemplateArgumentsFrom(const TemplateArgumentListInfo &List) {
- getExplicitTemplateArgs().initializeFrom(List);
+ if (hasExplicitTemplateArgs())
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->copyInto(
+ getTrailingObjects<TemplateArgumentLoc>(), List);
}
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
- return getExplicitTemplateArgs().getTemplateArgs();
+ if (!hasExplicitTemplateArgs())
+ return nullptr;
+
+ return getTrailingObjects<TemplateArgumentLoc>();
}
/// \brief Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs().NumTemplateArgs;
+ if (!hasExplicitTemplateArgs())
+ return 0;
+
+ return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
SourceLocation getLocStart() const LLVM_READONLY {
@@ -3240,8 +3236,8 @@
if (getQualifier())
return getQualifierLoc().getBeginLoc();
return MemberNameInfo.getBeginLoc();
-
}
+
SourceLocation getLocEnd() const LLVM_READONLY {
if (hasExplicitTemplateArgs())
return getRAngleLoc();
@@ -3259,6 +3255,7 @@
return child_range(&Base, &Base + 1);
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -3278,8 +3275,10 @@
/// In the final AST, an explicit access always becomes a MemberExpr.
/// An implicit access may become either a MemberExpr or a
/// DeclRefExpr, depending on whether the member is static.
-class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) UnresolvedMemberExpr
- : public OverloadExpr {
+class UnresolvedMemberExpr final
+ : public OverloadExpr,
+ private llvm::TrailingObjects<
+ UnresolvedMemberExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
/// \brief Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow : 1;
@@ -3300,6 +3299,10 @@
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
+ size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
+ return HasTemplateKWAndArgsInfo ? 1 : 0;
+ }
+
UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
@@ -3313,6 +3316,8 @@
: OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false),
HasUnresolvedUsing(false), Base(nullptr) { }
+ friend TrailingObjects;
+ friend class OverloadExpr;
friend class ASTStmtReader;
public:
@@ -3404,15 +3409,26 @@
}
};
-inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() {
+inline ASTTemplateKWAndArgsInfo *
+OverloadExpr::getTrailingASTTemplateKWAndArgsInfo() {
if (!HasTemplateKWAndArgsInfo)
return nullptr;
+
if (isa<UnresolvedLookupExpr>(this))
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
- cast<UnresolvedLookupExpr>(this) + 1);
+ return cast<UnresolvedLookupExpr>(this)
+ ->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
else
- return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
- cast<UnresolvedMemberExpr>(this) + 1);
+ return cast<UnresolvedMemberExpr>(this)
+ ->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
+}
+
+inline TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() {
+ if (isa<UnresolvedLookupExpr>(this))
+ return cast<UnresolvedLookupExpr>(this)
+ ->getTrailingObjects<TemplateArgumentLoc>();
+ else
+ return cast<UnresolvedMemberExpr>(this)
+ ->getTrailingObjects<TemplateArgumentLoc>();
}
/// \brief Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
@@ -3546,7 +3562,9 @@
/// static const unsigned value = sizeof...(Types);
/// };
/// \endcode
-class SizeOfPackExpr : public Expr {
+class SizeOfPackExpr final
+ : public Expr,
+ private llvm::TrailingObjects<SizeOfPackExpr, TemplateArgument> {
/// \brief The location of the \c sizeof keyword.
SourceLocation OperatorLoc;
@@ -3571,6 +3589,7 @@
/// \brief The parameter pack.
NamedDecl *Pack;
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -3587,7 +3606,7 @@
Length(Length ? *Length : PartialArgs.size()), Pack(Pack) {
assert((!Length || PartialArgs.empty()) &&
"have partial args for non-dependent sizeof... expression");
- TemplateArgument *Args = reinterpret_cast<TemplateArgument *>(this + 1);
+ TemplateArgument *Args = getTrailingObjects<TemplateArgument>();
std::uninitialized_copy(PartialArgs.begin(), PartialArgs.end(), Args);
}
@@ -3638,8 +3657,7 @@
/// \brief Get
ArrayRef<TemplateArgument> getPartialArguments() const {
assert(isPartiallySubstituted());
- const TemplateArgument *Args =
- reinterpret_cast<const TemplateArgument *>(this + 1);
+ const TemplateArgument *Args = getTrailingObjects<TemplateArgument>();
return llvm::makeArrayRef(Args, Args + Length);
}
@@ -3775,7 +3793,9 @@
/// };
/// template struct S<int, int>;
/// \endcode
-class FunctionParmPackExpr : public Expr {
+class FunctionParmPackExpr final
+ : public Expr,
+ private llvm::TrailingObjects<FunctionParmPackExpr, ParmVarDecl *> {
/// \brief The function parameter pack which was referenced.
ParmVarDecl *ParamPack;
@@ -3789,6 +3809,7 @@
SourceLocation NameLoc, unsigned NumParams,
ParmVarDecl *const *Params);
+ friend TrailingObjects;
friend class ASTReader;
friend class ASTStmtReader;
@@ -3809,7 +3830,7 @@
/// \brief Iterators over the parameters which the parameter pack expanded
/// into.
typedef ParmVarDecl * const *iterator;
- iterator begin() const { return reinterpret_cast<iterator>(this+1); }
+ iterator begin() const { return getTrailingObjects<ParmVarDecl *>(); }
iterator end() const { return begin() + NumParameters; }
/// \brief Get the number of parameters in this parameter pack.
@@ -4008,65 +4029,61 @@
child_range children() { return child_range(SubExprs, SubExprs + 2); }
};
-/// \brief Represents a 'co_await' expression. This expression checks whether its
-/// operand is ready, and suspends the coroutine if not. Then (after the resume
-/// if suspended) it resumes the coroutine and extracts the value from the
-/// operand. This implies making four calls:
+/// \brief Represents an expression that might suspend coroutine execution;
+/// either a co_await or co_yield expression.
///
-/// <operand>.operator co_await() or operator co_await(<operand>)
-/// <result>.await_ready()
-/// <result>.await_suspend(h)
-/// <result>.await_resume()
-///
-/// where h is a handle to the coroutine, and <result> is the result of calling
-/// operator co_await() if it exists or the original operand otherwise.
-///
-/// Note that the coroutine is prepared for suspension before the 'await_suspend'
-/// call, but resumes after that call, which may cause parts of the
-/// 'await_suspend' expression to occur much later than expected.
-class CoawaitExpr : public Expr {
- SourceLocation CoawaitLoc;
+/// Evaluation of this expression first evaluates its 'ready' expression. If
+/// that returns 'false':
+/// -- execution of the coroutine is suspended
+/// -- the 'suspend' expression is evaluated
+/// -- if the 'suspend' expression returns 'false', the coroutine is
+/// resumed
+/// -- otherwise, control passes back to the resumer.
+/// If the coroutine is not suspended, or when it is resumed, the 'resume'
+/// expression is evaluated, and its result is the result of the overall
+/// expression.
+class CoroutineSuspendExpr : public Expr {
+ SourceLocation KeywordLoc;
- enum SubExpr { Operand, Ready, Suspend, Resume, Count };
+ enum SubExpr { Common, Ready, Suspend, Resume, Count };
Stmt *SubExprs[SubExpr::Count];
friend class ASTStmtReader;
public:
- CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
- Expr *Suspend, Expr *Resume)
- : Expr(CoawaitExprClass, Resume->getType(), Resume->getValueKind(),
- Resume->getObjectKind(),
- Resume->isTypeDependent(),
- Resume->isValueDependent(),
- Operand->isInstantiationDependent(),
- Operand->containsUnexpandedParameterPack()),
- CoawaitLoc(CoawaitLoc) {
- SubExprs[CoawaitExpr::Operand] = Operand;
- SubExprs[CoawaitExpr::Ready] = Ready;
- SubExprs[CoawaitExpr::Suspend] = Suspend;
- SubExprs[CoawaitExpr::Resume] = Resume;
+ CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common,
+ Expr *Ready, Expr *Suspend, Expr *Resume)
+ : Expr(SC, Resume->getType(), Resume->getValueKind(),
+ Resume->getObjectKind(), Resume->isTypeDependent(),
+ Resume->isValueDependent(), Common->isInstantiationDependent(),
+ Common->containsUnexpandedParameterPack()),
+ KeywordLoc(KeywordLoc) {
+ SubExprs[SubExpr::Common] = Common;
+ SubExprs[SubExpr::Ready] = Ready;
+ SubExprs[SubExpr::Suspend] = Suspend;
+ SubExprs[SubExpr::Resume] = Resume;
}
- CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
- : Expr(CoawaitExprClass, Ty, VK_RValue, OK_Ordinary,
- true, true, true, Operand->containsUnexpandedParameterPack()),
- CoawaitLoc(CoawaitLoc) {
- assert(Operand->isTypeDependent() && Ty->isDependentType() &&
- "wrong constructor for non-dependent co_await expression");
- SubExprs[CoawaitExpr::Operand] = Operand;
- SubExprs[CoawaitExpr::Ready] = nullptr;
- SubExprs[CoawaitExpr::Suspend] = nullptr;
- SubExprs[CoawaitExpr::Resume] = nullptr;
+ CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, QualType Ty,
+ Expr *Common)
+ : Expr(SC, Ty, VK_RValue, OK_Ordinary, true, true, true,
+ Common->containsUnexpandedParameterPack()),
+ KeywordLoc(KeywordLoc) {
+ assert(Common->isTypeDependent() && Ty->isDependentType() &&
+ "wrong constructor for non-dependent co_await/co_yield expression");
+ SubExprs[SubExpr::Common] = Common;
+ SubExprs[SubExpr::Ready] = nullptr;
+ SubExprs[SubExpr::Suspend] = nullptr;
+ SubExprs[SubExpr::Resume] = nullptr;
}
- CoawaitExpr(EmptyShell Empty) : Expr(CoawaitExprClass, Empty) {
- SubExprs[CoawaitExpr::Operand] = nullptr;
- SubExprs[CoawaitExpr::Ready] = nullptr;
- SubExprs[CoawaitExpr::Suspend] = nullptr;
- SubExprs[CoawaitExpr::Resume] = nullptr;
+ CoroutineSuspendExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {
+ SubExprs[SubExpr::Common] = nullptr;
+ SubExprs[SubExpr::Ready] = nullptr;
+ SubExprs[SubExpr::Suspend] = nullptr;
+ SubExprs[SubExpr::Resume] = nullptr;
}
- SourceLocation getKeywordLoc() const { return CoawaitLoc; }
- Expr *getOperand() const {
- return static_cast<Expr*>(SubExprs[SubExpr::Operand]);
+ SourceLocation getKeywordLoc() const { return KeywordLoc; }
+ Expr *getCommonExpr() const {
+ return static_cast<Expr*>(SubExprs[SubExpr::Common]);
}
Expr *getReadyExpr() const {
@@ -4080,10 +4097,10 @@
}
SourceLocation getLocStart() const LLVM_READONLY {
- return CoawaitLoc;
+ return KeywordLoc;
}
SourceLocation getLocEnd() const LLVM_READONLY {
- return getOperand()->getLocEnd();
+ return getCommonExpr()->getLocEnd();
}
child_range children() {
@@ -4091,52 +4108,50 @@
}
static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CoawaitExprClass ||
+ T->getStmtClass() == CoyieldExprClass;
+ }
+};
+
+/// \brief Represents a 'co_await' expression.
+class CoawaitExpr : public CoroutineSuspendExpr {
+ friend class ASTStmtReader;
+public:
+ CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
+ Expr *Suspend, Expr *Resume)
+ : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready,
+ Suspend, Resume) {}
+ CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
+ : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {}
+ CoawaitExpr(EmptyShell Empty)
+ : CoroutineSuspendExpr(CoawaitExprClass, Empty) {}
+
+ Expr *getOperand() const {
+ // FIXME: Dig out the actual operand or store it.
+ return getCommonExpr();
+ }
+
+ static bool classof(const Stmt *T) {
return T->getStmtClass() == CoawaitExprClass;
}
};
-/// \brief Represents a 'co_yield' expression. This expression provides a value
-/// to the coroutine promise and optionally suspends the coroutine. This implies
-/// a making call to <promise>.yield_value(<operand>), which we name the "promise
-/// call".
-class CoyieldExpr : public Expr {
- SourceLocation CoyieldLoc;
-
- /// The operand of the 'co_yield' expression.
- Stmt *Operand;
- /// The implied call to the promise object. May be null if the
- /// coroutine has not yet been finalized.
- Stmt *PromiseCall;
-
+/// \brief Represents a 'co_yield' expression.
+class CoyieldExpr : public CoroutineSuspendExpr {
friend class ASTStmtReader;
public:
- CoyieldExpr(SourceLocation CoyieldLoc, QualType Void, Expr *Operand)
- : Expr(CoyieldExprClass, Void, VK_RValue, OK_Ordinary, false, false,
- Operand->isInstantiationDependent(),
- Operand->containsUnexpandedParameterPack()),
- CoyieldLoc(CoyieldLoc), Operand(Operand), PromiseCall(nullptr) {}
- CoyieldExpr(EmptyShell Empty) : Expr(CoyieldExprClass, Empty) {}
+ CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready,
+ Expr *Suspend, Expr *Resume)
+ : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready,
+ Suspend, Resume) {}
+ CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand)
+ : CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {}
+ CoyieldExpr(EmptyShell Empty)
+ : CoroutineSuspendExpr(CoyieldExprClass, Empty) {}
- SourceLocation getKeywordLoc() const { return CoyieldLoc; }
- Expr *getOperand() const { return static_cast<Expr*>(Operand); }
-
- /// \brief Get the call to the promise objet that is implied by an evaluation
- /// of this expression. Will be nullptr if the coroutine has not yet been
- /// finalized.
- Expr *getPromiseCall() const { return static_cast<Expr*>(PromiseCall); }
-
- /// \brief Set the resolved promise call. This is delayed until the
- /// complete coroutine body has been parsed and the promise type is known.
- void finalize(Stmt *PC) { PromiseCall = PC; }
-
- SourceLocation getLocStart() const LLVM_READONLY { return CoyieldLoc; }
- SourceLocation getLocEnd() const LLVM_READONLY {
- return Operand->getLocEnd();
- }
-
- child_range children() {
- Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
- return child_range(Which, Which + 1);
+ Expr *getOperand() const {
+ // FIXME: Dig out the actual operand or store it.
+ return getCommonExpr();
}
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index a1da0f4..61e6383 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -141,15 +141,17 @@
/// ObjCArrayLiteral - used for objective-c array containers; as in:
/// @[@"Hello", NSApp, [NSNumber numberWithInt:42]];
-class ObjCArrayLiteral : public Expr {
+class ObjCArrayLiteral final
+ : public Expr,
+ private llvm::TrailingObjects<ObjCArrayLiteral, Expr *> {
unsigned NumElements;
SourceRange Range;
ObjCMethodDecl *ArrayWithObjectsMethod;
-
+
ObjCArrayLiteral(ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR);
-
+
explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements)
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
@@ -171,11 +173,11 @@
}
/// \brief Retrieve elements of array of literals.
- Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
+ Expr **getElements() { return getTrailingObjects<Expr *>(); }
/// \brief Retrieve elements of array of literals.
- const Expr * const *getElements() const {
- return reinterpret_cast<const Expr * const*>(this + 1);
+ const Expr * const *getElements() const {
+ return getTrailingObjects<Expr *>();
}
/// getNumElements - Return number of elements of objective-c array literal.
@@ -196,11 +198,12 @@
}
// Iterators
- child_range children() {
- return child_range((Stmt **)getElements(),
- (Stmt **)getElements() + NumElements);
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(getElements()),
+ reinterpret_cast<Stmt **>(getElements()) + NumElements);
}
-
+
+ friend TrailingObjects;
friend class ASTStmtReader;
};
@@ -230,32 +233,35 @@
}
namespace clang {
-/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary
+/// \brief Internal struct for storing Key/value pair.
+struct ObjCDictionaryLiteral_KeyValuePair {
+ Expr *Key;
+ Expr *Value;
+};
+
+/// \brief Internal struct to describes an element that is a pack
+/// expansion, used if any of the elements in the dictionary literal
+/// are pack expansions.
+struct ObjCDictionaryLiteral_ExpansionData {
+ /// \brief The location of the ellipsis, if this element is a pack
+ /// expansion.
+ SourceLocation EllipsisLoc;
+
+ /// \brief If non-zero, the number of elements that this pack
+ /// expansion will expand to (+1).
+ unsigned NumExpansionsPlusOne;
+};
+
+/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary
/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] };
-class ObjCDictionaryLiteral : public Expr {
- /// \brief Key/value pair used to store the key and value of a given element.
- ///
- /// Objects of this type are stored directly after the expression.
- struct KeyValuePair {
- Expr *Key;
- Expr *Value;
- };
-
- /// \brief Data that describes an element that is a pack expansion, used if any
- /// of the elements in the dictionary literal are pack expansions.
- struct ExpansionData {
- /// \brief The location of the ellipsis, if this element is a pack
- /// expansion.
- SourceLocation EllipsisLoc;
-
- /// \brief If non-zero, the number of elements that this pack
- /// expansion will expand to (+1).
- unsigned NumExpansionsPlusOne;
- };
-
+class ObjCDictionaryLiteral final
+ : public Expr,
+ private llvm::TrailingObjects<ObjCDictionaryLiteral,
+ ObjCDictionaryLiteral_KeyValuePair,
+ ObjCDictionaryLiteral_ExpansionData> {
/// \brief The number of elements in this dictionary literal.
unsigned NumElements : 31;
-
+
/// \brief Determine whether this dictionary literal has any pack expansions.
///
/// If the dictionary literal has pack expansions, then there will
@@ -264,10 +270,17 @@
/// any) and number of elements in the expansion (if known). If
/// there are no pack expansions, we optimize away this storage.
unsigned HasPackExpansions : 1;
-
+
SourceRange Range;
ObjCMethodDecl *DictWithObjectsMethod;
-
+
+ typedef ObjCDictionaryLiteral_KeyValuePair KeyValuePair;
+ typedef ObjCDictionaryLiteral_ExpansionData ExpansionData;
+
+ size_t numTrailingObjects(OverloadToken<KeyValuePair>) const {
+ return NumElements;
+ }
+
ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions,
QualType T, ObjCMethodDecl *method,
@@ -278,28 +291,6 @@
: Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements),
HasPackExpansions(HasPackExpansions) {}
- KeyValuePair *getKeyValues() {
- return reinterpret_cast<KeyValuePair *>(this + 1);
- }
-
- const KeyValuePair *getKeyValues() const {
- return reinterpret_cast<const KeyValuePair *>(this + 1);
- }
-
- ExpansionData *getExpansionData() {
- if (!HasPackExpansions)
- return nullptr;
-
- return reinterpret_cast<ExpansionData *>(getKeyValues() + NumElements);
- }
-
- const ExpansionData *getExpansionData() const {
- if (!HasPackExpansions)
- return nullptr;
-
- return reinterpret_cast<const ExpansionData *>(getKeyValues()+NumElements);
- }
-
public:
static ObjCDictionaryLiteral *Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK,
@@ -317,10 +308,11 @@
ObjCDictionaryElement getKeyValueElement(unsigned Index) const {
assert((Index < NumElements) && "Arg access out of range!");
- const KeyValuePair &KV = getKeyValues()[Index];
+ const KeyValuePair &KV = getTrailingObjects<KeyValuePair>()[Index];
ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(), None };
if (HasPackExpansions) {
- const ExpansionData &Expansion = getExpansionData()[Index];
+ const ExpansionData &Expansion =
+ getTrailingObjects<ExpansionData>()[Index];
Result.EllipsisLoc = Expansion.EllipsisLoc;
if (Expansion.NumExpansionsPlusOne > 0)
Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1;
@@ -340,17 +332,20 @@
}
// Iterators
- child_range children() {
+ child_range children() {
// Note: we're taking advantage of the layout of the KeyValuePair struct
// here. If that struct changes, this code will need to change as well.
static_assert(sizeof(KeyValuePair) == sizeof(Stmt *) * 2,
"KeyValuePair is expected size");
- return child_range(reinterpret_cast<Stmt **>(this + 1),
- reinterpret_cast<Stmt **>(this + 1) + NumElements * 2);
+ return child_range(
+ reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()),
+ reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()) +
+ NumElements * 2);
}
friend class ASTStmtReader;
friend class ASTStmtWriter;
+ friend TrailingObjects;
};
@@ -797,13 +792,6 @@
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
: Expr(ObjCSubscriptRefExprClass, Empty) {}
- static ObjCSubscriptRefExpr *Create(const ASTContext &C,
- Expr *base,
- Expr *key, QualType T,
- ObjCMethodDecl *getMethod,
- ObjCMethodDecl *setMethod,
- SourceLocation RB);
-
SourceLocation getRBracket() const { return RBracket; }
void setRBracket(SourceLocation RB) { RBracket = RB; }
@@ -865,7 +853,13 @@
/// All four kinds of message sends are modeled by the ObjCMessageExpr
/// class, and can be distinguished via \c getReceiverKind(). Example:
///
-class ObjCMessageExpr : public Expr {
+/// The "void *" trailing objects are actually ONE void * (the
+/// receiver pointer), and NumArgs Expr *. But due to the
+/// implementation of children(), these must be together contiguously.
+
+class ObjCMessageExpr final
+ : public Expr,
+ private llvm::TrailingObjects<ObjCMessageExpr, void *, SourceLocation> {
/// \brief Stores either the selector that this message is sending
/// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
/// referring to the method that we type-checked against.
@@ -877,11 +871,6 @@
/// including the receiver.
unsigned NumArgs : NumArgsBitWidth;
- void setNumArgs(unsigned Num) {
- assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!");
- NumArgs = Num;
- }
-
/// \brief The kind of message send this is, which is one of the
/// ReceiverKind values.
///
@@ -915,6 +904,13 @@
/// brackets ('[' and ']', respectively).
SourceLocation LBracLoc, RBracLoc;
+ size_t numTrailingObjects(OverloadToken<void *>) const { return NumArgs + 1; }
+
+ void setNumArgs(unsigned Num) {
+ assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!");
+ NumArgs = Num;
+ }
+
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
: Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0),
HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) {
@@ -959,14 +955,11 @@
SelectorLocationsKind SelLocsK);
/// \brief Retrieve the pointer value of the message receiver.
- void *getReceiverPointer() const {
- return *const_cast<void **>(
- reinterpret_cast<const void * const*>(this + 1));
- }
+ void *getReceiverPointer() const { return *getTrailingObjects<void *>(); }
/// \brief Set the pointer value of the message receiver.
void setReceiverPointer(void *Value) {
- *reinterpret_cast<void **>(this + 1) = Value;
+ *getTrailingObjects<void *>() = Value;
}
SelectorLocationsKind getSelLocsKind() const {
@@ -979,10 +972,10 @@
/// \brief Get a pointer to the stored selector identifiers locations array.
/// No locations will be stored if HasStandardSelLocs is true.
SourceLocation *getStoredSelLocs() {
- return reinterpret_cast<SourceLocation*>(getArgs() + getNumArgs());
+ return getTrailingObjects<SourceLocation>();
}
const SourceLocation *getStoredSelLocs() const {
- return reinterpret_cast<const SourceLocation*>(getArgs() + getNumArgs());
+ return getTrailingObjects<SourceLocation>();
}
/// \brief Get the number of stored selector identifiers locations.
@@ -1286,20 +1279,21 @@
/// \brief Retrieve the arguments to this message, not including the
/// receiver.
Expr **getArgs() {
- return reinterpret_cast<Expr **>(this + 1) + 1;
+ return reinterpret_cast<Expr **>(getTrailingObjects<void *>() + 1);
}
const Expr * const *getArgs() const {
- return reinterpret_cast<const Expr * const *>(this + 1) + 1;
+ return reinterpret_cast<const Expr *const *>(getTrailingObjects<void *>() +
+ 1);
}
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(getArgs()[Arg]);
+ return getArgs()[Arg];
}
const Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(getArgs()[Arg]);
+ return getArgs()[Arg];
}
/// setArg - Set the specified argument.
void setArg(unsigned Arg, Expr *ArgExpr) {
@@ -1379,6 +1373,7 @@
return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs);
}
+ friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -1521,11 +1516,15 @@
/// \code
/// NSString *str = (__bridge_transfer NSString *)CFCreateString();
/// \endcode
-class ObjCBridgedCastExpr : public ExplicitCastExpr {
+class ObjCBridgedCastExpr final
+ : public ExplicitCastExpr,
+ private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> {
SourceLocation LParenLoc;
SourceLocation BridgeKeywordLoc;
unsigned Kind : 2;
-
+
+ friend TrailingObjects;
+ friend class CastExpr;
friend class ASTStmtReader;
friend class ASTStmtWriter;
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index 7b725b6..4872738 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -216,9 +216,6 @@
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBIndex, raw_ostream &Out) = 0;
- virtual void mangleCXXCatchHandlerType(QualType T, uint32_t Flags,
- raw_ostream &Out) = 0;
-
virtual void mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0;
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 4da17b0..b1ff9bd 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -217,7 +217,8 @@
/// \brief Dump the nested name specifier to standard output to aid
/// in debugging.
- void dump(const LangOptions &LO);
+ void dump(const LangOptions &LO) const;
+ void dump() const;
};
/// \brief A C++ nested-name-specifier augmented with source location
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 648feb1..1275b7f 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -84,21 +84,15 @@
/// \brief Fetches list of variables associated with this clause.
MutableArrayRef<Expr *> getVarRefs() {
return MutableArrayRef<Expr *>(
- reinterpret_cast<Expr **>(
- reinterpret_cast<char *>(this) +
- llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<Expr *>())),
- NumVars);
+ static_cast<T *>(this)->template getTrailingObjects<Expr *>(), NumVars);
}
/// \brief Sets the list of variables for this clause.
void setVarRefs(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- std::copy(
- VL.begin(), VL.end(),
- reinterpret_cast<Expr **>(
- reinterpret_cast<char *>(this) +
- llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<Expr *>())));
+ std::copy(VL.begin(), VL.end(),
+ static_cast<T *>(this)->template getTrailingObjects<Expr *>());
}
/// \brief Build a clause with \a N variables
@@ -142,9 +136,7 @@
/// \brief Fetches list of all variables in the clause.
ArrayRef<const Expr *> getVarRefs() const {
return llvm::makeArrayRef(
- reinterpret_cast<const Expr *const *>(
- reinterpret_cast<const char *>(this) +
- llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<const Expr *>())),
+ static_cast<const T *>(this)->template getTrailingObjects<Expr *>(),
NumVars);
}
};
@@ -664,6 +656,11 @@
SourceLocation LParenLoc;
/// \brief A kind of the 'schedule' clause.
OpenMPScheduleClauseKind Kind;
+ /// \brief Modifiers for 'schedule' clause.
+ enum {FIRST, SECOND, NUM_MODIFIERS};
+ OpenMPScheduleClauseModifier Modifiers[NUM_MODIFIERS];
+ /// \brief Locations of modifiers.
+ SourceLocation ModifiersLoc[NUM_MODIFIERS];
/// \brief Start location of the schedule ind in source code.
SourceLocation KindLoc;
/// \brief Location of ',' (if any).
@@ -678,6 +675,42 @@
/// \param K Schedule kind.
///
void setScheduleKind(OpenMPScheduleClauseKind K) { Kind = K; }
+ /// \brief Set the first schedule modifier.
+ ///
+ /// \param M Schedule modifier.
+ ///
+ void setFirstScheduleModifier(OpenMPScheduleClauseModifier M) {
+ Modifiers[FIRST] = M;
+ }
+ /// \brief Set the second schedule modifier.
+ ///
+ /// \param M Schedule modifier.
+ ///
+ void setSecondScheduleModifier(OpenMPScheduleClauseModifier M) {
+ Modifiers[SECOND] = M;
+ }
+ /// \brief Set location of the first schedule modifier.
+ ///
+ void setFirstScheduleModifierLoc(SourceLocation Loc) {
+ ModifiersLoc[FIRST] = Loc;
+ }
+ /// \brief Set location of the second schedule modifier.
+ ///
+ void setSecondScheduleModifierLoc(SourceLocation Loc) {
+ ModifiersLoc[SECOND] = Loc;
+ }
+ /// \brief Set schedule modifier location.
+ ///
+ /// \param M Schedule modifier location.
+ ///
+ void setScheduleModifer(OpenMPScheduleClauseModifier M) {
+ if (Modifiers[FIRST] == OMPC_SCHEDULE_MODIFIER_unknown)
+ Modifiers[FIRST] = M;
+ else {
+ assert(Modifiers[SECOND] == OMPC_SCHEDULE_MODIFIER_unknown);
+ Modifiers[SECOND] = M;
+ }
+ }
/// \brief Sets the location of '('.
///
/// \param Loc Location of '('.
@@ -716,15 +749,25 @@
/// \param Kind Schedule kind.
/// \param ChunkSize Chunk size.
/// \param HelperChunkSize Helper chunk size for combined directives.
+ /// \param M1 The first modifier applied to 'schedule' clause.
+ /// \param M1Loc Location of the first modifier
+ /// \param M2 The second modifier applied to 'schedule' clause.
+ /// \param M2Loc Location of the second modifier
///
OMPScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation KLoc, SourceLocation CommaLoc,
SourceLocation EndLoc, OpenMPScheduleClauseKind Kind,
- Expr *ChunkSize, Expr *HelperChunkSize)
+ Expr *ChunkSize, Expr *HelperChunkSize,
+ OpenMPScheduleClauseModifier M1, SourceLocation M1Loc,
+ OpenMPScheduleClauseModifier M2, SourceLocation M2Loc)
: OMPClause(OMPC_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc),
Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc) {
ChunkSizes[CHUNK_SIZE] = ChunkSize;
ChunkSizes[HELPER_CHUNK_SIZE] = HelperChunkSize;
+ Modifiers[FIRST] = M1;
+ Modifiers[SECOND] = M2;
+ ModifiersLoc[FIRST] = M1Loc;
+ ModifiersLoc[SECOND] = M2Loc;
}
/// \brief Build an empty clause.
@@ -734,17 +777,39 @@
Kind(OMPC_SCHEDULE_unknown) {
ChunkSizes[CHUNK_SIZE] = nullptr;
ChunkSizes[HELPER_CHUNK_SIZE] = nullptr;
+ Modifiers[FIRST] = OMPC_SCHEDULE_MODIFIER_unknown;
+ Modifiers[SECOND] = OMPC_SCHEDULE_MODIFIER_unknown;
}
/// \brief Get kind of the clause.
///
OpenMPScheduleClauseKind getScheduleKind() const { return Kind; }
+ /// \brief Get the first modifier of the clause.
+ ///
+ OpenMPScheduleClauseModifier getFirstScheduleModifier() const {
+ return Modifiers[FIRST];
+ }
+ /// \brief Get the second modifier of the clause.
+ ///
+ OpenMPScheduleClauseModifier getSecondScheduleModifier() const {
+ return Modifiers[SECOND];
+ }
/// \brief Get location of '('.
///
SourceLocation getLParenLoc() { return LParenLoc; }
/// \brief Get kind location.
///
SourceLocation getScheduleKindLoc() { return KindLoc; }
+ /// \brief Get the first modifier location.
+ ///
+ SourceLocation getFirstScheduleModifierLoc() const {
+ return ModifiersLoc[FIRST];
+ }
+ /// \brief Get the second modifier location.
+ ///
+ SourceLocation getSecondScheduleModifierLoc() const {
+ return ModifiersLoc[SECOND];
+ }
/// \brief Get location of ','.
///
SourceLocation getCommaLoc() { return CommaLoc; }
@@ -1087,7 +1152,11 @@
/// In this example directive '#pragma omp parallel' has clause 'private'
/// with the variables 'a' and 'b'.
///
-class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> {
+class OMPPrivateClause final
+ : public OMPVarListClause<OMPPrivateClause>,
+ private llvm::TrailingObjects<OMPPrivateClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
@@ -1179,7 +1248,11 @@
/// In this example directive '#pragma omp parallel' has clause 'firstprivate'
/// with the variables 'a' and 'b'.
///
-class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
+class OMPFirstprivateClause final
+ : public OMPVarListClause<OMPFirstprivateClause>,
+ private llvm::TrailingObjects<OMPFirstprivateClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
@@ -1299,7 +1372,9 @@
/// \endcode
/// In this example directive '#pragma omp simd' has clause 'lastprivate'
/// with the variables 'a' and 'b'.
-class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
+class OMPLastprivateClause final
+ : public OMPVarListClause<OMPLastprivateClause>,
+ private llvm::TrailingObjects<OMPLastprivateClause, Expr *> {
// There are 4 additional tail-allocated arrays at the end of the class:
// 1. Contains list of pseudo variables with the default initialization for
// each non-firstprivate variables. Used in codegen for initialization of
@@ -1317,6 +1392,8 @@
// Required for proper codegen of final assignment performed by the
// lastprivate clause.
//
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
@@ -1484,7 +1561,11 @@
/// In this example directive '#pragma omp parallel' has clause 'shared'
/// with the variables 'a' and 'b'.
///
-class OMPSharedClause : public OMPVarListClause<OMPSharedClause> {
+class OMPSharedClause final
+ : public OMPVarListClause<OMPSharedClause>,
+ private llvm::TrailingObjects<OMPSharedClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -1544,7 +1625,11 @@
/// In this example directive '#pragma omp parallel' has clause 'reduction'
/// with operator '+' and the variables 'a' and 'b'.
///
-class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
+class OMPReductionClause final
+ : public OMPVarListClause<OMPReductionClause>,
+ private llvm::TrailingObjects<OMPReductionClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Location of ':'.
SourceLocation ColonLoc;
@@ -1746,7 +1831,11 @@
/// In this example directive '#pragma omp simd' has clause 'linear'
/// with variables 'a', 'b' and linear step '2'.
///
-class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
+class OMPLinearClause final
+ : public OMPVarListClause<OMPLinearClause>,
+ private llvm::TrailingObjects<OMPLinearClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Modifier of 'linear' clause.
OpenMPLinearClauseKind Modifier;
@@ -1966,7 +2055,11 @@
/// In this example directive '#pragma omp simd' has clause 'aligned'
/// with variables 'a', 'b' and alignment '8'.
///
-class OMPAlignedClause : public OMPVarListClause<OMPAlignedClause> {
+class OMPAlignedClause final
+ : public OMPVarListClause<OMPAlignedClause>,
+ private llvm::TrailingObjects<OMPAlignedClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Location of ':'.
SourceLocation ColonLoc;
@@ -2050,7 +2143,9 @@
/// In this example directive '#pragma omp parallel' has clause 'copyin'
/// with the variables 'a' and 'b'.
///
-class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
+class OMPCopyinClause final
+ : public OMPVarListClause<OMPCopyinClause>,
+ private llvm::TrailingObjects<OMPCopyinClause, Expr *> {
// Class has 3 additional tail allocated arrays:
// 1. List of helper expressions for proper generation of assignment operation
// required for copyin clause. This list represents sources.
@@ -2064,6 +2159,8 @@
// threadprivate variables to local instances of that variables in other
// implicit threads.
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
@@ -2209,7 +2306,11 @@
/// In this example directive '#pragma omp single' has clause 'copyprivate'
/// with the variables 'a' and 'b'.
///
-class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
+class OMPCopyprivateClause final
+ : public OMPVarListClause<OMPCopyprivateClause>,
+ private llvm::TrailingObjects<OMPCopyprivateClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
@@ -2358,7 +2459,11 @@
/// In this example directive '#pragma omp flush' has implicit clause 'flush'
/// with the variables 'a' and 'b'.
///
-class OMPFlushClause : public OMPVarListClause<OMPFlushClause> {
+class OMPFlushClause final
+ : public OMPVarListClause<OMPFlushClause>,
+ private llvm::TrailingObjects<OMPFlushClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -2418,7 +2523,11 @@
/// In this example directive '#pragma omp task' with clause 'depend' with the
/// variables 'a' and 'b' with dependency 'in'.
///
-class OMPDependClause : public OMPVarListClause<OMPDependClause> {
+class OMPDependClause final
+ : public OMPVarListClause<OMPDependClause>,
+ private llvm::TrailingObjects<OMPDependClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
friend class OMPClauseReader;
/// \brief Dependency type (one of in, out, inout).
OpenMPDependClauseKind DepKind;
@@ -2613,6 +2722,606 @@
}
};
+/// \brief This represents clause 'map' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp target map(a,b)
+/// \endcode
+/// In this example directive '#pragma omp target' has clause 'map'
+/// with the variables 'a' and 'b'.
+///
+class OMPMapClause final : public OMPVarListClause<OMPMapClause>,
+ private llvm::TrailingObjects<OMPMapClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
+ friend class OMPClauseReader;
+
+ /// \brief Map type modifier for the 'map' clause.
+ OpenMPMapClauseKind MapTypeModifier;
+ /// \brief Map type for the 'map' clause.
+ OpenMPMapClauseKind MapType;
+ /// \brief Location of the map type.
+ SourceLocation MapLoc;
+ /// \brief Colon location.
+ SourceLocation ColonLoc;
+
+ /// \brief Set type modifier for the clause.
+ ///
+ /// \param T Type Modifier for the clause.
+ ///
+ void setMapTypeModifier(OpenMPMapClauseKind T) { MapTypeModifier = T; }
+
+ /// \brief Set type for the clause.
+ ///
+ /// \param T Type for the clause.
+ ///
+ void setMapType(OpenMPMapClauseKind T) { MapType = T; }
+
+ /// \brief Set type location.
+ ///
+ /// \param TLoc Type location.
+ ///
+ void setMapLoc(SourceLocation TLoc) { MapLoc = TLoc; }
+
+ /// \brief Set colon location.
+ void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+
+ /// \brief Build clause with number of variables \a N.
+ ///
+ /// \param MapTypeModifier Map type modifier.
+ /// \param MapType Map type.
+ /// \param MapLoc Location of the map type.
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ /// \param N Number of the variables in the clause.
+ ///
+ explicit OMPMapClause(OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, SourceLocation MapLoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPVarListClause<OMPMapClause>(OMPC_map, StartLoc, LParenLoc, EndLoc, N),
+ MapTypeModifier(MapTypeModifier), MapType(MapType), MapLoc(MapLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPMapClause(unsigned N)
+ : OMPVarListClause<OMPMapClause>(OMPC_map, SourceLocation(),
+ SourceLocation(), SourceLocation(), N),
+ MapTypeModifier(OMPC_MAP_unknown), MapType(OMPC_MAP_unknown), MapLoc() {}
+
+public:
+ /// \brief Creates clause with a list of variables \a VL.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ /// \param TypeModifier Map type modifier.
+ /// \param Type Map type.
+ /// \param TypeLoc Location of the map type.
+ ///
+ static OMPMapClause *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ OpenMPMapClauseKind TypeModifier,
+ OpenMPMapClauseKind Type, SourceLocation TypeLoc);
+ /// \brief Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPMapClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// \brief Fetches mapping kind for the clause.
+ OpenMPMapClauseKind getMapType() const LLVM_READONLY { return MapType; }
+
+ /// \brief Fetches the map type modifier for the clause.
+ OpenMPMapClauseKind getMapTypeModifier() const LLVM_READONLY {
+ return MapTypeModifier;
+ }
+
+ /// \brief Fetches location of clause mapping kind.
+ SourceLocation getMapLoc() const LLVM_READONLY { return MapLoc; }
+
+ /// \brief Get colon location.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_map;
+ }
+
+ child_range children() {
+ return child_range(
+ reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+};
+
+/// \brief This represents 'num_teams' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp teams num_teams(n)
+/// \endcode
+/// In this example directive '#pragma omp teams' has clause 'num_teams'
+/// with single expression 'n'.
+///
+class OMPNumTeamsClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief NumTeams number.
+ Stmt *NumTeams;
+ /// \brief Set the NumTeams number.
+ ///
+ /// \param E NumTeams number.
+ ///
+ void setNumTeams(Expr *E) { NumTeams = E; }
+
+public:
+ /// \brief Build 'num_teams' clause.
+ ///
+ /// \param E Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_num_teams, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ NumTeams(E) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPNumTeamsClause()
+ : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), NumTeams(nullptr) {}
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ /// \brief Return NumTeams number.
+ Expr *getNumTeams() { return cast<Expr>(NumTeams); }
+ /// \brief Return NumTeams number.
+ Expr *getNumTeams() const { return cast<Expr>(NumTeams); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_num_teams;
+ }
+
+ child_range children() { return child_range(&NumTeams, &NumTeams + 1); }
+};
+
+/// \brief This represents 'thread_limit' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp teams thread_limit(n)
+/// \endcode
+/// In this example directive '#pragma omp teams' has clause 'thread_limit'
+/// with single expression 'n'.
+///
+class OMPThreadLimitClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief ThreadLimit number.
+ Stmt *ThreadLimit;
+ /// \brief Set the ThreadLimit number.
+ ///
+ /// \param E ThreadLimit number.
+ ///
+ void setThreadLimit(Expr *E) { ThreadLimit = E; }
+
+public:
+ /// \brief Build 'thread_limit' clause.
+ ///
+ /// \param E Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPThreadLimitClause(Expr *E, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_thread_limit, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ ThreadLimit(E) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPThreadLimitClause()
+ : OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), ThreadLimit(nullptr) {}
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ /// \brief Return ThreadLimit number.
+ Expr *getThreadLimit() { return cast<Expr>(ThreadLimit); }
+ /// \brief Return ThreadLimit number.
+ Expr *getThreadLimit() const { return cast<Expr>(ThreadLimit); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_thread_limit;
+ }
+
+ child_range children() { return child_range(&ThreadLimit, &ThreadLimit + 1); }
+};
+
+/// \brief This represents 'priority' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp task priority(n)
+/// \endcode
+/// In this example directive '#pragma omp teams' has clause 'priority' with
+/// single expression 'n'.
+///
+class OMPPriorityClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Priority number.
+ Stmt *Priority;
+ /// \brief Set the Priority number.
+ ///
+ /// \param E Priority number.
+ ///
+ void setPriority(Expr *E) { Priority = E; }
+
+public:
+ /// \brief Build 'priority' clause.
+ ///
+ /// \param E Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPPriorityClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_priority, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Priority(E) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPPriorityClause()
+ : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), Priority(nullptr) {}
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ /// \brief Return Priority number.
+ Expr *getPriority() { return cast<Expr>(Priority); }
+ /// \brief Return Priority number.
+ Expr *getPriority() const { return cast<Expr>(Priority); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_priority;
+ }
+
+ child_range children() { return child_range(&Priority, &Priority + 1); }
+};
+
+/// \brief This represents 'grainsize' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp taskloop grainsize(4)
+/// \endcode
+/// In this example directive '#pragma omp taskloop' has clause 'grainsize'
+/// with single expression '4'.
+///
+class OMPGrainsizeClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Safe iteration space distance.
+ Stmt *Grainsize;
+
+ /// \brief Set safelen.
+ void setGrainsize(Expr *Size) { Grainsize = Size; }
+
+public:
+ /// \brief Build 'grainsize' clause.
+ ///
+ /// \param Size Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPGrainsizeClause(Expr *Size, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_grainsize, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Grainsize(Size) {}
+
+ /// \brief Build an empty clause.
+ ///
+ explicit OMPGrainsizeClause()
+ : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), Grainsize(nullptr) {}
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Return safe iteration space distance.
+ Expr *getGrainsize() const { return cast_or_null<Expr>(Grainsize); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_grainsize;
+ }
+
+ child_range children() { return child_range(&Grainsize, &Grainsize + 1); }
+};
+
+/// \brief This represents 'nogroup' clause in the '#pragma omp ...' directive.
+///
+/// \code
+/// #pragma omp taskloop nogroup
+/// \endcode
+/// In this example directive '#pragma omp taskloop' has 'nogroup' clause.
+///
+class OMPNogroupClause : public OMPClause {
+public:
+ /// \brief Build 'nogroup' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_nogroup, StartLoc, EndLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPNogroupClause()
+ : OMPClause(OMPC_nogroup, SourceLocation(), SourceLocation()) {}
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_nogroup;
+ }
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+};
+
+/// \brief This represents 'num_tasks' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp taskloop num_tasks(4)
+/// \endcode
+/// In this example directive '#pragma omp taskloop' has clause 'num_tasks'
+/// with single expression '4'.
+///
+class OMPNumTasksClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Safe iteration space distance.
+ Stmt *NumTasks;
+
+ /// \brief Set safelen.
+ void setNumTasks(Expr *Size) { NumTasks = Size; }
+
+public:
+ /// \brief Build 'num_tasks' clause.
+ ///
+ /// \param Size Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPNumTasksClause(Expr *Size, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_num_tasks, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ NumTasks(Size) {}
+
+ /// \brief Build an empty clause.
+ ///
+ explicit OMPNumTasksClause()
+ : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), NumTasks(nullptr) {}
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Return safe iteration space distance.
+ Expr *getNumTasks() const { return cast_or_null<Expr>(NumTasks); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_num_tasks;
+ }
+
+ child_range children() { return child_range(&NumTasks, &NumTasks + 1); }
+};
+
+/// \brief This represents 'hint' clause in the '#pragma omp ...' directive.
+///
+/// \code
+/// #pragma omp critical (name) hint(6)
+/// \endcode
+/// In this example directive '#pragma omp critical' has name 'name' and clause
+/// 'hint' with argument '6'.
+///
+class OMPHintClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Hint expression of the 'hint' clause.
+ Stmt *Hint;
+
+ /// \brief Set hint expression.
+ ///
+ void setHint(Expr *H) { Hint = H; }
+
+public:
+ /// \brief Build 'hint' clause with expression \a Hint.
+ ///
+ /// \param Hint Hint expression.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_hint, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Hint(Hint) {}
+
+ /// \brief Build an empty clause.
+ ///
+ OMPHintClause()
+ : OMPClause(OMPC_hint, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), Hint(nullptr) {}
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Returns number of threads.
+ Expr *getHint() const { return cast_or_null<Expr>(Hint); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_hint;
+ }
+
+ child_range children() { return child_range(&Hint, &Hint + 1); }
+};
+
+/// \brief This represents 'dist_schedule' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp distribute dist_schedule(static, 3)
+/// \endcode
+/// In this example directive '#pragma omp distribute' has 'dist_schedule'
+/// clause with arguments 'static' and '3'.
+///
+class OMPDistScheduleClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief A kind of the 'schedule' clause.
+ OpenMPDistScheduleClauseKind Kind;
+ /// \brief Start location of the schedule kind in source code.
+ SourceLocation KindLoc;
+ /// \brief Location of ',' (if any).
+ SourceLocation CommaLoc;
+ /// \brief Chunk size and a reference to pseudo variable for combined
+ /// directives.
+ enum { CHUNK_SIZE, HELPER_CHUNK_SIZE, NUM_EXPRS };
+ Stmt *ChunkSizes[NUM_EXPRS];
+
+ /// \brief Set schedule kind.
+ ///
+ /// \param K Schedule kind.
+ ///
+ void setDistScheduleKind(OpenMPDistScheduleClauseKind K) { Kind = K; }
+ /// \brief Sets the location of '('.
+ ///
+ /// \param Loc Location of '('.
+ ///
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Set schedule kind start location.
+ ///
+ /// \param KLoc Schedule kind location.
+ ///
+ void setDistScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; }
+ /// \brief Set location of ','.
+ ///
+ /// \param Loc Location of ','.
+ ///
+ void setCommaLoc(SourceLocation Loc) { CommaLoc = Loc; }
+ /// \brief Set chunk size.
+ ///
+ /// \param E Chunk size.
+ ///
+ void setChunkSize(Expr *E) { ChunkSizes[CHUNK_SIZE] = E; }
+ /// \brief Set helper chunk size.
+ ///
+ /// \param E Helper chunk size.
+ ///
+ void setHelperChunkSize(Expr *E) { ChunkSizes[HELPER_CHUNK_SIZE] = E; }
+
+public:
+ /// \brief Build 'dist_schedule' clause with schedule kind \a Kind and chunk
+ /// size expression \a ChunkSize.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param KLoc Starting location of the argument.
+ /// \param CommaLoc Location of ','.
+ /// \param EndLoc Ending location of the clause.
+ /// \param Kind DistSchedule kind.
+ /// \param ChunkSize Chunk size.
+ /// \param HelperChunkSize Helper chunk size for combined directives.
+ ///
+ OMPDistScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation KLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc,
+ OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize,
+ Expr *HelperChunkSize)
+ : OMPClause(OMPC_dist_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc) {
+ ChunkSizes[CHUNK_SIZE] = ChunkSize;
+ ChunkSizes[HELPER_CHUNK_SIZE] = HelperChunkSize;
+ }
+
+ /// \brief Build an empty clause.
+ ///
+ explicit OMPDistScheduleClause()
+ : OMPClause(OMPC_dist_schedule, SourceLocation(), SourceLocation()),
+ Kind(OMPC_DIST_SCHEDULE_unknown) {
+ ChunkSizes[CHUNK_SIZE] = nullptr;
+ ChunkSizes[HELPER_CHUNK_SIZE] = nullptr;
+ }
+
+ /// \brief Get kind of the clause.
+ ///
+ OpenMPDistScheduleClauseKind getDistScheduleKind() const { return Kind; }
+ /// \brief Get location of '('.
+ ///
+ SourceLocation getLParenLoc() { return LParenLoc; }
+ /// \brief Get kind location.
+ ///
+ SourceLocation getDistScheduleKindLoc() { return KindLoc; }
+ /// \brief Get location of ','.
+ ///
+ SourceLocation getCommaLoc() { return CommaLoc; }
+ /// \brief Get chunk size.
+ ///
+ Expr *getChunkSize() {
+ return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]);
+ }
+ /// \brief Get chunk size.
+ ///
+ Expr *getChunkSize() const {
+ return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]);
+ }
+ /// \brief Get helper chunk size.
+ ///
+ Expr *getHelperChunkSize() {
+ return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]);
+ }
+ /// \brief Get helper chunk size.
+ ///
+ Expr *getHelperChunkSize() const {
+ return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]);
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_dist_schedule;
+ }
+
+ child_range children() {
+ return child_range(&ChunkSizes[CHUNK_SIZE], &ChunkSizes[CHUNK_SIZE] + 1);
+ }
+};
} // end namespace clang
#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 2235c10..102bbc2 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -185,7 +185,11 @@
/// CK_FloatingToBoolean - Floating point to boolean.
/// (bool) f
CK_FloatingToBoolean,
-
+
+ // CK_BooleanToSignedIntegral - Convert a boolean to -1 or 0 for true and
+ // false, respectively.
+ CK_BooleanToSignedIntegral,
+
/// CK_FloatingCast - Casting between floating types of different size.
/// (double) f
/// (float) ld
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index f269fb1..8ab3f61 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -42,7 +42,7 @@
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
- IncludeNewlines(true) { }
+ IncludeNewlines(true), MSVCFormatting(false) { }
/// \brief What language we're printing.
LangOptions LangOpts;
@@ -163,6 +163,11 @@
/// \brief When true, include newlines after statements like "break", etc.
unsigned IncludeNewlines : 1;
+
+ /// \brief Use whitespace and punctuation like MSVC does. In particular, this
+ /// prints anonymous namespaces as `anonymous namespace' and does not insert
+ /// spaces after template arguments.
+ bool MSVCFormatting : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index ab0aa96..f1ae76b 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
+#include <type_traits>
+
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -133,6 +135,12 @@
/// from which they were produced.
template <typename Derived> class RecursiveASTVisitor {
public:
+ /// A queue used for performing data recursion over statements.
+ /// Parameters involving this type are used to implement data
+ /// recursion over Stmts and Exprs within this class, and should
+ /// typically not be explicitly specified by derived classes.
+ typedef SmallVectorImpl<Stmt *> DataRecursionQueue;
+
/// \brief Return a reference to the derived class.
Derived &getDerived() { return *static_cast<Derived *>(this); }
@@ -148,19 +156,12 @@
/// code, e.g., implicit constructors and destructors.
bool shouldVisitImplicitCode() const { return false; }
- /// \brief Return whether \param S should be traversed using data recursion
- /// to avoid a stack overflow with extreme cases.
- bool shouldUseDataRecursionFor(Stmt *S) const {
- return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) ||
- isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S);
- }
-
/// \brief Recursively visit a statement or expression, by
/// dispatching to Traverse*() based on the argument's dynamic type.
///
/// \returns false if the visitation was terminated early, true
- /// otherwise (including when the argument is NULL).
- bool TraverseStmt(Stmt *S);
+ /// otherwise (including when the argument is nullptr).
+ bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr);
/// \brief Recursively visit a type, by dispatching to
/// Traverse*Type() based on the argument's getTypeClass() property.
@@ -253,13 +254,14 @@
/// \c LE->getBody().
///
/// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseLambdaBody(LambdaExpr *LE);
+ bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr);
/// \brief Recursively visit the syntactic or semantic form of an
/// initialization list.
///
/// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseSynOrSemInitListExpr(InitListExpr *S);
+ bool TraverseSynOrSemInitListExpr(InitListExpr *S,
+ DataRecursionQueue *Queue = nullptr);
// ---- Methods on Attrs ----
@@ -273,9 +275,44 @@
// ---- Methods on Stmts ----
+private:
+ template<typename T, typename U>
+ struct has_same_member_pointer_type : std::false_type {};
+ template<typename T, typename U, typename R, typename... P>
+ struct has_same_member_pointer_type<R (T::*)(P...), R (U::*)(P...)>
+ : std::true_type {};
+
+ // Traverse the given statement. If the most-derived traverse function takes a
+ // data recursion queue, pass it on; otherwise, discard it. Note that the
+ // first branch of this conditional must compile whether or not the derived
+ // class can take a queue, so if we're taking the second arm, make the first
+ // arm call our function rather than the derived class version.
+#define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) \
+ (has_same_member_pointer_type<decltype( \
+ &RecursiveASTVisitor::Traverse##NAME), \
+ decltype(&Derived::Traverse##NAME)>::value \
+ ? static_cast<typename std::conditional< \
+ has_same_member_pointer_type< \
+ decltype(&RecursiveASTVisitor::Traverse##NAME), \
+ decltype(&Derived::Traverse##NAME)>::value, \
+ Derived &, RecursiveASTVisitor &>::type>(*this) \
+ .Traverse##NAME(static_cast<CLASS *>(VAR), QUEUE) \
+ : getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)))
+
+// Try to traverse the given statement, or enqueue it if we're performing data
+// recursion in the middle of traversing another statement. Can only be called
+// from within a DEF_TRAVERSE_STMT body or similar context.
+#define TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S) \
+ do { \
+ if (!TRAVERSE_STMT_BASE(Stmt, Stmt, S, Queue)) \
+ return false; \
+ } while (0)
+
+public:
// Declare Traverse*() for all concrete Stmt classes.
#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) bool Traverse##CLASS(CLASS *S);
+#define STMT(CLASS, PARENT) \
+ bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr);
#include "clang/AST/StmtNodes.inc"
// The above header #undefs ABSTRACT_STMT and STMT upon exit.
@@ -295,9 +332,10 @@
// operator methods. Unary operators are not classes in themselves
// (they're all opcodes in UnaryOperator) but do have visitors.
#define OPERATOR(NAME) \
- bool TraverseUnary##NAME(UnaryOperator *S) { \
+ bool TraverseUnary##NAME(UnaryOperator *S, \
+ DataRecursionQueue *Queue = nullptr) { \
TRY_TO(WalkUpFromUnary##NAME(S)); \
- TRY_TO(TraverseStmt(S->getSubExpr())); \
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSubExpr()); \
return true; \
} \
bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
@@ -314,10 +352,10 @@
// operator methods. Binary operators are not classes in themselves
// (they're all opcodes in BinaryOperator) but do have visitors.
#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \
- bool TraverseBin##NAME(BINOP_TYPE *S) { \
+ bool TraverseBin##NAME(BINOP_TYPE *S, DataRecursionQueue *Queue = nullptr) { \
TRY_TO(WalkUpFromBin##NAME(S)); \
- TRY_TO(TraverseStmt(S->getLHS())); \
- TRY_TO(TraverseStmt(S->getRHS())); \
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLHS()); \
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRHS()); \
return true; \
} \
bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
@@ -443,129 +481,14 @@
/// \brief Process clauses with list of variables.
template <typename T> bool VisitOMPClauseList(T *Node);
- struct EnqueueJob {
- Stmt *S;
- Stmt::child_iterator StmtIt;
-
- EnqueueJob(Stmt *S) : S(S), StmtIt() {}
- };
- bool dataTraverse(Stmt *S);
- bool dataTraverseNode(Stmt *S, bool &EnqueueChildren);
+ bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue);
};
template <typename Derived>
-bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
-
- SmallVector<EnqueueJob, 16> Queue;
- Queue.push_back(S);
-
- while (!Queue.empty()) {
- EnqueueJob &job = Queue.back();
- Stmt *CurrS = job.S;
- if (!CurrS) {
- Queue.pop_back();
- continue;
- }
-
- if (getDerived().shouldUseDataRecursionFor(CurrS)) {
- if (job.StmtIt == Stmt::child_iterator()) {
- bool EnqueueChildren = true;
- if (!dataTraverseNode(CurrS, EnqueueChildren))
- return false;
- if (!EnqueueChildren) {
- Queue.pop_back();
- continue;
- }
- job.StmtIt = CurrS->child_begin();
- } else {
- ++job.StmtIt;
- }
-
- if (job.StmtIt != CurrS->child_end())
- Queue.push_back(*job.StmtIt);
- else
- Queue.pop_back();
- continue;
- }
-
- Queue.pop_back();
- TRY_TO(TraverseStmt(CurrS));
- }
-
- return true;
-}
-
-template <typename Derived>
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
- bool &EnqueueChildren) {
-
-// Dispatch to the corresponding WalkUpFrom* function only if the derived
-// class didn't override Traverse* (and thus the traversal is trivial).
-#define DISPATCH_WALK(NAME, CLASS, VAR) \
- { \
- bool (Derived::*DerivedFn)(CLASS *) = &Derived::Traverse##NAME; \
- bool (Derived::*BaseFn)(CLASS *) = &RecursiveASTVisitor::Traverse##NAME; \
- if (DerivedFn == BaseFn) \
- return getDerived().WalkUpFrom##NAME(static_cast<CLASS *>(VAR)); \
- } \
- EnqueueChildren = false; \
- return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR));
-
- if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
- switch (BinOp->getOpcode()) {
-#define OPERATOR(NAME) \
- case BO_##NAME: \
- DISPATCH_WALK(Bin##NAME, BinaryOperator, S);
-
- BINOP_LIST()
-#undef OPERATOR
-
-#define OPERATOR(NAME) \
- case BO_##NAME##Assign: \
- DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S);
-
- CAO_LIST()
-#undef OPERATOR
- }
- } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
- switch (UnOp->getOpcode()) {
-#define OPERATOR(NAME) \
- case UO_##NAME: \
- DISPATCH_WALK(Unary##NAME, UnaryOperator, S);
-
- UNARYOP_LIST()
-#undef OPERATOR
- }
- }
-
- // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
- switch (S->getStmtClass()) {
- case Stmt::NoStmtClass:
- break;
-#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) \
- case Stmt::CLASS##Class: \
- DISPATCH_WALK(CLASS, CLASS, S);
-#include "clang/AST/StmtNodes.inc"
- }
-
-#undef DISPATCH_WALK
-
- return true;
-}
-
-#define DISPATCH(NAME, CLASS, VAR) \
- return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
- if (!S)
- return true;
-
-#define DISPATCH_STMT(NAME, CLASS, VAR) DISPATCH(NAME, CLASS, VAR)
-
- if (getDerived().shouldUseDataRecursionFor(S))
- return dataTraverse(S);
+ DataRecursionQueue *Queue) {
+#define DISPATCH_STMT(NAME, CLASS, VAR) \
+ return TRAVERSE_STMT_BASE(NAME, CLASS, VAR, Queue);
// If we have a binary expr, dispatch to the subcode of the binop. A smart
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
@@ -617,6 +540,35 @@
#undef DISPATCH_STMT
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S,
+ DataRecursionQueue *Queue) {
+ if (!S)
+ return true;
+
+ if (Queue) {
+ Queue->push_back(S);
+ return true;
+ }
+
+ SmallVector<Stmt *, 8> LocalQueue;
+ LocalQueue.push_back(S);
+
+ while (!LocalQueue.empty()) {
+ Stmt *CurrS = LocalQueue.pop_back_val();
+
+ size_t N = LocalQueue.size();
+ TRY_TO(dataTraverseNode(CurrS, &LocalQueue));
+ // Process new children in the order they were added.
+ std::reverse(LocalQueue.begin() + N, LocalQueue.end());
+ }
+
+ return true;
+}
+
+#define DISPATCH(NAME, CLASS, VAR) \
+ return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
if (T.isNull())
return true;
@@ -870,8 +822,9 @@
}
template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
- TRY_TO(TraverseStmt(LE->getBody()));
+bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(
+ LambdaExpr *LE, DataRecursionQueue *Queue) {
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody());
return true;
}
@@ -1025,6 +978,8 @@
DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); })
+DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); })
+
#undef DEF_TRAVERSE_TYPE
// ----------------- TypeLoc traversal -----------------
@@ -1253,6 +1208,8 @@
DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
+DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
+
#undef DEF_TRAVERSE_TYPELOC
// ----------------- Decl traversal -----------------
@@ -1371,6 +1328,8 @@
DEF_TRAVERSE_DECL(ExternCContextDecl, {})
DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+
// We shouldn't traverse an aliased namespace, since it will be
// defined (and, therefore, traversed) somewhere else.
//
@@ -1917,25 +1876,26 @@
// This macro makes available a variable S, the passed-in stmt.
#define DEF_TRAVERSE_STMT(STMT, CODE) \
template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##STMT(STMT *S) { \
+ bool RecursiveASTVisitor<Derived>::Traverse##STMT( \
+ STMT *S, DataRecursionQueue *Queue) { \
TRY_TO(WalkUpFrom##STMT(S)); \
{ CODE; } \
for (Stmt *SubStmt : S->children()) { \
- TRY_TO(TraverseStmt(SubStmt)); \
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \
} \
return true; \
}
DEF_TRAVERSE_STMT(GCCAsmStmt, {
- TRY_TO(TraverseStmt(S->getAsmString()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString());
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
- TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintLiteral(I));
}
for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
- TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintLiteral(I));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- TRY_TO(TraverseStmt(S->getClobberStringLiteral(I)));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberStringLiteral(I));
}
// children() iterates over inputExpr and outputExpr.
})
@@ -1988,9 +1948,9 @@
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {})
DEF_TRAVERSE_STMT(CXXForRangeStmt, {
if (!getDerived().shouldVisitImplicitCode()) {
- TRY_TO(TraverseStmt(S->getLoopVarStmt()));
- TRY_TO(TraverseStmt(S->getRangeInit()));
- TRY_TO(TraverseStmt(S->getBody()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt());
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit());
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
// Visit everything else only if shouldVisitImplicitCode().
return true;
}
@@ -2023,9 +1983,8 @@
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(
- S->getExplicitTemplateArgs().getTemplateArgs(),
- S->getNumTemplateArgs()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ S->getNumTemplateArgs()));
}
})
@@ -2067,12 +2026,13 @@
})
template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(InitListExpr *S) {
+bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
+ InitListExpr *S, DataRecursionQueue *Queue) {
if (S) {
TRY_TO(WalkUpFromInitListExpr(S));
// All we need are the default actions. FIXME: use a helper function.
for (Stmt *SubStmt : S->children()) {
- TRY_TO(TraverseStmt(SubStmt));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt);
}
}
return true;
@@ -2084,48 +2044,41 @@
// the syntactic and the semantic form.
//
// There is no guarantee about which form \p S takes when this method is called.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
+DEF_TRAVERSE_STMT(InitListExpr, {
TRY_TO(TraverseSynOrSemInitListExpr(
- S->isSemanticForm() ? S->getSyntacticForm() : S));
+ S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
TRY_TO(TraverseSynOrSemInitListExpr(
- S->isSemanticForm() ? S : S->getSemanticForm()));
+ S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
return true;
-}
+})
// GenericSelectionExpr is a special case because the types and expressions
// are interleaved. We also need to watch out for null types (default
// generic associations).
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseGenericSelectionExpr(
- GenericSelectionExpr *S) {
- TRY_TO(WalkUpFromGenericSelectionExpr(S));
+DEF_TRAVERSE_STMT(GenericSelectionExpr, {
TRY_TO(TraverseStmt(S->getControllingExpr()));
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
- TRY_TO(TraverseStmt(S->getAssocExpr(i)));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i));
}
return true;
-}
+})
-// PseudoObjectExpr is a special case because of the wierdness with
+// PseudoObjectExpr is a special case because of the weirdness with
// syntactic expressions and opaque values.
-template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraversePseudoObjectExpr(PseudoObjectExpr *S) {
- TRY_TO(WalkUpFromPseudoObjectExpr(S));
- TRY_TO(TraverseStmt(S->getSyntacticForm()));
+DEF_TRAVERSE_STMT(PseudoObjectExpr, {
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSyntacticForm());
for (PseudoObjectExpr::semantics_iterator i = S->semantics_begin(),
e = S->semantics_end();
i != e; ++i) {
Expr *sub = *i;
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
sub = OVE->getSourceExpr();
- TRY_TO(TraverseStmt(sub));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(sub);
}
return true;
-}
+})
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
// This is called for code like 'return T()' where T is a built-in
@@ -2164,6 +2117,8 @@
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
})
+DEF_TRAVERSE_STMT(MSPropertySubscriptExpr, {})
+
DEF_TRAVERSE_STMT(CXXUuidofExpr, {
// The child-iterator will pick up the arg if it's an expression,
// but not if it's a type.
@@ -2181,7 +2136,7 @@
})
DEF_TRAVERSE_STMT(ExpressionTraitExpr,
- { TRY_TO(TraverseStmt(S->getQueriedExpression())); })
+ { TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getQueriedExpression()); })
DEF_TRAVERSE_STMT(VAArgExpr, {
// The child-iterator will pick up the expression argument.
@@ -2194,10 +2149,7 @@
})
// Walk only the visible parts of lambda expressions.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
- TRY_TO(WalkUpFromLambdaExpr(S));
-
+DEF_TRAVERSE_STMT(LambdaExpr, {
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
@@ -2226,12 +2178,11 @@
}
if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE);
}
- TRY_TO(TraverseLambdaBody(S));
- return true;
-}
+ return TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue);
+})
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
// This is called for code like 'T()', where T is a template argument.
@@ -2355,25 +2306,25 @@
// derived class requests.
DEF_TRAVERSE_STMT(CoroutineBodyStmt, {
if (!getDerived().shouldVisitImplicitCode()) {
- TRY_TO(TraverseStmt(S->getBody()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
return true;
}
})
DEF_TRAVERSE_STMT(CoreturnStmt, {
if (!getDerived().shouldVisitImplicitCode()) {
- TRY_TO(TraverseStmt(S->getOperand()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
return true;
}
})
DEF_TRAVERSE_STMT(CoawaitExpr, {
if (!getDerived().shouldVisitImplicitCode()) {
- TRY_TO(TraverseStmt(S->getOperand()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
return true;
}
})
DEF_TRAVERSE_STMT(CoyieldExpr, {
if (!getDerived().shouldVisitImplicitCode()) {
- TRY_TO(TraverseStmt(S->getOperand()));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
return true;
}
})
@@ -2485,6 +2436,15 @@
DEF_TRAVERSE_STMT(OMPTeamsDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPTaskLoopDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPTaskLoopSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPDistributeDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
// OpenMP clauses.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
@@ -2617,6 +2577,11 @@
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNogroupClause(OMPNogroupClause *) {
+ return true;
+}
+
+template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (auto *E : Node->varlists()) {
@@ -2769,6 +2734,61 @@
return true;
}
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
+ TRY_TO(VisitOMPClauseList(C));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
+ OMPNumTeamsClause *C) {
+ TRY_TO(TraverseStmt(C->getNumTeams()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
+ OMPThreadLimitClause *C) {
+ TRY_TO(TraverseStmt(C->getThreadLimit()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause(
+ OMPPriorityClause *C) {
+ TRY_TO(TraverseStmt(C->getPriority()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause(
+ OMPGrainsizeClause *C) {
+ TRY_TO(TraverseStmt(C->getGrainsize()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNumTasksClause(
+ OMPNumTasksClause *C) {
+ TRY_TO(TraverseStmt(C->getNumTasks()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPHintClause(OMPHintClause *C) {
+ TRY_TO(TraverseStmt(C->getHint()));
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPDistScheduleClause(
+ OMPDistScheduleClause *C) {
+ TRY_TO(TraverseStmt(C->getChunkSize()));
+ TRY_TO(TraverseStmt(C->getHelperChunkSize()));
+ return true;
+}
+
// FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm
@@ -2787,6 +2807,8 @@
// Every class that has getQualifier.
#undef DEF_TRAVERSE_STMT
+#undef TRAVERSE_STMT
+#undef TRAVERSE_STMT_BASE
#undef TRY_TO
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
index 92046d5..eaa22f8 100644
--- a/include/clang/AST/Redeclarable.h
+++ b/include/clang/AST/Redeclarable.h
@@ -20,6 +20,7 @@
#include <iterator>
namespace clang {
+class ASTContext;
/// \brief Provides common interface for the Decls that can be redeclared.
template<typename decl_type>
@@ -32,7 +33,11 @@
&ExternalASTSource::CompleteRedeclChain>
KnownLatest;
- typedef const ASTContext *UninitializedLatest;
+ /// We store a pointer to the ASTContext in the UninitializedLatest
+ /// pointer, but to avoid circular type dependencies when we steal the low
+ /// bits of this pointer, we use a raw void* here.
+ typedef const void *UninitializedLatest;
+
typedef Decl *Previous;
/// A pointer to either an uninitialized latest declaration (where either
@@ -47,7 +52,7 @@
enum LatestTag { LatestLink };
DeclLink(LatestTag, const ASTContext &Ctx)
- : Next(NotKnownLatest(&Ctx)) {}
+ : Next(NotKnownLatest(reinterpret_cast<UninitializedLatest>(&Ctx))) {}
DeclLink(PreviousTag, decl_type *D)
: Next(NotKnownLatest(Previous(D))) {}
@@ -67,7 +72,8 @@
return static_cast<decl_type*>(NKL.get<Previous>());
// Allocate the generational 'most recent' cache now, if needed.
- Next = KnownLatest(*NKL.get<UninitializedLatest>(),
+ Next = KnownLatest(*reinterpret_cast<const ASTContext *>(
+ NKL.get<UninitializedLatest>()),
const_cast<decl_type *>(D));
}
@@ -83,7 +89,9 @@
assert(NextIsLatest() && "decl became canonical unexpectedly");
if (Next.is<NotKnownLatest>()) {
NotKnownLatest NKL = Next.get<NotKnownLatest>();
- Next = KnownLatest(*NKL.get<UninitializedLatest>(), D);
+ Next = KnownLatest(*reinterpret_cast<const ASTContext *>(
+ NKL.get<UninitializedLatest>()),
+ D);
} else {
auto Latest = Next.get<KnownLatest>();
Latest.set(D);
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index c64ced4..d3950e9 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -130,7 +130,7 @@
friend class CharacterLiteral;
unsigned : NumExprBits;
- unsigned Kind : 2;
+ unsigned Kind : 3;
};
enum APFloatSemantics {
@@ -558,7 +558,7 @@
CompoundStmtBits.NumStmts = 0;
}
- void setStmts(const ASTContext &C, Stmt **Stmts, unsigned NumStmts);
+ void setStmts(const ASTContext &C, ArrayRef<Stmt *> Stmts);
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
unsigned size() const { return CompoundStmtBits.NumStmts; }
@@ -825,18 +825,20 @@
AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt)
: Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc),
NumAttrs(Attrs.size()) {
- memcpy(getAttrArrayPtr(), Attrs.data(), Attrs.size() * sizeof(Attr *));
+ std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr());
}
explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs)
: Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) {
- memset(getAttrArrayPtr(), 0, NumAttrs * sizeof(Attr *));
+ std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr);
}
- Attr *const *getAttrArrayPtr() const {
- return reinterpret_cast<Attr *const *>(this + 1);
+ const Attr *const *getAttrArrayPtr() const {
+ return reinterpret_cast<const Attr *const *>(this + 1);
}
- Attr **getAttrArrayPtr() { return reinterpret_cast<Attr **>(this + 1); }
+ const Attr **getAttrArrayPtr() {
+ return reinterpret_cast<const Attr **>(this + 1);
+ }
public:
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
@@ -1986,6 +1988,7 @@
enum VariableCaptureKind {
VCK_This,
VCK_ByRef,
+ VCK_ByCopy,
VCK_VLAType,
};
@@ -2005,24 +2008,10 @@
/// \param Var The variable being captured, or null if capturing this.
///
Capture(SourceLocation Loc, VariableCaptureKind Kind,
- VarDecl *Var = nullptr)
- : VarAndKind(Var, Kind), Loc(Loc) {
- switch (Kind) {
- case VCK_This:
- assert(!Var && "'this' capture cannot have a variable!");
- break;
- case VCK_ByRef:
- assert(Var && "capturing by reference must have a variable!");
- break;
- case VCK_VLAType:
- assert(!Var &&
- "Variable-length array type capture cannot have a variable!");
- break;
- }
- }
+ VarDecl *Var = nullptr);
/// \brief Determine the kind of capture.
- VariableCaptureKind getCaptureKind() const { return VarAndKind.getInt(); }
+ VariableCaptureKind getCaptureKind() const;
/// \brief Retrieve the source location at which the variable or 'this' was
/// first used.
@@ -2031,9 +2020,14 @@
/// \brief Determine whether this capture handles the C++ 'this' pointer.
bool capturesThis() const { return getCaptureKind() == VCK_This; }
- /// \brief Determine whether this capture handles a variable.
+ /// \brief Determine whether this capture handles a variable (by reference).
bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; }
+ /// \brief Determine whether this capture handles a variable by copy.
+ bool capturesVariableByCopy() const {
+ return getCaptureKind() == VCK_ByCopy;
+ }
+
/// \brief Determine whether this capture handles a variable-length array
/// type.
bool capturesVariableArrayType() const {
@@ -2043,11 +2037,8 @@
/// \brief Retrieve the declaration of the variable being captured.
///
/// This operation is only valid if this capture captures a variable.
- VarDecl *getCapturedVar() const {
- assert(capturesVariable() &&
- "No variable available for 'this' or VAT capture");
- return VarAndKind.getPointer();
- }
+ VarDecl *getCapturedVar() const;
+
friend class ASTStmtReader;
};
@@ -2094,26 +2085,17 @@
const Stmt *getCapturedStmt() const { return getStoredStmts()[NumCaptures]; }
/// \brief Retrieve the outlined function declaration.
- CapturedDecl *getCapturedDecl() { return CapDeclAndKind.getPointer(); }
- const CapturedDecl *getCapturedDecl() const {
- return CapDeclAndKind.getPointer();
- }
+ CapturedDecl *getCapturedDecl();
+ const CapturedDecl *getCapturedDecl() const;
/// \brief Set the outlined function declaration.
- void setCapturedDecl(CapturedDecl *D) {
- assert(D && "null CapturedDecl");
- CapDeclAndKind.setPointer(D);
- }
+ void setCapturedDecl(CapturedDecl *D);
/// \brief Retrieve the captured region kind.
- CapturedRegionKind getCapturedRegionKind() const {
- return CapDeclAndKind.getInt();
- }
+ CapturedRegionKind getCapturedRegionKind() const;
/// \brief Set the captured region kind.
- void setCapturedRegionKind(CapturedRegionKind Kind) {
- CapDeclAndKind.setInt(Kind);
- }
+ void setCapturedRegionKind(CapturedRegionKind Kind);
/// \brief Retrieve the record declaration for captured variables.
const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; }
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 982181e..1ca73e2 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -292,14 +292,33 @@
/// body and holds the additional semantic context required to set up and tear
/// down the coroutine frame.
class CoroutineBodyStmt : public Stmt {
- enum SubStmt { Body, Count };
- Stmt *SubStmts[SubStmt::Count];
+ enum SubStmt {
+ Body, ///< The body of the coroutine.
+ Promise, ///< The promise statement.
+ InitSuspend, ///< The initial suspend statement, run before the body.
+ FinalSuspend, ///< The final suspend statement, run after the body.
+ OnException, ///< Handler for exceptions thrown in the body.
+ OnFallthrough, ///< Handler for control flow falling off the body.
+ ReturnValue, ///< Return value for thunk function.
+ FirstParamMove ///< First offset for move construction of parameter copies.
+ };
+ Stmt *SubStmts[SubStmt::FirstParamMove];
friend class ASTStmtReader;
public:
- CoroutineBodyStmt(Stmt *Body)
+ CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend,
+ Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough,
+ Expr *ReturnValue, ArrayRef<Expr *> ParamMoves)
: Stmt(CoroutineBodyStmtClass) {
SubStmts[CoroutineBodyStmt::Body] = Body;
+ SubStmts[CoroutineBodyStmt::Promise] = Promise;
+ SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend;
+ SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend;
+ SubStmts[CoroutineBodyStmt::OnException] = OnException;
+ SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough;
+ SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue;
+ // FIXME: Tail-allocate space for parameter move expressions and store them.
+ assert(ParamMoves.empty() && "not implemented yet");
}
/// \brief Retrieve the body of the coroutine as written. This will be either
@@ -308,6 +327,23 @@
return SubStmts[SubStmt::Body];
}
+ Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; }
+ VarDecl *getPromiseDecl() const {
+ return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl());
+ }
+
+ Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; }
+ Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; }
+
+ Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; }
+ Stmt *getFallthroughHandler() const {
+ return SubStmts[SubStmt::OnFallthrough];
+ }
+
+ Expr *getReturnValueInit() const {
+ return cast<Expr>(SubStmts[SubStmt::ReturnValue]);
+ }
+
SourceLocation getLocStart() const LLVM_READONLY {
return getBody()->getLocStart();
}
@@ -316,7 +352,7 @@
}
child_range children() {
- return child_range(SubStmts, SubStmts + SubStmt::Count);
+ return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove);
}
static bool classof(const Stmt *T) {
@@ -328,50 +364,47 @@
///
/// This statament models the initialization of the coroutine promise
/// (encapsulating the eventual notional return value) from an expression
-/// (or braced-init-list).
+/// (or braced-init-list), followed by termination of the coroutine.
///
-/// This initialization is modeled by a call to one of:
+/// This initialization is modeled by the evaluation of the operand
+/// followed by a call to one of:
/// <promise>.return_value(<operand>)
/// <promise>.return_void()
/// which we name the "promise call".
class CoreturnStmt : public Stmt {
SourceLocation CoreturnLoc;
- /// The operand of the 'co_return' statement.
- Stmt *Operand;
- /// The implied call to the promise object. May be null if the
- /// coroutine has not yet been finalized.
- Stmt *PromiseCall;
+ enum SubStmt { Operand, PromiseCall, Count };
+ Stmt *SubStmts[SubStmt::Count];
friend class ASTStmtReader;
public:
- CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand)
- : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
- Operand(Operand), PromiseCall(nullptr) {}
+ CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
+ : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
+ SubStmts[SubStmt::Operand] = Operand;
+ SubStmts[SubStmt::PromiseCall] = PromiseCall;
+ }
SourceLocation getKeywordLoc() const { return CoreturnLoc; }
/// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
/// if none was specified.
- Expr *getOperand() const { return static_cast<Expr*>(Operand); }
+ Expr *getOperand() const { return static_cast<Expr*>(SubStmts[Operand]); }
/// \brief Retrieve the promise call that results from this 'co_return'
/// statement. Will be nullptr if either the coroutine has not yet been
/// finalized or the coroutine has no eventual return type.
- Expr *getPromiseCall() const { return static_cast<Expr*>(PromiseCall); }
-
- /// \brief Set the resolved promise call. This is delayed until the
- /// complete coroutine body has been parsed and the promise type is known.
- void finalize(Stmt *PC) { PromiseCall = PC; }
+ Expr *getPromiseCall() const {
+ return static_cast<Expr*>(SubStmts[PromiseCall]);
+ }
SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
SourceLocation getLocEnd() const LLVM_READONLY {
- return Operand->getLocEnd();
+ return getOperand()->getLocEnd();
}
child_range children() {
- Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
- return child_range(Which, Which + 1);
+ return child_range(SubStmts, SubStmts + SubStmt::Count);
}
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index 8f84602..c82aeda 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -70,8 +70,7 @@
: Stmt(SC), Kind(K), StartLoc(std::move(StartLoc)),
EndLoc(std::move(EndLoc)), NumClauses(NumClauses),
NumChildren(NumChildren),
- ClausesOffset(llvm::RoundUpToAlignment(sizeof(T),
- llvm::alignOf<OMPClause *>())) {}
+ ClausesOffset(llvm::alignTo(sizeof(T), llvm::alignOf<OMPClause *>())) {}
/// \brief Sets the list of variables for this clause.
///
@@ -391,8 +390,11 @@
/// \brief Offset to the start of children expression arrays.
static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
- return isOpenMPWorksharingDirective(Kind) ? WorksharingEnd
- : DefaultEnd;
+ return (isOpenMPWorksharingDirective(Kind) ||
+ isOpenMPTaskLoopDirective(Kind) ||
+ isOpenMPDistributeDirective(Kind))
+ ? WorksharingEnd
+ : DefaultEnd;
}
/// \brief Children number.
@@ -421,37 +423,51 @@
void setInit(Expr *Init) { *std::next(child_begin(), InitOffset) = Init; }
void setInc(Expr *Inc) { *std::next(child_begin(), IncOffset) = Inc; }
void setIsLastIterVariable(Expr *IL) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), IsLastIterVariableOffset) = IL;
}
void setLowerBoundVariable(Expr *LB) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), LowerBoundVariableOffset) = LB;
}
void setUpperBoundVariable(Expr *UB) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), UpperBoundVariableOffset) = UB;
}
void setStrideVariable(Expr *ST) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), StrideVariableOffset) = ST;
}
void setEnsureUpperBound(Expr *EUB) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), EnsureUpperBoundOffset) = EUB;
}
void setNextLowerBound(Expr *NLB) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), NextLowerBoundOffset) = NLB;
}
void setNextUpperBound(Expr *NUB) {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
*std::next(child_begin(), NextUpperBoundOffset) = NUB;
}
@@ -578,43 +594,50 @@
reinterpret_cast<const Expr *>(*std::next(child_begin(), IncOffset)));
}
Expr *getIsLastIterVariable() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), IsLastIterVariableOffset)));
}
Expr *getLowerBoundVariable() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), LowerBoundVariableOffset)));
}
Expr *getUpperBoundVariable() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), UpperBoundVariableOffset)));
}
Expr *getStrideVariable() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), StrideVariableOffset)));
}
Expr *getEnsureUpperBound() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), EnsureUpperBoundOffset)));
}
Expr *getNextLowerBound() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), NextLowerBoundOffset)));
}
Expr *getNextUpperBound() const {
- assert(isOpenMPWorksharingDirective(getDirectiveKind()) &&
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind())) &&
"expected worksharing loop directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), NextUpperBoundOffset)));
@@ -665,7 +688,10 @@
T->getStmtClass() == OMPForDirectiveClass ||
T->getStmtClass() == OMPForSimdDirectiveClass ||
T->getStmtClass() == OMPParallelForDirectiveClass ||
- T->getStmtClass() == OMPParallelForSimdDirectiveClass;
+ T->getStmtClass() == OMPParallelForSimdDirectiveClass ||
+ T->getStmtClass() == OMPTaskLoopDirectiveClass ||
+ T->getStmtClass() == OMPTaskLoopSimdDirectiveClass ||
+ T->getStmtClass() == OMPDistributeDirectiveClass;
}
};
@@ -1126,18 +1152,22 @@
/// \param Name Name of the directive.
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
///
OMPCriticalDirective(const DeclarationNameInfo &Name, SourceLocation StartLoc,
- SourceLocation EndLoc)
+ SourceLocation EndLoc, unsigned NumClauses)
: OMPExecutableDirective(this, OMPCriticalDirectiveClass, OMPD_critical,
- StartLoc, EndLoc, 0, 1),
+ StartLoc, EndLoc, NumClauses, 1),
DirName(Name) {}
/// \brief Build an empty directive.
///
- explicit OMPCriticalDirective()
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPCriticalDirective(unsigned NumClauses)
: OMPExecutableDirective(this, OMPCriticalDirectiveClass, OMPD_critical,
- SourceLocation(), SourceLocation(), 0, 1),
+ SourceLocation(), SourceLocation(), NumClauses,
+ 1),
DirName() {}
/// \brief Set name of the directive.
@@ -1153,17 +1183,21 @@
/// \param Name Name of the directive.
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
///
static OMPCriticalDirective *
Create(const ASTContext &C, const DeclarationNameInfo &Name,
- SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt);
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt);
/// \brief Creates an empty directive.
///
/// \param C AST context.
+ /// \param NumClauses Number of clauses.
///
- static OMPCriticalDirective *CreateEmpty(const ASTContext &C, EmptyShell);
+ static OMPCriticalDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
/// \brief Return name of the directive.
///
@@ -2183,6 +2217,205 @@
}
};
+/// \brief This represents '#pragma omp taskloop' directive.
+///
+/// \code
+/// #pragma omp taskloop private(a,b) grainsize(val) num_tasks(num)
+/// \endcode
+/// In this example directive '#pragma omp taskloop' has clauses 'private'
+/// with the variables 'a' and 'b', 'grainsize' with expression 'val' and
+/// 'num_tasks' with expression 'num'.
+///
+class OMPTaskLoopDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPTaskLoopDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPTaskLoopDirectiveClass, OMPD_taskloop,
+ StartLoc, EndLoc, CollapsedNum, NumClauses) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPTaskLoopDirective(unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPTaskLoopDirectiveClass, OMPD_taskloop,
+ SourceLocation(), SourceLocation(), CollapsedNum,
+ NumClauses) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPTaskLoopDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// \brief Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPTaskLoopDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPTaskLoopDirectiveClass;
+ }
+};
+
+/// \brief This represents '#pragma omp taskloop simd' directive.
+///
+/// \code
+/// #pragma omp taskloop simd private(a,b) grainsize(val) num_tasks(num)
+/// \endcode
+/// In this example directive '#pragma omp taskloop simd' has clauses 'private'
+/// with the variables 'a' and 'b', 'grainsize' with expression 'val' and
+/// 'num_tasks' with expression 'num'.
+///
+class OMPTaskLoopSimdDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPTaskLoopSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPTaskLoopSimdDirectiveClass,
+ OMPD_taskloop_simd, StartLoc, EndLoc, CollapsedNum,
+ NumClauses) {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPTaskLoopSimdDirective(unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPTaskLoopSimdDirectiveClass,
+ OMPD_taskloop_simd, SourceLocation(), SourceLocation(),
+ CollapsedNum, NumClauses) {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPTaskLoopSimdDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// \brief Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPTaskLoopSimdDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPTaskLoopSimdDirectiveClass;
+ }
+};
+
+/// \brief This represents '#pragma omp distribute' directive.
+///
+/// \code
+/// #pragma omp distribute private(a,b)
+/// \endcode
+/// In this example directive '#pragma omp distribute' has clauses 'private'
+/// with the variables 'a' and 'b'
+///
+class OMPDistributeDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+
+ /// \brief Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPDistributeDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPDistributeDirectiveClass, OMPD_distribute,
+ StartLoc, EndLoc, CollapsedNum, NumClauses)
+ {}
+
+ /// \brief Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPDistributeDirective(unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPDistributeDirectiveClass, OMPD_distribute,
+ SourceLocation(), SourceLocation(), CollapsedNum,
+ NumClauses)
+ {}
+
+public:
+ /// \brief Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPDistributeDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// \brief Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPDistributeDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPDistributeDirectiveClass;
+ }
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 07e70ca..f87171a 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TrailingObjects.h"
namespace llvm {
class FoldingSetNodeID;
@@ -562,84 +563,72 @@
/// the "<int>" in "sort<int>".
/// This is safe to be used inside an AST node, in contrast with
/// TemplateArgumentListInfo.
-struct ASTTemplateArgumentListInfo {
+struct ASTTemplateArgumentListInfo final
+ : private llvm::TrailingObjects<ASTTemplateArgumentListInfo,
+ TemplateArgumentLoc> {
+private:
+ friend TrailingObjects;
+
+ ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
+
+public:
/// \brief The source location of the left angle bracket ('<').
SourceLocation LAngleLoc;
-
+
/// \brief The source location of the right angle bracket ('>').
SourceLocation RAngleLoc;
-
- union {
- /// \brief The number of template arguments in TemplateArgs.
- /// The actual template arguments (if any) are stored after the
- /// ExplicitTemplateArgumentList structure.
- unsigned NumTemplateArgs;
- /// Force ASTTemplateArgumentListInfo to the right alignment
- /// for the following array of TemplateArgumentLocs.
- llvm::AlignedCharArray<
- llvm::AlignOf<TemplateArgumentLoc>::Alignment, 1> Aligner;
- };
+ /// \brief The number of template arguments in TemplateArgs.
+ unsigned NumTemplateArgs;
/// \brief Retrieve the template arguments
- TemplateArgumentLoc *getTemplateArgs() {
- return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
- }
-
- /// \brief Retrieve the template arguments
const TemplateArgumentLoc *getTemplateArgs() const {
- return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
+ return getTrailingObjects<TemplateArgumentLoc>();
}
const TemplateArgumentLoc &operator[](unsigned I) const {
return getTemplateArgs()[I];
}
- static const ASTTemplateArgumentListInfo *Create(ASTContext &C,
- const TemplateArgumentListInfo &List);
-
- void initializeFrom(const TemplateArgumentListInfo &List);
- void initializeFrom(const TemplateArgumentListInfo &List,
- bool &Dependent, bool &InstantiationDependent,
- bool &ContainsUnexpandedParameterPack);
- void copyInto(TemplateArgumentListInfo &List) const;
- static std::size_t sizeFor(unsigned NumTemplateArgs);
+ static const ASTTemplateArgumentListInfo *
+ Create(ASTContext &C, const TemplateArgumentListInfo &List);
};
-/// \brief Extends ASTTemplateArgumentListInfo with the source location
-/// information for the template keyword; this is used as part of the
-/// representation of qualified identifiers, such as S<T>::template apply<T>.
-struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo {
- typedef ASTTemplateArgumentListInfo Base;
+/// \brief Represents an explicit template argument list in C++, e.g.,
+/// the "<int>" in "sort<int>".
+///
+/// It is intended to be used as a trailing object on AST nodes, and
+/// as such, doesn't contain the array of TemplateArgumentLoc itself,
+/// but expects the containing object to also provide storage for
+/// that.
+struct LLVM_ALIGNAS(LLVM_PTR_SIZE) ASTTemplateKWAndArgsInfo {
+ /// \brief The source location of the left angle bracket ('<').
+ SourceLocation LAngleLoc;
- // NOTE: the source location of the (optional) template keyword is
- // stored after all template arguments.
+ /// \brief The source location of the right angle bracket ('>').
+ SourceLocation RAngleLoc;
- /// \brief Get the source location of the template keyword.
- SourceLocation getTemplateKeywordLoc() const {
- return *reinterpret_cast<const SourceLocation*>
- (getTemplateArgs() + NumTemplateArgs);
- }
+ /// \brief The source location of the template keyword; this is used
+ /// as part of the representation of qualified identifiers, such as
+ /// S<T>::template apply<T>. Will be empty if this expression does
+ /// not have a template keyword.
+ SourceLocation TemplateKWLoc;
- /// \brief Sets the source location of the template keyword.
- void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) {
- *reinterpret_cast<SourceLocation*>
- (getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc;
- }
+ /// \brief The number of template arguments in TemplateArgs.
+ unsigned NumTemplateArgs;
- static const ASTTemplateKWAndArgsInfo*
- Create(ASTContext &C, SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo &List);
-
- void initializeFrom(SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo &List);
void initializeFrom(SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo &List,
- bool &Dependent, bool &InstantiationDependent,
+ TemplateArgumentLoc *OutArgArray);
+ void initializeFrom(SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &List,
+ TemplateArgumentLoc *OutArgArray, bool &Dependent,
+ bool &InstantiationDependent,
bool &ContainsUnexpandedParameterPack);
void initializeFrom(SourceLocation TemplateKWLoc);
- static std::size_t sizeFor(unsigned NumTemplateArgs);
+ void copyInto(const TemplateArgumentLoc *ArgArray,
+ TemplateArgumentListInfo &List) const;
};
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index f3d23b9..3e10d2f 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -180,9 +180,7 @@
StorageType Storage;
- explicit TemplateName(void *Ptr) {
- Storage = StorageType::getFromOpaqueValue(Ptr);
- }
+ explicit TemplateName(void *Ptr);
public:
// \brief Kind of name that is actually stored.
@@ -207,17 +205,15 @@
};
TemplateName() : Storage() { }
- explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
- explicit TemplateName(OverloadedTemplateStorage *Storage)
- : Storage(Storage) { }
+ explicit TemplateName(TemplateDecl *Template);
+ explicit TemplateName(OverloadedTemplateStorage *Storage);
explicit TemplateName(SubstTemplateTemplateParmStorage *Storage);
- explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
- : Storage(Storage) { }
- explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
- explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
+ explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage);
+ explicit TemplateName(QualifiedTemplateName *Qual);
+ explicit TemplateName(DependentTemplateName *Dep);
/// \brief Determine whether this template name is NULL.
- bool isNull() const { return Storage.isNull(); }
+ bool isNull() const;
// \brief Get the kind of name that is actually stored.
NameKind getKind() const;
@@ -238,26 +234,14 @@
/// name refers to, if known. If the template name does not refer to a
/// specific set of function templates because it is a dependent name or
/// refers to a single template, returns NULL.
- OverloadedTemplateStorage *getAsOverloadedTemplate() const {
- if (UncommonTemplateNameStorage *Uncommon =
- Storage.dyn_cast<UncommonTemplateNameStorage *>())
- return Uncommon->getAsOverloadedStorage();
-
- return nullptr;
- }
+ OverloadedTemplateStorage *getAsOverloadedTemplate() const;
/// \brief Retrieve the substituted template template parameter, if
/// known.
///
/// \returns The storage for the substituted template template parameter,
/// if known. Otherwise, returns NULL.
- SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const {
- if (UncommonTemplateNameStorage *uncommon =
- Storage.dyn_cast<UncommonTemplateNameStorage *>())
- return uncommon->getAsSubstTemplateTemplateParm();
-
- return nullptr;
- }
+ SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const;
/// \brief Retrieve the substituted template template parameter pack, if
/// known.
@@ -265,25 +249,15 @@
/// \returns The storage for the substituted template template parameter pack,
/// if known. Otherwise, returns NULL.
SubstTemplateTemplateParmPackStorage *
- getAsSubstTemplateTemplateParmPack() const {
- if (UncommonTemplateNameStorage *Uncommon =
- Storage.dyn_cast<UncommonTemplateNameStorage *>())
- return Uncommon->getAsSubstTemplateTemplateParmPack();
-
- return nullptr;
- }
+ getAsSubstTemplateTemplateParmPack() const;
/// \brief Retrieve the underlying qualified template name
/// structure, if any.
- QualifiedTemplateName *getAsQualifiedTemplateName() const {
- return Storage.dyn_cast<QualifiedTemplateName *>();
- }
+ QualifiedTemplateName *getAsQualifiedTemplateName() const;
/// \brief Retrieve the underlying dependent template name
/// structure, if any.
- DependentTemplateName *getAsDependentTemplateName() const {
- return Storage.dyn_cast<DependentTemplateName *>();
- }
+ DependentTemplateName *getAsDependentTemplateName() const;
TemplateName getUnderlying() const;
@@ -359,9 +333,6 @@
TemplateName replacement);
};
-inline TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
- : Storage(Storage) { }
-
inline TemplateName TemplateName::getUnderlying() const {
if (SubstTemplateTemplateParmStorage *subst
= getAsSubstTemplateTemplateParm())
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index d080535..d63b2c4 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1210,6 +1210,16 @@
RQ_RValue
};
+/// Which keyword(s) were used to create an AutoType.
+enum class AutoTypeKeyword {
+ /// \brief auto
+ Auto,
+ /// \brief decltype(auto)
+ DecltypeAuto,
+ /// \brief __auto_type (GNU extension)
+ GNUAutoType
+};
+
/// The base class of the type hierarchy.
///
/// A central concept with types is that each type always has a canonical
@@ -1428,8 +1438,9 @@
unsigned : NumTypeBits;
- /// Was this placeholder type spelled as 'decltype(auto)'?
- unsigned IsDecltypeAuto : 1;
+ /// Was this placeholder type spelled as 'auto', 'decltype(auto)',
+ /// or '__auto_type'? AutoTypeKeyword value.
+ unsigned Keyword : 2;
};
union {
@@ -1657,6 +1668,7 @@
bool isObjCQualifiedClassType() const; // Class<foo>
bool isObjCObjectOrInterfaceType() const;
bool isObjCIdType() const; // id
+ bool isObjCInertUnsafeUnretainedType() const;
/// Whether the type is Objective-C 'id' or a __kindof type of an
/// object type, e.g., __kindof NSView * or __kindof id
@@ -1709,6 +1721,7 @@
bool isNDRangeT() const; // OpenCL ndrange_t
bool isReserveIDT() const; // OpenCL reserve_id_t
+ bool isPipeType() const; // OpenCL pipe type
bool isOpenCLSpecificType() const; // Any OpenCL specific type
/// Determines if this type, which must satisfy
@@ -3625,6 +3638,7 @@
attr_nullable,
attr_null_unspecified,
attr_objc_kindof,
+ attr_objc_inert_unsafe_unretained,
};
private:
@@ -3902,8 +3916,7 @@
/// is no deduced type and an auto type is canonical. In the latter case, it is
/// also a dependent type.
class AutoType : public Type, public llvm::FoldingSetNode {
- AutoType(QualType DeducedType, bool IsDecltypeAuto,
- bool IsDependent)
+ AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent)
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
/*VariablyModified=*/false,
@@ -3911,13 +3924,18 @@
? false : DeducedType->containsUnexpandedParameterPack()) {
assert((DeducedType.isNull() || !IsDependent) &&
"auto deduced to dependent type");
- AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
+ AutoTypeBits.Keyword = (unsigned)Keyword;
}
friend class ASTContext; // ASTContext creates these
public:
- bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; }
+ bool isDecltypeAuto() const {
+ return getKeyword() == AutoTypeKeyword::DecltypeAuto;
+ }
+ AutoTypeKeyword getKeyword() const {
+ return (AutoTypeKeyword)AutoTypeBits.Keyword;
+ }
bool isSugared() const { return !isCanonicalUnqualified(); }
QualType desugar() const { return getCanonicalTypeInternal(); }
@@ -3932,14 +3950,13 @@
}
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDeducedType(), isDecltypeAuto(),
- isDependentType());
+ Profile(ID, getDeducedType(), getKeyword(), isDependentType());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
- bool IsDecltypeAuto, bool IsDependent) {
+ AutoTypeKeyword Keyword, bool IsDependent) {
ID.AddPointer(Deduced.getAsOpaquePtr());
- ID.AddBoolean(IsDecltypeAuto);
+ ID.AddInteger((unsigned)Keyword);
ID.AddBoolean(IsDependent);
}
@@ -4999,6 +5016,41 @@
}
};
+/// PipeType - OpenCL20.
+class PipeType : public Type, public llvm::FoldingSetNode {
+ QualType ElementType;
+
+ PipeType(QualType elemType, QualType CanonicalPtr) :
+ Type(Pipe, CanonicalPtr, elemType->isDependentType(),
+ elemType->isInstantiationDependentType(),
+ elemType->isVariablyModifiedType(),
+ elemType->containsUnexpandedParameterPack()),
+ ElementType(elemType) {}
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+
+ QualType getElementType() const { return ElementType; }
+
+ bool isSugared() const { return false; }
+
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Pipe;
+ }
+
+};
+
/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {
public:
@@ -5445,9 +5497,13 @@
isImage1dBufferT();
}
+inline bool Type::isPipeType() const {
+ return isa<PipeType>(CanonicalType);
+}
+
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isNDRangeT() || isReserveIDT();
+ isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
}
inline bool Type::isTemplateTypeParmType() const {
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 674fffb..ba3f848 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -170,19 +170,18 @@
/// \brief Initializes this by copying its information from another
/// TypeLoc of the same type.
- void initializeFullCopy(TypeLoc Other) const {
+ void initializeFullCopy(TypeLoc Other) {
assert(getType() == Other.getType());
- size_t Size = getFullDataSize();
- memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
+ copy(Other);
}
/// \brief Initializes this by copying its information from another
/// TypeLoc of the same type. The given size must be the full data
/// size.
- void initializeFullCopy(TypeLoc Other, unsigned Size) const {
+ void initializeFullCopy(TypeLoc Other, unsigned Size) {
assert(getType() == Other.getType());
assert(getFullDataSize() == Size);
- memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
+ copy(Other);
}
/// Copies the other type loc into this one.
@@ -255,7 +254,7 @@
unsigned align =
TypeLoc::getLocalAlignmentForType(QualType(getTypePtr(), 0));
uintptr_t dataInt = reinterpret_cast<uintptr_t>(Data);
- dataInt = llvm::RoundUpToAlignment(dataInt, align);
+ dataInt = llvm::alignTo(dataInt, align);
return UnqualTypeLoc(getTypePtr(), reinterpret_cast<void*>(dataInt));
}
@@ -354,7 +353,7 @@
unsigned getLocalDataSize() const {
unsigned size = sizeof(LocalData);
unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
- size = llvm::RoundUpToAlignment(size, extraAlign);
+ size = llvm::alignTo(size, extraAlign);
size += asDerived()->getExtraLocalDataSize();
return size;
}
@@ -400,14 +399,14 @@
void *getExtraLocalData() const {
unsigned size = sizeof(LocalData);
unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
- size = llvm::RoundUpToAlignment(size, extraAlign);
+ size = llvm::alignTo(size, extraAlign);
return reinterpret_cast<char*>(Base::Data) + size;
}
void *getNonLocalData() const {
uintptr_t data = reinterpret_cast<uintptr_t>(Base::Data);
data += asDerived()->getLocalDataSize();
- data = llvm::RoundUpToAlignment(data, getNextTypeAlign());
+ data = llvm::alignTo(data, getNextTypeAlign());
return reinterpret_cast<void*>(data);
}
@@ -2034,7 +2033,26 @@
}
};
+struct PipeTypeLocInfo {
+ SourceLocation KWLoc;
+};
+class PipeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, PipeTypeLoc, PipeType,
+ PipeTypeLocInfo> {
+public:
+ TypeLoc getValueLoc() const { return this->getInnerTypeLoc(); }
+
+ SourceRange getLocalSourceRange() const { return SourceRange(getKWLoc()); }
+
+ SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; }
+ void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setKWLoc(Loc);
+ }
+
+ QualType getInnerType() const { return this->getTypePtr()->getElementType(); }
+};
}
#endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 2549f0b..8caf102 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -104,6 +104,7 @@
TYPE(ObjCObject, Type)
TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
+TYPE(Pipe, Type)
TYPE(Atomic, Type)
#ifdef LAST_TYPE
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 8147de4..f0d8227 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -2544,6 +2544,54 @@
return Node.hasGlobalStorage();
}
+/// \brief Matches a variable declaration that has automatic storage duration.
+///
+/// Example matches x, but not y, z, or a.
+/// (matcher = varDecl(hasAutomaticStorageDuration())
+/// \code
+/// void f() {
+/// int x;
+/// static int y;
+/// thread_local int z;
+/// }
+/// int a;
+/// \endcode
+AST_MATCHER(VarDecl, hasAutomaticStorageDuration) {
+ return Node.getStorageDuration() == SD_Automatic;
+}
+
+/// \brief Matches a variable declaration that has static storage duration.
+///
+/// Example matches y and a, but not x or z.
+/// (matcher = varDecl(hasStaticStorageDuration())
+/// \code
+/// void f() {
+/// int x;
+/// static int y;
+/// thread_local int z;
+/// }
+/// int a;
+/// \endcode
+AST_MATCHER(VarDecl, hasStaticStorageDuration) {
+ return Node.getStorageDuration() == SD_Static;
+}
+
+/// \brief Matches a variable declaration that has thread storage duration.
+///
+/// Example matches z, but not x, z, or a.
+/// (matcher = varDecl(hasThreadStorageDuration())
+/// \code
+/// void f() {
+/// int x;
+/// static int y;
+/// thread_local int z;
+/// }
+/// int a;
+/// \endcode
+AST_MATCHER(VarDecl, hasThreadStorageDuration) {
+ return Node.getStorageDuration() == SD_Thread;
+}
+
/// \brief Matches a variable declaration that is an exception variable from
/// a C++ catch block, or an Objective-C \@catch statement.
///
@@ -2823,6 +2871,57 @@
*Node.getParamDecl(N), Finder, Builder));
}
+/// \brief Matches all arguments and their respective ParmVarDecl.
+///
+/// Given
+/// \code
+/// void f(int i);
+/// int y;
+/// f(y);
+/// \endcode
+/// callExpr(declRefExpr(to(varDecl(hasName("y")))),
+/// parmVarDecl(hasType(isInteger())))
+/// matches f(y);
+/// with declRefExpr(...)
+/// matching int y
+/// and parmVarDecl(...)
+/// matching int i
+AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParam,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
+ CXXConstructExpr),
+ internal::Matcher<Expr>, ArgMatcher,
+ internal::Matcher<ParmVarDecl>, ParamMatcher) {
+ BoundNodesTreeBuilder Result;
+ // The first argument of an overloaded member operator is the implicit object
+ // argument of the method which should not be matched against a parameter, so
+ // we skip over it here.
+ BoundNodesTreeBuilder Matches;
+ unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
+ .matches(Node, Finder, &Matches)
+ ? 1
+ : 0;
+ int ParamIndex = 0;
+ bool Matched = false;
+ for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
+ BoundNodesTreeBuilder ArgMatches(*Builder);
+ if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()),
+ Finder, &ArgMatches)) {
+ BoundNodesTreeBuilder ParamMatches(ArgMatches);
+ if (expr(anyOf(cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
+ hasParameter(ParamIndex, ParamMatcher)))),
+ callExpr(callee(functionDecl(
+ hasParameter(ParamIndex, ParamMatcher))))))
+ .matches(Node, Finder, &ParamMatches)) {
+ Result.addMatch(ParamMatches);
+ Matched = true;
+ }
+ }
+ ++ParamIndex;
+ }
+ *Builder = std::move(Result);
+ return Matched;
+}
+
/// \brief Matches any parameter of a function declaration.
///
/// Does not match the 'this' parameter of a method.
@@ -2894,6 +2993,47 @@
return Node.isDeleted();
}
+/// \brief Matches defaulted function declarations.
+///
+/// Given:
+/// \code
+/// class A { ~A(); };
+/// class B { ~B() = default; };
+/// \endcode
+/// functionDecl(isDefaulted())
+/// matches the declaration of ~B, but not ~A.
+AST_MATCHER(FunctionDecl, isDefaulted) {
+ return Node.isDefaulted();
+}
+
+/// \brief Matches functions that have a non-throwing exception specification.
+///
+/// Given:
+/// \code
+/// void f();
+/// void g() noexcept;
+/// void h() throw();
+/// void i() throw(int);
+/// void j() noexcept(false);
+/// \endcode
+/// functionDecl(isNoThrow())
+/// matches the declarations of g, and h, but not f, i or j.
+AST_MATCHER(FunctionDecl, isNoThrow) {
+ const auto *FnTy = Node.getType()->getAs<FunctionProtoType>();
+
+ // If the function does not have a prototype, then it is assumed to be a
+ // throwing function (as it would if the function did not have any exception
+ // specification).
+ if (!FnTy)
+ return false;
+
+ // Assume the best for any unresolved exception specification.
+ if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType()))
+ return true;
+
+ return FnTy->isNothrow(Node.getASTContext());
+}
+
/// \brief Matches constexpr variable and function declarations.
///
/// Given:
@@ -3457,6 +3597,20 @@
return Node->isIntegerType();
}
+/// \brief Matches QualType nodes that are of character type.
+///
+/// Given
+/// \code
+/// void a(char);
+/// void b(wchar_t);
+/// void c(double);
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isAnyCharacter())))
+/// matches "a(char)", "b(wchar_t)", but not "c(double)".
+AST_MATCHER(QualType, isAnyCharacter) {
+ return Node->isAnyCharacterType();
+}
+
/// \brief Matches QualType nodes that are const-qualified, i.e., that
/// include "top-level" const.
///
@@ -3476,6 +3630,25 @@
return Node.isConstQualified();
}
+/// \brief Matches QualType nodes that are volatile-qualified, i.e., that
+/// include "top-level" volatile.
+///
+/// Given
+/// \code
+/// void a(int);
+/// void b(int volatile);
+/// void c(volatile int);
+/// void d(volatile int*);
+/// void e(int volatile) {};
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isVolatileQualified())))
+/// matches "void b(int volatile)", "void c(volatile int)" and
+/// "void e(int volatile) {}". It does not match d as there
+/// is no top-level volatile on the parameter type "volatile int *".
+AST_MATCHER(QualType, isVolatileQualified) {
+ return Node.isVolatileQualified();
+}
+
/// \brief Matches QualType nodes that have local CV-qualifiers attached to
/// the node, not hidden within a typedef.
///
@@ -3653,6 +3826,18 @@
new internal::TypeLocTypeMatcher(InnerMatcher));
}
+/// \brief Matches type \c bool.
+///
+/// Given
+/// \code
+/// struct S { bool func(); };
+/// \endcode
+/// functionDecl(returns(booleanType()))
+/// matches "bool func();"
+AST_MATCHER(Type, booleanType) {
+ return Node.isBooleanType();
+}
+
/// \brief Matches type \c void.
///
/// Given
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 55839c5..1d1d795 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -188,8 +188,11 @@
/// Used by the implementation of Matcher<T> and DynTypedMatcher.
/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T>
/// instead.
-class DynMatcherInterface : public RefCountedBaseVPTR {
+class DynMatcherInterface
+ : public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> {
public:
+ virtual ~DynMatcherInterface() {}
+
/// \brief Returns true if \p DynNode can be matched.
///
/// May bind \p DynNode to an ID via \p Builder, or recurse into
@@ -209,8 +212,6 @@
template <typename T>
class MatcherInterface : public DynMatcherInterface {
public:
- ~MatcherInterface() override {}
-
/// \brief Returns true if 'Node' can be matched.
///
/// May bind 'Node' to an ID via 'Builder', or recurse into
@@ -557,22 +558,32 @@
return false;
}
-/// \brief Metafunction to determine if type T has a member called getDecl.
+// Metafunction to determine if type T has a member called
+// getDecl.
+#if defined(_MSC_VER) && !defined(__clang__)
+// For MSVC, we use a weird nonstandard __if_exists statement, as it
+// is not standards-conformant enough to properly compile the standard
+// code below. (At least up through MSVC 2015 require this workaround)
template <typename T> struct has_getDecl {
- struct Default { int getDecl; };
- struct Derived : T, Default { };
-
- template<typename C, C> struct CheckT;
-
- // If T::getDecl exists, an ambiguity arises and CheckT will
- // not be instantiable. This makes f(...) the only available
- // overload.
- template<typename C>
- static char (&f(CheckT<int Default::*, &C::getDecl>*))[1];
- template<typename C> static char (&f(...))[2];
-
- static bool const value = sizeof(f<Derived>(nullptr)) == 2;
+ __if_exists(T::getDecl) {
+ enum { value = 1 };
+ }
+ __if_not_exists(T::getDecl) {
+ enum { value = 0 };
+ }
};
+#else
+// There is a default template inheriting from "false_type". Then, a
+// partial specialization inherits from "true_type". However, this
+// specialization will only exist when the call to getDecl() isn't an
+// error -- it vanishes by SFINAE when the member doesn't exist.
+template <typename> struct type_sink_to_void { typedef void type; };
+template <typename T, typename = void> struct has_getDecl : std::false_type {};
+template <typename T>
+struct has_getDecl<
+ T, typename type_sink_to_void<decltype(std::declval<T>().getDecl())>::type>
+ : std::true_type {};
+#endif
/// \brief Matches overloaded operators with a specific name.
///
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index f872715..6d816fd 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -33,8 +33,31 @@
class AnalysisDeclContext;
class FunctionDecl;
class LocationContext;
-class ProgramPointTag;
+/// ProgramPoints can be "tagged" as representing points specific to a given
+/// analysis entity. Tags are abstract annotations, with an associated
+/// description and potentially other information.
+class ProgramPointTag {
+public:
+ ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
+ virtual ~ProgramPointTag();
+ virtual StringRef getTagDescription() const = 0;
+
+protected:
+ /// Used to implement 'isKind' in subclasses.
+ const void *getTagKind() { return TagKind; }
+
+private:
+ const void *TagKind;
+};
+
+class SimpleProgramPointTag : public ProgramPointTag {
+ std::string Desc;
+public:
+ SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
+ StringRef getTagDescription() const override;
+};
+
class ProgramPoint {
public:
enum Kind { BlockEdgeKind,
@@ -643,30 +666,6 @@
}
};
-/// ProgramPoints can be "tagged" as representing points specific to a given
-/// analysis entity. Tags are abstract annotations, with an associated
-/// description and potentially other information.
-class ProgramPointTag {
-public:
- ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
- virtual ~ProgramPointTag();
- virtual StringRef getTagDescription() const = 0;
-
-protected:
- /// Used to implement 'isKind' in subclasses.
- const void *getTagKind() { return TagKind; }
-
-private:
- const void *TagKind;
-};
-
-class SimpleProgramPointTag : public ProgramPointTag {
- std::string Desc;
-public:
- SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
- StringRef getTagDescription() const override;
-};
-
} // end namespace clang
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index dba24aa..c612686 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -255,6 +255,7 @@
def TargetMips : TargetArch<["mips", "mipsel"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
+def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
let OSes = ["Win32"];
}
@@ -429,8 +430,8 @@
}
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
- // NOTE: If you add any additional spellings, MSP430Interrupt's spellings
- // must match.
+ // NOTE: If you add any additional spellings, MSP430Interrupt's,
+ // MipsInterrupt's and AnyX86Interrupt's spellings must match.
let Spellings = [GNU<"interrupt">];
let Args = [EnumArgument<"Interrupt", "InterruptType",
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
@@ -849,8 +850,8 @@
}
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
- // NOTE: If you add any additional spellings, ARMInterrupt's spellings must
- // match.
+ // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's
+ // and AnyX86Interrupt's spellings must match.
let Spellings = [GNU<"interrupt">];
let Args = [UnsignedArgument<"Number">];
let ParseKind = "Interrupt";
@@ -864,8 +865,26 @@
let Documentation = [Undocumented];
}
+def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
+ // NOTE: If you add any additional spellings, ARMInterrupt's,
+ // MSP430Interrupt's and AnyX86Interrupt's spellings must match.
+ let Spellings = [GNU<"interrupt">];
+ let Subjects = SubjectList<[Function]>;
+ let Args = [EnumArgument<"Interrupt", "InterruptType",
+ ["vector=sw0", "vector=sw1", "vector=hw0",
+ "vector=hw1", "vector=hw2", "vector=hw3",
+ "vector=hw4", "vector=hw5", "eic", ""],
+ ["sw0", "sw1", "hw0", "hw1", "hw2", "hw3",
+ "hw4", "hw5", "eic", "eic"]
+ >];
+ let ParseKind = "Interrupt";
+ let Documentation = [MipsInterruptDocs];
+}
+
def Mode : Attr {
let Spellings = [GCC<"mode">];
+ let Subjects = SubjectList<[Var, TypedefName, Field], ErrorDiag,
+ "ExpectedVariableFieldOrTypedef">;
let Args = [IdentifierArgument<"Mode">];
let Documentation = [Undocumented];
}
@@ -894,6 +913,13 @@
let Documentation = [Undocumented];
}
+def DisableTailCalls : InheritableAttr {
+ let Spellings = [GNU<"disable_tail_calls">,
+ CXX11<"clang", "disable_tail_calls">];
+ let Subjects = SubjectList<[Function, ObjCMethod]>;
+ let Documentation = [DisableTailCallsDocs];
+}
+
def NoAlias : InheritableAttr {
let Spellings = [Declspec<"noalias">];
let Subjects = SubjectList<[Function]>;
@@ -993,6 +1019,15 @@
let Documentation = [ReturnsNonNullDocs];
}
+// pass_object_size(N) indicates that the parameter should have
+// __builtin_object_size with Type=N evaluated on the parameter at the callsite.
+def PassObjectSize : InheritableParamAttr {
+ let Spellings = [GNU<"pass_object_size">];
+ let Args = [IntArgument<"Type">];
+ let Subjects = SubjectList<[ParmVar]>;
+ let Documentation = [PassObjectSizeDocs];
+}
+
// Nullability type attributes.
def TypeNonNull : TypeAttr {
let Spellings = [Keyword<"_Nonnull">];
@@ -1074,8 +1109,8 @@
let Spellings = [GNU<"objc_bridge_related">];
let Subjects = SubjectList<[Record], ErrorDiag>;
let Args = [IdentifierArgument<"RelatedClass">,
- IdentifierArgument<"ClassMethod">,
- IdentifierArgument<"InstanceMethod">];
+ IdentifierArgument<"ClassMethod", 1>,
+ IdentifierArgument<"InstanceMethod", 1>];
let HasCustomParsing = 1;
let Documentation = [Undocumented];
}
@@ -1547,6 +1582,16 @@
let Documentation = [Undocumented];
}
+def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
+ // NOTE: If you add any additional spellings, ARMInterrupt's,
+ // MSP430Interrupt's and MipsInterrupt's spellings must match.
+ let Spellings = [GNU<"interrupt">];
+ let Subjects = SubjectList<[HasFunctionProto]>;
+ let ParseKind = "Interrupt";
+ let HasCustomParsing = 1;
+ let Documentation = [AnyX86InterruptDocs];
+}
+
def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
let Spellings = [GNU<"force_align_arg_pointer">];
// Technically, this appertains to a FunctionDecl, but the target-specific
@@ -2184,3 +2229,9 @@
let SemaHandler = 0;
let Documentation = [Undocumented];
}
+
+def InternalLinkage : InheritableAttr {
+ let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
+ let Subjects = SubjectList<[Var, Function, CXXRecord]>;
+ let Documentation = [InternalLinkageDocs];
+}
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 707a547..08cd99b 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -263,6 +263,103 @@
}];
}
+def PassObjectSizeDocs : Documentation {
+ let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
+ let Content = [{
+.. Note:: The mangling of functions with parameters that are annotated with
+ ``pass_object_size`` is subject to change. You can get around this by
+ using ``__asm__("foo")`` to explicitly name your functions, thus preserving
+ your ABI; also, non-overloadable C functions with ``pass_object_size`` are
+ not mangled.
+
+The ``pass_object_size(Type)`` attribute can be placed on function parameters to
+instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite
+of said function, and implicitly pass the result of this call in as an invisible
+argument of type ``size_t`` directly after the parameter annotated with
+``pass_object_size``. Clang will also replace any calls to
+``__builtin_object_size(param, Type)`` in the function by said implicit
+parameter.
+
+Example usage:
+
+.. code-block:: c
+
+ int bzero1(char *const p __attribute__((pass_object_size(0))))
+ __attribute__((noinline)) {
+ int i = 0;
+ for (/**/; i < (int)__builtin_object_size(p, 0); ++i) {
+ p[i] = 0;
+ }
+ return i;
+ }
+
+ int main() {
+ char chars[100];
+ int n = bzero1(&chars[0]);
+ assert(n == sizeof(chars));
+ return 0;
+ }
+
+If successfully evaluating ``__builtin_object_size(param, Type)`` at the
+callsite is not possible, then the "failed" value is passed in. So, using the
+definition of ``bzero1`` from above, the following code would exit cleanly:
+
+.. code-block:: c
+
+ int main2(int argc, char *argv[]) {
+ int n = bzero1(argv);
+ assert(n == -1);
+ return 0;
+ }
+
+``pass_object_size`` plays a part in overload resolution. If two overload
+candidates are otherwise equally good, then the overload with one or more
+parameters with ``pass_object_size`` is preferred. This implies that the choice
+between two identical overloads both with ``pass_object_size`` on one or more
+parameters will always be ambiguous; for this reason, having two such overloads
+is illegal. For example:
+
+.. code-block:: c++
+
+ #define PS(N) __attribute__((pass_object_size(N)))
+ // OK
+ void Foo(char *a, char *b); // Overload A
+ // OK -- overload A has no parameters with pass_object_size.
+ void Foo(char *a PS(0), char *b PS(0)); // Overload B
+ // Error -- Same signature (sans pass_object_size) as overload B, and both
+ // overloads have one or more parameters with the pass_object_size attribute.
+ void Foo(void *a PS(0), void *b);
+
+ // OK
+ void Bar(void *a PS(0)); // Overload C
+ // OK
+ void Bar(char *c PS(1)); // Overload D
+
+ void main() {
+ char known[10], *unknown;
+ Foo(unknown, unknown); // Calls overload B
+ Foo(known, unknown); // Calls overload B
+ Foo(unknown, known); // Calls overload B
+ Foo(known, known); // Calls overload B
+
+ Bar(known); // Calls overload D
+ Bar(unknown); // Calls overload D
+ }
+
+Currently, ``pass_object_size`` is a bit restricted in terms of its usage:
+
+* Only one use of ``pass_object_size`` is allowed per parameter.
+
+* It is an error to take the address of a function with ``pass_object_size`` on
+ any of its parameters. If you wish to do this, you can create an overload
+ without ``pass_object_size`` on any parameters.
+
+* It is an error to apply the ``pass_object_size`` attribute to parameters that
+ are not pointers. Additionally, any parameter that ``pass_object_size`` is
+ applied to must be marked ``const`` at its function's definition.
+ }];
+}
+
def OverloadableDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -714,6 +811,46 @@
}];
}
+def MipsInterruptDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
+MIPS targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+By default, the compiler will produce a function prologue and epilogue suitable for
+an interrupt service routine that handles an External Interrupt Controller (eic)
+generated interrupt. This behaviour can be explicitly requested with the "eic"
+argument.
+
+Otherwise, for use with vectored interrupt mode, the argument passed should be
+of the form "vector=LEVEL" where LEVEL is one of the following values:
+"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will
+then set the interrupt mask to the corresponding level which will mask all
+interrupts up to and including the argument.
+
+The semantics are as follows:
+
+- The prologue is modified so that the Exception Program Counter (EPC) and
+ Status coprocessor registers are saved to the stack. The interrupt mask is
+ set so that the function can only be interrupted by a higher priority
+ interrupt. The epilogue will restore the previous values of EPC and Status.
+
+- The prologue and epilogue are modified to save and restore all non-kernel
+ registers as necessary.
+
+- The FPU is disabled in the prologue, as the floating pointer registers are not
+ spilled to the stack.
+
+- The function return sequence is changed to use an exception return instruction.
+
+- The parameter sets the interrupt mask for the function corresponding to the
+ interrupt level specified. If no mask is specified the interrupt mask
+ defaults to "eic".
+ }];
+}
+
def TargetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -1661,7 +1798,9 @@
The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``.
For example, it prevents tail-call optimization in the following case:
+
.. code-block: c
+
int __attribute__((not_tail_called)) foo1(int);
int foo2(int a) {
@@ -1669,7 +1808,9 @@
}
However, it doesn't prevent tail-call optimization in this case:
+
.. code-block: c
+
int __attribute__((not_tail_called)) foo1(int);
int foo2(int a) {
@@ -1681,7 +1822,9 @@
}
Marking virtual functions as ``not_tail_called`` is an error:
+
.. code-block: c++
+
class Base {
public:
// not_tail_called on a virtual function is an error.
@@ -1700,6 +1843,106 @@
// not_tail_called on a virtual function is an error.
[[clang::not_tail_called]] int foo2() override;
};
+ }];
+}
+def InternalLinkageDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``internal_linkage`` attribute changes the linkage type of the declaration to internal.
+This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition,
+this attribute affects all methods and static data members of that class.
+This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables.
+ }];
+}
+
+def DisableTailCallsDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function.
+
+For example:
+
+ .. code-block:: c
+
+ int callee(int);
+
+ int foo(int a) __attribute__((disable_tail_calls)) {
+ return callee(a); // This call is not tail-call optimized.
+ }
+
+Marking virtual functions as ``disable_tail_calls`` is legal.
+
+ .. code-block: c++
+
+ int callee(int);
+
+ class Base {
+ public:
+ [[clang::disable_tail_calls]] virtual int foo1() {
+ return callee(); // This call is not tail-call optimized.
+ }
+ };
+
+ class Derived1 : public Base {
+ public:
+ int foo1() override {
+ return callee(); // This call is tail-call optimized.
+ }
+ };
+
+ }];
+}
+
+def AnyX86InterruptDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
+x86/x86-64 targets.The compiler generates function entry and exit sequences
+suitable for use in an interrupt handler when this attribute is present.
+The 'IRET' instruction, instead of the 'RET' instruction, is used to return
+from interrupt or exception handlers. All registers, except for the EFLAGS
+register which is restored by the 'IRET' instruction, are preserved by the
+compiler.
+
+Any interruptible-without-stack-switch code must be compiled with
+-mno-red-zone since interrupt handlers can and will, because of the
+hardware design, touch the red zone.
+
+1. interrupt handler must be declared with a mandatory pointer argument:
+
+ .. code-block:: c
+
+ struct interrupt_frame
+ {
+ uword_t ip;
+ uword_t cs;
+ uword_t flags;
+ uword_t sp;
+ uword_t ss;
+ };
+
+ __attribute__ ((interrupt))
+ void f (struct interrupt_frame *frame) {
+ ...
+ }
+
+2. exception handler:
+
+ The exception handler is very similar to the interrupt handler with
+ a different mandatory function signature:
+
+ .. code-block:: c
+
+ __attribute__ ((interrupt))
+ void f (struct interrupt_frame *frame, uword_t error_code) {
+ ...
+ }
+
+ and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction.
+
+ The exception handler should only be used for exceptions which push an
+ error code and all other exceptions must use the interrupt handler.
+ The system will crash if the wrong handler is used.
}];
}
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 41f19e7..c0a6af9 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -192,6 +192,10 @@
/// for AuxTarget).
unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); }
+ /// Returns true if this is a libc/libm function without the '__builtin_'
+ /// prefix.
+ static bool isBuiltinFunc(const char *Name);
+
private:
const Info &getRecord(unsigned ID) const;
diff --git a/include/clang/Basic/BuiltinsHexagon.def b/include/clang/Basic/BuiltinsHexagon.def
index c071a46..c4f0324 100644
--- a/include/clang/Basic/BuiltinsHexagon.def
+++ b/include/clang/Basic/BuiltinsHexagon.def
@@ -23,52 +23,52 @@
// The builtins above are not autogenerated from iset.py.
// Make sure you do not overwrite these.
-BUILTIN(__builtin_HEXAGON_C2_cmpeq,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgt,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgtu,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpeqp,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgtp,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgtup,"bLLiLLi","")
+BUILTIN(__builtin_HEXAGON_C2_cmpeq,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgt,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtu,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpeqp,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtp,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtup,"iLLiLLi","")
BUILTIN(__builtin_HEXAGON_A4_rcmpeqi,"iii","")
BUILTIN(__builtin_HEXAGON_A4_rcmpneqi,"iii","")
BUILTIN(__builtin_HEXAGON_A4_rcmpeq,"iii","")
BUILTIN(__builtin_HEXAGON_A4_rcmpneq,"iii","")
-BUILTIN(__builtin_HEXAGON_C2_bitsset,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_bitsclr,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_nbitsset,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_nbitsclr,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpeqi,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgti,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgtui,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgei,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpgeui,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmplt,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_cmpltu,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_bitsclri,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_nbitsclri,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmpneqi,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmpltei,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmplteui,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmpneq,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmplte,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_cmplteu,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_and,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_or,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_xor,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_andn,"bii","")
-BUILTIN(__builtin_HEXAGON_C2_not,"bi","")
-BUILTIN(__builtin_HEXAGON_C2_orn,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_and_and,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_and_or,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_or_and,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_or_or,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_and_andn,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_and_orn,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_or_andn,"biii","")
-BUILTIN(__builtin_HEXAGON_C4_or_orn,"biii","")
-BUILTIN(__builtin_HEXAGON_C2_pxfer_map,"bi","")
-BUILTIN(__builtin_HEXAGON_C2_any8,"bi","")
-BUILTIN(__builtin_HEXAGON_C2_all8,"bi","")
+BUILTIN(__builtin_HEXAGON_C2_bitsset,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_bitsclr,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_nbitsset,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_nbitsclr,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpeqi,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgti,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtui,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgei,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpgeui,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmplt,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_cmpltu,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_bitsclri,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_nbitsclri,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmpneqi,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmpltei,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmplteui,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmpneq,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmplte,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_cmplteu,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_and,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_or,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_xor,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_andn,"iii","")
+BUILTIN(__builtin_HEXAGON_C2_not,"ii","")
+BUILTIN(__builtin_HEXAGON_C2_orn,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_and_and,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_and_or,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_or_and,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_or_or,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_and_andn,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_and_orn,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_or_andn,"iiii","")
+BUILTIN(__builtin_HEXAGON_C4_or_orn,"iiii","")
+BUILTIN(__builtin_HEXAGON_C2_pxfer_map,"ii","")
+BUILTIN(__builtin_HEXAGON_C2_any8,"ii","")
+BUILTIN(__builtin_HEXAGON_C2_all8,"ii","")
BUILTIN(__builtin_HEXAGON_C2_vitpack,"iii","")
BUILTIN(__builtin_HEXAGON_C2_mux,"iiii","")
BUILTIN(__builtin_HEXAGON_C2_muxii,"iiii","")
@@ -76,43 +76,43 @@
BUILTIN(__builtin_HEXAGON_C2_muxri,"iiii","")
BUILTIN(__builtin_HEXAGON_C2_vmux,"LLiiLLiLLi","")
BUILTIN(__builtin_HEXAGON_C2_mask,"LLii","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpbeq,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpbeqi,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpbeq_any,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpbgtu,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpbgtui,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpbgt,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpbgti,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbeq,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbeqi,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbgtu,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbgtui,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbgt,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpbgti,"bii","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpheq,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A2_vcmphgt,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A2_vcmphgtu,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpheqi,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmphgti,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmphgtui,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpheq,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmphgt,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmphgtu,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmpheqi,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmphgti,"bii","")
-BUILTIN(__builtin_HEXAGON_A4_cmphgtui,"bii","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpweq,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpwgt,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A2_vcmpwgtu,"bLLiLLi","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpweqi,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpwgti,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_vcmpwgtui,"bLLii","")
-BUILTIN(__builtin_HEXAGON_A4_boundscheck,"biLLi","")
-BUILTIN(__builtin_HEXAGON_A4_tlbmatch,"bLLii","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpbeq,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpbeqi,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpbeq_any,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpbgtu,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpbgtui,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpbgt,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpbgti,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbeq,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbeqi,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbgtu,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbgtui,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbgt,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpbgti,"iii","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpheq,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A2_vcmphgt,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A2_vcmphgtu,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpheqi,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmphgti,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmphgtui,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpheq,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmphgt,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmphgtu,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmpheqi,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmphgti,"iii","")
+BUILTIN(__builtin_HEXAGON_A4_cmphgtui,"iii","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpweq,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpwgt,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A2_vcmpwgtu,"iLLiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpweqi,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpwgti,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_vcmpwgtui,"iLLii","")
+BUILTIN(__builtin_HEXAGON_A4_boundscheck,"iiLLi","")
+BUILTIN(__builtin_HEXAGON_A4_tlbmatch,"iLLii","")
BUILTIN(__builtin_HEXAGON_C2_tfrpr,"ii","")
-BUILTIN(__builtin_HEXAGON_C2_tfrrp,"bi","")
-BUILTIN(__builtin_HEXAGON_C4_fastcorner9,"bii","")
-BUILTIN(__builtin_HEXAGON_C4_fastcorner9_not,"bii","")
+BUILTIN(__builtin_HEXAGON_C2_tfrrp,"ii","")
+BUILTIN(__builtin_HEXAGON_C4_fastcorner9,"iii","")
+BUILTIN(__builtin_HEXAGON_C4_fastcorner9_not,"iii","")
BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s0,"iiii","")
BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s1,"iiii","")
BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s0,"iiii","")
@@ -620,13 +620,13 @@
BUILTIN(__builtin_HEXAGON_F2_sffms,"ffff","")
BUILTIN(__builtin_HEXAGON_F2_sffma_lib,"ffff","")
BUILTIN(__builtin_HEXAGON_F2_sffms_lib,"ffff","")
-BUILTIN(__builtin_HEXAGON_F2_sfcmpeq,"bff","")
-BUILTIN(__builtin_HEXAGON_F2_sfcmpgt,"bff","")
-BUILTIN(__builtin_HEXAGON_F2_sfcmpge,"bff","")
-BUILTIN(__builtin_HEXAGON_F2_sfcmpuo,"bff","")
+BUILTIN(__builtin_HEXAGON_F2_sfcmpeq,"iff","")
+BUILTIN(__builtin_HEXAGON_F2_sfcmpgt,"iff","")
+BUILTIN(__builtin_HEXAGON_F2_sfcmpge,"iff","")
+BUILTIN(__builtin_HEXAGON_F2_sfcmpuo,"iff","")
BUILTIN(__builtin_HEXAGON_F2_sfmax,"fff","")
BUILTIN(__builtin_HEXAGON_F2_sfmin,"fff","")
-BUILTIN(__builtin_HEXAGON_F2_sfclass,"bfi","")
+BUILTIN(__builtin_HEXAGON_F2_sfclass,"ifi","")
BUILTIN(__builtin_HEXAGON_F2_sfimm_p,"fi","")
BUILTIN(__builtin_HEXAGON_F2_sfimm_n,"fi","")
BUILTIN(__builtin_HEXAGON_F2_sffixupn,"fff","")
@@ -642,11 +642,11 @@
BUILTIN(__builtin_HEXAGON_F2_dffma_sc,"ddddi","")
BUILTIN(__builtin_HEXAGON_F2_dfmax,"ddd","")
BUILTIN(__builtin_HEXAGON_F2_dfmin,"ddd","")
-BUILTIN(__builtin_HEXAGON_F2_dfcmpeq,"bdd","")
-BUILTIN(__builtin_HEXAGON_F2_dfcmpgt,"bdd","")
-BUILTIN(__builtin_HEXAGON_F2_dfcmpge,"bdd","")
-BUILTIN(__builtin_HEXAGON_F2_dfcmpuo,"bdd","")
-BUILTIN(__builtin_HEXAGON_F2_dfclass,"bdi","")
+BUILTIN(__builtin_HEXAGON_F2_dfcmpeq,"idd","")
+BUILTIN(__builtin_HEXAGON_F2_dfcmpgt,"idd","")
+BUILTIN(__builtin_HEXAGON_F2_dfcmpge,"idd","")
+BUILTIN(__builtin_HEXAGON_F2_dfcmpuo,"idd","")
+BUILTIN(__builtin_HEXAGON_F2_dfclass,"idi","")
BUILTIN(__builtin_HEXAGON_F2_dfimm_p,"di","")
BUILTIN(__builtin_HEXAGON_F2_dfimm_n,"di","")
BUILTIN(__builtin_HEXAGON_F2_dffixupn,"ddd","")
@@ -797,13 +797,13 @@
BUILTIN(__builtin_HEXAGON_S2_insertp_rp,"LLiLLiLLiLLi","")
BUILTIN(__builtin_HEXAGON_S4_extractp_rp,"LLiLLiLLi","")
BUILTIN(__builtin_HEXAGON_S2_extractup_rp,"LLiLLiLLi","")
-BUILTIN(__builtin_HEXAGON_S2_tstbit_i,"bii","")
-BUILTIN(__builtin_HEXAGON_S4_ntstbit_i,"bii","")
+BUILTIN(__builtin_HEXAGON_S2_tstbit_i,"iii","")
+BUILTIN(__builtin_HEXAGON_S4_ntstbit_i,"iii","")
BUILTIN(__builtin_HEXAGON_S2_setbit_i,"iii","")
BUILTIN(__builtin_HEXAGON_S2_togglebit_i,"iii","")
BUILTIN(__builtin_HEXAGON_S2_clrbit_i,"iii","")
-BUILTIN(__builtin_HEXAGON_S2_tstbit_r,"bii","")
-BUILTIN(__builtin_HEXAGON_S4_ntstbit_r,"bii","")
+BUILTIN(__builtin_HEXAGON_S2_tstbit_r,"iii","")
+BUILTIN(__builtin_HEXAGON_S4_ntstbit_r,"iii","")
BUILTIN(__builtin_HEXAGON_S2_setbit_r,"iii","")
BUILTIN(__builtin_HEXAGON_S2_togglebit_r,"iii","")
BUILTIN(__builtin_HEXAGON_S2_clrbit_r,"iii","")
diff --git a/include/clang/Basic/BuiltinsWebAssembly.def b/include/clang/Basic/BuiltinsWebAssembly.def
index 58171c8..9754335 100644
--- a/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/include/clang/Basic/BuiltinsWebAssembly.def
@@ -16,7 +16,9 @@
// The format of this database matches clang/Basic/Builtins.def.
-BUILTIN(__builtin_wasm_memory_size, "z", "nc")
+// Note that memory_size is not "c" (readnone) because it must be sequenced with
+// respect to grow_memory calls.
+BUILTIN(__builtin_wasm_memory_size, "z", "n")
BUILTIN(__builtin_wasm_grow_memory, "vz", "n")
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 2c7c394..f738cc1 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -41,6 +41,13 @@
TARGET_BUILTIN(__builtin_ia32_undef256, "V4d", "nc", "")
TARGET_BUILTIN(__builtin_ia32_undef512, "V8d", "nc", "")
+// FLAGS
+//
+TARGET_BUILTIN(__builtin_ia32_readeflags_u32, "Ui", "n", "")
+TARGET_BUILTIN(__builtin_ia32_readeflags_u64, "ULLi", "n", "")
+TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "")
+TARGET_BUILTIN(__builtin_ia32_writeeflags_u64, "vULLi", "n", "")
+
// 3DNow!
//
TARGET_BUILTIN(__builtin_ia32_femms, "v", "", "3dnow")
@@ -336,6 +343,7 @@
TARGET_BUILTIN(__builtin_ia32_clflush, "vvC*", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_lfence, "v", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_mfence, "v", "", "sse2")
+TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "", "sse2")
@@ -596,7 +604,7 @@
TARGET_BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLiC*", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8f", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_maskloadq256, "V4LLiV4LLiC*V4LLi", "", "avx2")
@@ -618,23 +626,23 @@
TARGET_BUILTIN(__builtin_ia32_psrlv2di, "V2LLiV2LLiV2LLi", "", "avx2")
// GATHER
-TARGET_BUILTIN(__builtin_ia32_gatherd_pd, "V2dV2dV2dC*V4iV2dIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_pd256, "V4dV4dV4dC*V4iV4dIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_pd, "V2dV2dV2dC*V2LLiV2dIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_pd256, "V4dV4dV4dC*V4LLiV4dIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_ps, "V4fV4fV4fC*V4iV4fIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_ps256, "V8fV8fV8fC*V8iV8fIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_ps, "V4fV4fV4fC*V2LLiV4fIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_ps256, "V4fV4fV4fC*V4LLiV4fIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_pd, "V2dV2ddC*V4iV2dIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_pd256, "V4dV4ddC*V4iV4dIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_pd, "V2dV2ddC*V2LLiV2dIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_pd256, "V4dV4ddC*V4LLiV4dIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_ps, "V4fV4ffC*V4iV4fIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_ps256, "V8fV8ffC*V8iV8fIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_ps, "V4fV4ffC*V2LLiV4fIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_ps256, "V4fV4ffC*V4LLiV4fIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_q, "V2LLiV2LLiV2LLiC*V4iV2LLiIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_q256, "V4LLiV4LLiV4LLiC*V4iV4LLiIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_q, "V2LLiV2LLiV2LLiC*V2LLiV2LLiIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_q256, "V4LLiV4LLiV4LLiC*V4LLiV4LLiIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_d, "V4iV4iV4iC*V4iV4iIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iV8iC*V8iV8iIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iV4iC*V2LLiV4iIc", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_q, "V2LLiV2LLiLLiC*V4iV2LLiIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_q256, "V4LLiV4LLiLLiC*V4iV4LLiIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_q, "V2LLiV2LLiLLiC*V2LLiV2LLiIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_q256, "V4LLiV4LLiLLiC*V4LLiV4LLiIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_d, "V4iV4iiC*V4iV4iIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iiC*V8iV8iIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iiC*V2LLiV4iIc", "", "avx2")
+TARGET_BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iiC*V4LLiV4iIc", "", "avx2")
// F16C
TARGET_BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "", "f16c")
@@ -916,27 +924,30 @@
BUILTIN(__builtin_ia32_rdpmc, "ULLii", "")
BUILTIN(__builtin_ia32_rdtsc, "ULLi", "")
BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "")
+// PKU
+TARGET_BUILTIN(__builtin_ia32_rdpkru, "Ui", "", "pku")
+TARGET_BUILTIN(__builtin_ia32_wrpkru, "vUi", "", "pku")
// AVX-512
TARGET_BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUcIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_rsqrt14sd_mask, "V2dV2dV2dV2dUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_rsqrt14ss_mask, "V4fV4fV4fV4fUc", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_rsqrt14sd, "V2dV2dV2dV2dUc", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_rsqrt14ss, "V4fV4fV4fV4fUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_rsqrt28sd_mask, "V2dV2dV2dV2dUcIi", "", "avx512er")
-TARGET_BUILTIN(__builtin_ia32_rsqrt28ss_mask, "V4fV4fV4fV4fUcIi", "", "avx512er")
+TARGET_BUILTIN(__builtin_ia32_rsqrt28sd_round, "V2dV2dV2dV2dUcIi", "", "avx512er")
+TARGET_BUILTIN(__builtin_ia32_rsqrt28ss_round, "V4fV4fV4fV4fUcIi", "", "avx512er")
TARGET_BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUcIi", "", "avx512er")
TARGET_BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsIi", "", "avx512er")
-TARGET_BUILTIN(__builtin_ia32_rcp14sd_mask, "V2dV2dV2dV2dUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_rcp14ss_mask, "V4fV4fV4fV4fUc", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_rcp14sd, "V2dV2dV2dV2dUc", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_rcp14ss, "V4fV4fV4fV4fUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_rcp28sd_mask, "V2dV2dV2dV2dUcIi", "", "avx512er")
-TARGET_BUILTIN(__builtin_ia32_rcp28ss_mask, "V4fV4fV4fV4fUcIi", "", "avx512er")
+TARGET_BUILTIN(__builtin_ia32_rcp28sd_round, "V2dV2dV2dV2dUcIi", "", "avx512er")
+TARGET_BUILTIN(__builtin_ia32_rcp28ss_round, "V4fV4fV4fV4fUcIi", "", "avx512er")
TARGET_BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUcIi", "", "avx512er")
TARGET_BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsIi", "", "avx512er")
TARGET_BUILTIN(__builtin_ia32_exp2pd_mask, "V8dV8dV8dUcIi", "", "avx512er")
@@ -1299,18 +1310,18 @@
TARGET_BUILTIN(__builtin_ia32_pmaddubsw512_mask, "V32sV64cV64cV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pmaddwd512_mask, "V16iV32sV32sV16iUs", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_addss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_divss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_mulss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_subss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_maxss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_minss_mask, "V4fV4fV4fV4fUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_addsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_divsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_mulsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_subsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_maxsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_minsd_mask, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_addss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_divss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_mulss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_subss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_maxss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_minss_round, "V4fV4fV4fV4fUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_addsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_divsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_mulsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_subsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_maxsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
+TARGET_BUILTIN(__builtin_ia32_minsd_round, "V2dV2dV2dV2dUcIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_addpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl")
TARGET_BUILTIN(__builtin_ia32_addpd256_mask, "V4dV4dV4dV4dUc", "", "avx512vl")
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index e7d9354..9d8dbc5 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -220,5 +220,5 @@
// OpenMP
def err_omp_more_one_clause : Error<
- "directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier}2">;
+ "directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">;
}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 7a71285..b04498f 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -22,6 +22,7 @@
def err_drv_unknown_language : Error<"language not recognized: '%0'">;
def err_drv_invalid_arch_name : Error<
"invalid arch name '%0'">;
+def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
def err_drv_invalid_thread_model_for_target : Error<
"invalid thread model '%0' in '%1' for this target">;
def err_drv_invalid_linker_name : Error<
@@ -123,6 +124,9 @@
def err_drv_optimization_remark_pattern : Error<
"%0 in '%1'">;
def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">;
+def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">;
+def err_drv_omp_host_ir_file_not_found : Error<
+ "The provided host compiler IR file '%0' is required to generate code for OpenMP target regions but cannot be found.">;
def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
def warn_drv_lto_libpath : Warning<"libLTO.dylib relative to clang installed dir not found; using 'ld' default search path instead">,
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 4b94b18..2e4e57b 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -24,6 +24,7 @@
def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">;
def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
+def GNUAutoType : DiagGroup<"gnu-auto-type">;
def ArrayBounds : DiagGroup<"array-bounds">;
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
def Availability : DiagGroup<"availability">;
@@ -82,6 +83,7 @@
def CXX11CompatDeprecatedWritableStr :
DiagGroup<"c++11-compat-deprecated-writable-strings">;
+def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
def PartialAvailability : DiagGroup<"partial-availability">;
@@ -91,7 +93,8 @@
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
// FIXME: Why is DeprecatedImplementations not in this group?
-def Deprecated : DiagGroup<"deprecated", [DeprecatedDeclarations,
+def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes,
+ DeprecatedDeclarations,
DeprecatedIncrementBool,
DeprecatedRegister,
DeprecatedWritableStr]>,
@@ -184,6 +187,9 @@
def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic",
[CXXPre1zCompatPedantic]>;
+def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister,
+ DeprecatedIncrementBool]>;
+
def : DiagGroup<"effc++">;
def DivZero : DiagGroup<"division-by-zero">;
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
@@ -199,6 +205,7 @@
def DanglingField : DiagGroup<"dangling-field">;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
def FlagEnum : DiagGroup<"flag-enum">;
+def IncrementBool : DiagGroup<"increment-bool", [DeprecatedIncrementBool]>;
def InfiniteRecursion : DiagGroup<"infinite-recursion">;
def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
@@ -311,6 +318,7 @@
def RedeclaredClassMember : DiagGroup<"redeclared-class-member">;
def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">;
def RedundantMove : DiagGroup<"redundant-move">;
+def Register : DiagGroup<"register", [DeprecatedRegister]>;
def ReturnStackAddress : DiagGroup<"return-stack-address">;
def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
@@ -608,6 +616,7 @@
CharSubscript,
Comment,
DeleteNonVirtualDtor,
+ ForLoopAnalysis,
Format,
Implicit,
InfiniteRecursion,
@@ -655,7 +664,10 @@
// Note that putting warnings in -Wall will not disable them by default. If a
// warning should be active _only_ when -Wall is passed in, mark it as
// DefaultIgnore in addition to putting it here.
-def : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool]>;
+def All : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool]>;
+
+// Warnings that should be in clang-cl /w4.
+def : DiagGroup<"CL4", [All, Extra]>;
// Warnings enabled by -pedantic. This is magically filled in by TableGen.
def Pedantic : DiagGroup<"pedantic">;
@@ -707,6 +719,7 @@
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
+ GNUAutoType,
GNUBinaryLiteral, GNUCaseRange,
GNUComplexInteger, GNUCompoundLiteralInitializer,
GNUConditionalOmittedOperand, GNUDesignator,
@@ -753,6 +766,8 @@
def MicrosoftConstInit : DiagGroup<"microsoft-const-init">;
def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">;
def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">;
+def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">;
+def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">;
// Aliases.
def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
// -Wmsvc-include = -Wmicrosoft-include
@@ -766,7 +781,8 @@
MicrosoftEnumValue, MicrosoftDefaultArgRedefinition, MicrosoftTemplate,
MicrosoftRedeclareStatic, MicrosoftEnumForwardReference, MicrosoftGoto,
MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast,
- MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag]>;
+ MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag,
+ MicrosoftCommentPaste, MicrosoftEndOfFile]>;
def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index a675dfa..312b71f 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -29,7 +29,7 @@
enum {
DIAG_START_COMMON = 0,
DIAG_START_DRIVER = DIAG_START_COMMON + 300,
- DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + 200,
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 77090e9..2fc9664 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -13,9 +13,8 @@
let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in {
-def null_in_string : Warning<"null character(s) preserved in string literal">,
- InGroup<NullCharacter>;
-def null_in_char : Warning<"null character(s) preserved in character literal">,
+def null_in_char_or_string : Warning<
+ "null character(s) preserved in %select{char|string}0 literal">,
InGroup<NullCharacter>;
def null_in_file : Warning<"null character ignored">, InGroup<NullCharacter>;
def warn_nested_block_comment : Warning<"'/*' within block comment">,
@@ -60,6 +59,12 @@
def ext_charize_microsoft : Extension<
"charizing operator #@ is a Microsoft extension">,
InGroup<MicrosoftCharize>;
+def ext_comment_paste_microsoft : Extension<
+ "pasting two '/' tokens into a '//' comment is a Microsoft extension">,
+ InGroup<MicrosoftCommentPaste>;
+def ext_ctrl_z_eof_microsoft : Extension<
+ "treating Ctrl-Z as end-of-file is a Microsoft extension">,
+ InGroup<MicrosoftEndOfFile>;
def ext_token_used : Extension<"extension used">,
InGroup<DiagGroup<"language-extension-token">>;
@@ -67,10 +72,8 @@
def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
InGroup<CXX11Compat>, DefaultIgnore;
-def ext_unterminated_string : ExtWarn<"missing terminating '\"' character">,
- InGroup<InvalidPPToken>;
-def ext_unterminated_char : ExtWarn<"missing terminating ' character">,
- InGroup<InvalidPPToken>;
+def ext_unterminated_char_or_string : ExtWarn<
+ "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>;
def ext_empty_character : ExtWarn<"empty character constant">,
InGroup<InvalidPPToken>;
def err_unterminated_block_comment : Error<"unterminated /* comment">;
@@ -154,13 +157,10 @@
"use of non-standard escape character '\\%0'">;
def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">,
InGroup<DiagGroup<"unknown-escape-sequence">>;
-def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">;
-def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">;
-def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">;
-def err_invalid_suffix_integer_constant : Error<
- "invalid suffix '%0' on integer constant">;
-def err_invalid_suffix_float_constant : Error<
- "invalid suffix '%0' on floating constant">;
+def err_invalid_digit : Error<
+ "invalid digit '%0' in %select{decimal|octal|binary}1 constant">;
+def err_invalid_suffix_constant : Error<
+ "invalid suffix '%0' on %select{integer|floating}1 constant">;
def warn_cxx11_compat_digit_separator : Warning<
"digit separators are incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
@@ -175,10 +175,8 @@
def err_exponent_has_no_digits : Error<"exponent has no digits">;
def ext_imaginary_constant : Extension<
"imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
-def err_hexconstant_requires_exponent : Error<
- "hexadecimal floating constants require an exponent">;
-def err_hexconstant_requires_digits : Error<
- "hexadecimal floating constants require a significand">;
+def err_hexconstant_requires: Error<
+ "hexadecimal floating constants require %select{an exponent|a significand}0">;
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_binary_literal : Extension<
@@ -189,8 +187,8 @@
"binary integer literals are incompatible with C++ standards before C++14">,
InGroup<CXXPre14CompatPedantic>, DefaultIgnore;
def err_pascal_string_too_long : Error<"Pascal string is too long">;
-def err_octal_escape_too_large : Error<"octal escape sequence out of range">;
-def err_hex_escape_too_large : Error<"hex escape sequence out of range">;
+def err_escape_too_large : Error<
+ "%select{hex|octal}0 escape sequence out of range">;
def ext_string_too_long : Extension<"string literal of length %0 exceeds "
"maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to "
"support">, InGroup<OverlengthStrings>;
@@ -301,15 +299,17 @@
def warn_pp_macro_is_reserved_id : Warning<
"macro name is a reserved identifier">, DefaultIgnore,
InGroup<ReservedIdAsMacro>;
+def warn_pp_objc_macro_redef_ignored : Warning<
+ "ignoring redefinition of Objective-C qualifier macro">,
+ InGroup<DiagGroup<"objc-macro-redefinition">>;
def pp_invalid_string_literal : Warning<
"invalid string literal, ignoring final '\\'">;
def warn_pp_expr_overflow : Warning<
"integer overflow in preprocessor expression">;
-def warn_pp_convert_lhs_to_positive : Warning<
- "left side of operator converted from negative value to unsigned: %0">;
-def warn_pp_convert_rhs_to_positive : Warning<
- "right side of operator converted from negative value to unsigned: %0">;
+def warn_pp_convert_to_positive : Warning<
+ "%select{left|right}0 side of operator converted from negative value to "
+ "unsigned: %1">;
def ext_pp_import_directive : Extension<"#import is a language extension">,
InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>;
@@ -490,6 +490,8 @@
// - #pragma __debug
def warn_pragma_debug_unexpected_command : Warning<
"unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
+def warn_pragma_debug_missing_argument : Warning<
+ "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
def err_paste_at_start : Error<
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index f4cd16b..f8dee2f 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -51,14 +51,6 @@
"extra ';' after member function definition">,
InGroup<ExtraSemi>, DefaultIgnore;
-def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">,
- InGroup<DuplicateDeclSpecifier>;
-def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">,
- InGroup<DuplicateDeclSpecifier>;
-def ext_plain_complex : ExtWarn<
- "plain '_Complex' requires a type specifier; assuming '_Complex double'">;
-def ext_integer_complex : Extension<
- "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
def ext_thread_before : Extension<"'__thread' before '%0'">;
def ext_keyword_as_ident : ExtWarn<
"keyword '%0' will be made available as an identifier "
@@ -70,12 +62,6 @@
InGroup<DiagGroup<"nullability-extension">>;
def error_empty_enum : Error<"use of empty enum">;
-def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
-def err_invalid_short_spec : Error<"'short %0' is invalid">;
-def err_invalid_long_spec : Error<"'long %0' is invalid">;
-def err_invalid_longlong_spec : Error<"'long long %0' is invalid">;
-def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">;
-def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">;
def ext_ident_list_in_param : Extension<
"type-less parameter names in function declaration">;
@@ -286,11 +272,6 @@
def warn_cxx98_compat_trailing_return_type : Warning<
"trailing return types are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-def ext_auto_type_specifier : ExtWarn<
- "'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
-def warn_auto_storage_class : Warning<
- "'auto' storage class specifier is redundant and incompatible with C++11">,
- InGroup<CXX11Compat>, DefaultIgnore;
def ext_auto_storage_class : ExtWarn<
"'auto' storage class specifier is not permitted in C++11, and will not "
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
@@ -299,6 +280,9 @@
def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
"'decltype(auto)' type specifier is incompatible with C++ standards before "
"C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
+def ext_auto_type : Extension<
+ "'__auto_type' is a GNU extension">,
+ InGroup<GNUAutoType>;
def ext_for_range : ExtWarn<
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_for_range : Warning<
@@ -327,9 +311,6 @@
"'static' may not be used with an unspecified variable length array size">;
def err_unspecified_size_with_static : Error<
"'static' may not be used without an array size">;
-def warn_deprecated_register : Warning<
- "'register' storage class specifier is deprecated">,
- InGroup<DeprecatedRegister>;
def err_expected_parentheses_around_typename : Error<
"expected parentheses around type name in %0 expression">;
@@ -348,39 +329,10 @@
def err_typename_identifiers_only : Error<
"typename is allowed for identifiers only">;
-def err_invalid_decl_spec_combination : Error<
- "cannot combine with previous '%0' declaration specifier">;
-def err_invalid_vector_decl_spec_combination : Error<
- "cannot combine with previous '%0' declaration specifier. "
- "'__vector' must be first">;
-def err_invalid_pixel_decl_spec_combination : Error<
- "'__pixel' must be preceded by '__vector'. "
- "'%0' declaration specifier not allowed here">;
-def err_invalid_vector_bool_decl_spec : Error<
- "cannot use '%0' with '__vector bool'">;
-def err_invalid_vector_long_decl_spec : Error<
- "cannot use 'long' with '__vector'">;
-def err_invalid_vector_float_decl_spec : Error<
- "cannot use 'float' with '__vector'">;
-def err_invalid_vector_double_decl_spec : Error <
- "use of 'double' with '__vector' requires VSX support to be enabled "
- "(available on POWER7 or later)">;
-def err_invalid_vector_long_long_decl_spec : Error <
- "use of 'long long' with '__vector bool' requires VSX support (available on "
- "POWER7 or later) or extended Altivec support (available on POWER8 or later) "
- "to be enabled">;
-def err_invalid_vector_long_double_decl_spec : Error<
- "cannot use 'long double' with '__vector'">;
-def warn_vector_long_decl_spec_combination : Warning<
- "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>;
def err_friend_invalid_in_context : Error<
"'friend' used outside of class">;
-def err_use_of_tag_name_without_tag : Error<
- "must use '%1' tag to refer to type %0%select{| in this scope}2">;
-def err_templated_using_directive : Error<
- "cannot template a using directive">;
-def err_templated_using_declaration : Error<
- "cannot template a using declaration">;
+def err_templated_using_directive_declaration : Error<
+ "cannot template a using %select{directive|declaration}0">;
def err_unexpected_colon_in_nested_name_spec : Error<
"unexpected ':' in nested name specifier; did you mean '::'?">;
def err_unexpected_token_in_nested_name_spec : Error<
@@ -695,12 +647,9 @@
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<
"out-of-line constructor for %0 cannot have template arguments">;
-def err_out_of_line_template_id_names_constructor : Error<
+def err_out_of_line_template_id_type_names_constructor : Error<
"qualified reference to %0 is a constructor name rather than a "
- "template name wherever a constructor can be declared">;
-def err_out_of_line_type_names_constructor : Error<
- "qualified reference to %0 is a constructor name rather than a "
- "type wherever a constructor can be declared">;
+ "%select{template name|type}1 wherever a constructor can be declared">;
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
@@ -740,15 +689,11 @@
"%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0"
" which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
-def ext_deleted_function : ExtWarn<
- "deleted function definitions are a C++11 extension">, InGroup<CXX11>;
-def warn_cxx98_compat_deleted_function : Warning<
- "deleted function definitions are incompatible with C++98">,
- InGroup<CXX98Compat>, DefaultIgnore;
-def ext_defaulted_function : ExtWarn<
- "defaulted function definitions are a C++11 extension">, InGroup<CXX11>;
-def warn_cxx98_compat_defaulted_function : Warning<
- "defaulted function definitions are incompatible with C++98">,
+def ext_defaulted_deleted_function : ExtWarn<
+ "%select{defaulted|deleted}0 function definitions are a C++11 extension">,
+ InGroup<CXX11>;
+def warn_cxx98_compat_defaulted_deleted_function : Warning<
+ "%select{defaulted|deleted}0 function definitions are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
// C++11 in-class member initialization
@@ -821,10 +766,6 @@
def err_lambda_missing_parens : Error<
"lambda requires '()' before %select{'mutable'|return type|"
"attribute specifier}0">;
-def warn_init_capture_direct_list_init : Warning<
- "direct list initialization of a lambda init-capture will change meaning in "
- "a future version of Clang; insert an '=' to avoid a change in behavior">,
- InGroup<FutureCompat>;
// Availability attribute
def err_expected_version : Error<
@@ -961,10 +902,6 @@
def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
-// OpenCL Section 6.8.g
-def err_opencl_unknown_type_specifier : Error<
- "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">;
-
// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
def warn_pragma_expected_colon : Warning<
"missing ':' after %0 - ignoring">, InGroup<IgnoredPragmas>;
@@ -973,12 +910,18 @@
def warn_pragma_unknown_extension : Warning<
"unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>;
+// OpenCL error
+def err_opencl_taking_function_address_parser : Error<
+ "taking address of function is not allowed">;
+
// OpenMP support.
def warn_pragma_omp_ignored : Warning<
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
def warn_omp_extra_tokens_at_eol : Warning<
"extra tokens at the end of '#pragma omp %0' are ignored">,
InGroup<ExtraTokens>;
+def warn_pragma_expected_colon_r_paren : Warning<
+ "missing ':' or ')' after %0 - ignoring">, InGroup<IgnoredPragmas>;
def err_omp_unknown_directive : Error<
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error<
@@ -988,9 +931,15 @@
def err_omp_unexpected_clause : Error<
"unexpected OpenMP clause '%0' in directive '#pragma omp %1'">;
def err_omp_immediate_directive : Error<
- "'#pragma omp %0' cannot be an immediate substatement">;
+ "'#pragma omp %0' %select{|with '%2' clause }1cannot be an immediate substatement">;
def err_omp_expected_identifier_for_critical : Error<
"expected identifier specifying the name of the 'omp critical' directive">;
+def err_omp_unknown_map_type : Error<
+ "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">;
+def err_omp_unknown_map_type_modifier : Error<
+ "incorrect map type modifier, expected 'always'">;
+def err_omp_map_type_missing : Error<
+ "missing map type">;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index fa0b5fe..dd9fb57 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1,4 +1,3 @@
-
//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===//
//
// The LLVM Compiler Infrastructure
@@ -67,6 +66,9 @@
"when argument is of %select{integer|floating point|complex}2 type">,
InGroup<AbsoluteValue>;
def note_replace_abs_function : Note<"use function '%0' instead">;
+def warn_pointer_abs : Warning<
+ "taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">,
+ InGroup<AbsoluteValue>;
def warn_infinite_recursive_function : Warning<
"all paths through this function will call itself">,
@@ -188,6 +190,63 @@
"flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
// Declarations.
+def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">,
+ InGroup<DuplicateDeclSpecifier>;
+def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">,
+ InGroup<DuplicateDeclSpecifier>;
+def ext_plain_complex : ExtWarn<
+ "plain '_Complex' requires a type specifier; assuming '_Complex double'">;
+def ext_integer_complex : Extension<
+ "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
+
+def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
+def err_invalid_width_spec : Error<
+ "'%select{|short|long|long long}0 %1' is invalid">;
+def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">;
+def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">;
+
+def ext_auto_type_specifier : ExtWarn<
+ "'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
+def warn_auto_storage_class : Warning<
+ "'auto' storage class specifier is redundant and incompatible with C++11">,
+ InGroup<CXX11Compat>, DefaultIgnore;
+
+def warn_deprecated_register : Warning<
+ "'register' storage class specifier is deprecated "
+ "and incompatible with C++1z">, InGroup<DeprecatedRegister>;
+def ext_register_storage_class : ExtWarn<
+ "ISO C++1z does not allow 'register' storage class specifier">,
+ DefaultError, InGroup<Register>;
+
+def err_invalid_decl_spec_combination : Error<
+ "cannot combine with previous '%0' declaration specifier">;
+def err_invalid_vector_decl_spec_combination : Error<
+ "cannot combine with previous '%0' declaration specifier. "
+ "'__vector' must be first">;
+def err_invalid_pixel_decl_spec_combination : Error<
+ "'__pixel' must be preceded by '__vector'. "
+ "'%0' declaration specifier not allowed here">;
+def err_invalid_vector_bool_decl_spec : Error<
+ "cannot use '%0' with '__vector bool'">;
+def err_invalid_vector_long_decl_spec : Error<
+ "cannot use 'long' with '__vector'">;
+def err_invalid_vector_float_decl_spec : Error<
+ "cannot use 'float' with '__vector'">;
+def err_invalid_vector_double_decl_spec : Error <
+ "use of 'double' with '__vector' requires VSX support to be enabled "
+ "(available on POWER7 or later)">;
+def err_invalid_vector_long_long_decl_spec : Error <
+ "use of 'long long' with '__vector bool' requires VSX support (available on "
+ "POWER7 or later) or extended Altivec support (available on POWER8 or later) "
+ "to be enabled">;
+def err_invalid_vector_long_double_decl_spec : Error<
+ "cannot use 'long double' with '__vector'">;
+def warn_vector_long_decl_spec_combination : Warning<
+ "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>;
+
+def err_use_of_tag_name_without_tag : Error<
+ "must use '%1' tag to refer to type %0%select{| in this scope}2">;
+
def err_redeclaration_different_type : Error<
"redeclaration of %0 with a different type%diff{: $ vs $|}1,2">;
def err_bad_variable_name : Error<
@@ -195,6 +254,17 @@
def err_bad_parameter_name : Error<
"%0 cannot be the name of a parameter">;
def err_parameter_name_omitted : Error<"parameter name omitted">;
+def err_anyx86_interrupt_attribute : Error<
+ "%select{x86|x86-64}0 'interrupt' attribute only applies to functions that "
+ "have %select{a 'void' return type|"
+ "only a pointer parameter optionally followed by an integer parameter|"
+ "a pointer as the first parameter|a %2 type as the second parameter}1">;
+def err_anyx86_interrupt_called : Error<
+ "interrupt service routine cannot be called directly">;
+def warn_mips_interrupt_attribute : Warning<
+ "MIPS 'interrupt' attribute only applies to functions that have "
+ "%select{no parameters|a 'void' return type}0">,
+ InGroup<IgnoredAttributes>;
def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,
@@ -431,6 +501,10 @@
def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">;
def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
+def err_function_needs_feature
+ : Error<"always_inline function %1 requires target feature '%2', but would "
+ "be inlined into function %0 that is compiled without support for "
+ "'%2'">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">,
InGroup<ImplicitFunctionDeclare>, DefaultError;
def warn_dyn_class_memaccess : Warning<
@@ -864,6 +938,9 @@
def warn_property_getter_owning_mismatch : Warning<
"property declared as returning non-retained objects"
"; getter returning retained objects">;
+def warn_property_redecl_getter_mismatch : Warning<
+ "getter name mismatch between property redeclaration (%1) and its original "
+ "declaration (%0)">, InGroup<PropertyAttr>;
def error_property_setter_ambiguous_use : Error<
"synthesized properties %0 and %1 both claim setter %2 -"
" use of this setter will cause unexpected behavior">;
@@ -899,6 +976,8 @@
"property synthesized here">;
def error_synthesize_category_decl : Error<
"@synthesize not allowed in a category's implementation">;
+def error_synthesize_on_class_property : Error<
+ "@synthesize not allowed on a class property %0">;
def error_reference_property : Error<
"property of reference type is not supported">;
def error_missing_property_interface : Error<
@@ -1103,6 +1182,8 @@
"%0 cannot be defined in a parameter type">;
def err_type_defined_in_alias_template : Error<
"%0 cannot be defined in a type alias template">;
+def err_type_defined_in_condition : Error<
+ "%0 cannot be defined in a condition">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
@@ -1501,8 +1582,7 @@
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}5 vs "
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
- "volatile and restrict|const, volatile, and restrict}6)"
- "|: cannot take the address of a potentially disabled function}4">;
+ "volatile and restrict|const, volatile, and restrict}6)}4">;
def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot "
"bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">;
@@ -1666,18 +1746,22 @@
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
- "variable %0 declared with 'auto' type cannot appear in its own initializer">;
+ "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 "
+ "type cannot appear in its own initializer">;
def err_illegal_decl_array_of_auto : Error<
"'%0' declared as array of %1">;
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype"
- "|in non-static struct member"
- "|in non-static union member|in non-static class member|in interface member"
+ "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed "
+ "%select{in function prototype"
+ "|in non-static struct member|in struct member"
+ "|in non-static union member|in union member"
+ "|in non-static class member|in interface member"
"|in exception declaration|in template parameter|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
- "|in conversion function type|here|in lambda parameter}1">;
+ "|in conversion function type|here|in lambda parameter"
+ "|in type allocated by 'new'|in K&R-style function parameter}1">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
@@ -1691,12 +1775,8 @@
def err_auto_var_init_multiple_expressions : Error<
"initializer for variable %0 with type %1 contains multiple expressions">;
def err_auto_var_init_paren_braces : Error<
- "cannot deduce type for variable %0 with type %1 from "
- "parenthesized initializer list">;
-def warn_auto_var_direct_list_init : Warning<
- "direct list initialization of a variable with a deduced type will change "
- "meaning in a future version of Clang; insert an '=' to avoid a change in "
- "behavior">, InGroup<FutureCompat>;
+ "cannot deduce type for variable %1 with type %2 from "
+ "%select{parenthesized|nested}0 initializer list">;
def err_auto_new_ctor_multiple_expressions : Error<
"new expression for type %0 contains multiple constructor arguments">;
def err_auto_missing_trailing_return : Error<
@@ -1715,8 +1795,8 @@
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
def err_auto_different_deductions : Error<
- "'%select{auto|decltype(auto)}0' deduced as %1 in declaration of %2 and "
- "deduced as %3 in declaration of %4">;
+ "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
+ "of %2 and deduced as %3 in declaration of %4">;
def err_implied_std_initializer_list_not_found : Error<
"cannot deduce type of initializer list because std::initializer_list was "
"not found; include <initializer_list>">;
@@ -1726,6 +1806,10 @@
"array backing the initializer list will be destroyed at the end of "
"%select{the full-expression|the constructor}0">,
InGroup<DiagGroup<"dangling-initializer-list">>;
+def err_auto_init_list_from_c : Error<
+ "cannot use __auto_type with initializer list in C">;
+def err_auto_bitfield : Error<
+ "cannot pass bit-field as __auto_type initializer in C">;
// C++1y decltype(auto) type
def err_decltype_auto_cannot_be_combined : Error<
@@ -1992,6 +2076,8 @@
def err_concept_decl_invalid_specifiers : Error<
"%select{variable|function}0 concept cannot be declared "
"'%select{thread_local|inline|friend|constexpr}1'">;
+def err_function_concept_with_params : Error<
+ "function concept cannot have any parameters">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
@@ -2054,8 +2140,7 @@
"%0 attribute requires %select{int or bool|an integer "
"constant|a string|an identifier}1">;
def err_attribute_argument_outof_range : Error<
- "init_priority attribute requires integer constant between "
- "101 and 65535 inclusive">;
+ "%0 attribute requires integer constant between %1 and %2 inclusive">;
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
@@ -2063,10 +2148,12 @@
"invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
def err_attribute_argument_out_of_bounds : Error<
"%0 attribute parameter %1 is out of bounds">;
+def err_attribute_only_once_per_parameter : Error<
+ "%0 attribute can only be applied once per parameter">;
def err_attribute_uuid_malformed_guid : Error<
"uuid attribute contains a malformed GUID">;
def warn_attribute_pointers_only : Warning<
- "%0 attribute only applies to pointer arguments">,
+ "%0 attribute only applies to%select{| constant}1 pointer arguments">,
InGroup<IgnoredAttributes>;
def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>;
def warn_attribute_return_pointers_only : Warning<
@@ -2323,6 +2410,8 @@
"propagating dll attribute to %select{already instantiated|explicitly specialized}0 "
"base class template without dll attribute is not supported">,
InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore;
+def err_attribute_dll_ambiguous_default_ctor : Error<
+ "'__declspec(dllexport)' cannot be applied to more than one default constructor in %0">;
def err_attribute_weakref_not_static : Error<
"weakref declaration must have internal linkage">;
def err_attribute_weakref_not_global_context : Error<
@@ -2356,7 +2445,8 @@
"Objective-C instance methods|init methods of interface or class extension declarations|"
"variables, functions and classes|Objective-C protocols|"
"functions and global variables|structs, unions, and typedefs|structs and typedefs|"
- "interface or protocol declarations|kernel functions|non-K&R-style functions}1">,
+ "interface or protocol declarations|kernel functions|non-K&R-style functions|"
+ "variables, fields and typedefs}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
@@ -2651,15 +2741,14 @@
InGroup<ImplicitConversionFloatingPointToBool>;
def ext_ms_impcast_fn_obj : ExtWarn<
"implicit conversion between pointer-to-function and pointer-to-object is a "
- "Microsoft extension">,
- InGroup<MicrosoftCast>, DefaultError, SFINAEFailure;
+ "Microsoft extension">, InGroup<MicrosoftCast>;
def warn_impcast_pointer_to_bool : Warning<
"address of%select{| function| array}0 '%1' will always evaluate to "
"'true'">,
InGroup<PointerBoolConversion>;
def warn_cast_nonnull_to_bool : Warning<
- "nonnull parameter '%0' will evaluate to "
+ "nonnull %select{function call|parameter}0 '%1' will evaluate to "
"'true' on first encounter">,
InGroup<PointerBoolConversion>;
def warn_this_bool_conversion : Warning<
@@ -2674,9 +2763,10 @@
"comparison of %select{address of|function|array}0 '%1' %select{not |}2"
"equal to a null pointer is always %select{true|false}2">,
InGroup<TautologicalPointerCompare>;
-def warn_nonnull_parameter_compare : Warning<
- "comparison of nonnull parameter '%0' %select{not |}1"
- "equal to a null pointer is %select{true|false}1 on first encounter">,
+def warn_nonnull_expr_compare : Warning<
+ "comparison of nonnull %select{function call|parameter}0 '%1' "
+ "%select{not |}2equal to a null pointer is '%select{true|false}2' on first "
+ "encounter">,
InGroup<TautologicalPointerCompare>;
def warn_this_null_compare : Warning<
"'this' pointer cannot be null in well-defined C++ code; comparison may be "
@@ -2716,9 +2806,10 @@
"cast to %1 from smaller integer type %0">,
InGroup<IntToVoidPointerCast>;
-def warn_attribute_ignored_for_field_of_type : Warning<
- "%0 attribute ignored for field of type %1">,
- InGroup<IgnoredAttributes>;
+def warn_attribute_packed_for_bitfield : Warning<
+ "'packed' attribute was ignored on bit-fields with single-byte alignment "
+ "in older versions of GCC and Clang">,
+ InGroup<DiagGroup<"attribute-packed-for-bitfield">>;
def warn_transparent_union_attribute_field_size_align : Warning<
"%select{alignment|size}0 of field %1 (%2 bits) does not match the "
"%select{alignment|size}0 of the first field in transparent union; "
@@ -2762,10 +2853,12 @@
"mode attribute only supported for integer and floating-point types">;
def err_mode_wrong_type : Error<
"type of machine mode does not match type of base type">;
+def warn_vector_mode_deprecated : Warning<
+ "specifying vector types with the 'mode' attribute is deprecated; "
+ "use the 'vector_size' attribute instead">,
+ InGroup<DeprecatedAttributes>;
def err_complex_mode_vector_type : Error<
"type of machine mode does not support base vector types">;
-def err_attr_wrong_decl : Error<
- "%0 attribute invalid on this declaration, requires typedef or value">;
def warn_attribute_nonnull_no_pointers : Warning<
"'nonnull' attribute applied to function with no pointer arguments">,
InGroup<IgnoredAttributes>;
@@ -3011,8 +3104,7 @@
"%select{none|const|restrict|const and restrict|volatile|const and volatile"
"|volatile and restrict|const, volatile, and restrict}3 but found "
"%select{none|const|restrict|const and restrict|volatile|const and volatile"
- "|volatile and restrict|const, volatile, and restrict}4)"
- "| made ineligible by enable_if}2">;
+ "|volatile and restrict|const, volatile, and restrict}4)}2">;
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
def note_ovl_candidate_illegal_constructor : Note<
@@ -3041,11 +3133,23 @@
"candidate template ignored: substitution failure%0%1">;
def note_ovl_candidate_disabled_by_enable_if : Note<
"candidate template ignored: disabled by %0%1">;
+def note_ovl_candidate_has_pass_object_size_params: Note<
+ "candidate address cannot be taken because parameter %0 has "
+ "pass_object_size attribute">;
def note_ovl_candidate_disabled_by_enable_if_attr : Note<
"candidate disabled: %0">;
+def err_addrof_function_disabled_by_enable_if_attr : Error<
+ "cannot take address of function %0 becuase it has one or more "
+ "non-tautological enable_if conditions">;
+def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
+ "candidate function made ineligible by enable_if">;
def note_ovl_candidate_failed_overload_resolution : Note<
"candidate template ignored: couldn't resolve reference to overloaded "
"function %0">;
+def note_ovl_candidate_deduced_mismatch : Note<
+ "candidate template ignored: deduced type "
+ "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument"
+ "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">;
def note_ovl_candidate_non_deduced_mismatch : Note<
"candidate template ignored: could not match %diff{$ against $|types}0,1">;
// This note is needed because the above note would sometimes print two
@@ -3053,7 +3157,7 @@
// can handle that case properly.
def note_ovl_candidate_non_deduced_mismatch_qualified : Note<
"candidate template ignored: could not match %q0 against %q1">;
-
+
// Note that we don't treat templates differently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
"%select{function|function|constructor|function|function|constructor|"
@@ -4110,6 +4214,12 @@
InGroup<DiagGroup<"undefined-inline">>;
def note_used_here : Note<"used here">;
+def err_internal_linkage_redeclaration : Error<
+ "'internal_linkage' attribute does not appear on the first declaration of %0">;
+def warn_internal_linkage_local_storage : Warning<
+ "'internal_linkage' attribute on a non-static local variable is ignored">,
+ InGroup<IgnoredAttributes>;
+
def ext_internal_in_extern_inline : ExtWarn<
"static %select{function|variable}0 %1 is used in an inline function with "
"external linkage">, InGroup<StaticInInline>;
@@ -4187,6 +4297,11 @@
def err_tag_definition_of_typedef : Error<
"definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
+def err_different_pass_object_size_params : Error<
+ "conflicting pass_object_size attributes on parameters">;
+def err_late_asm_label_name : Error<
+ "cannot apply asm label to %select{variable|function}0 after its first use">;
+def err_different_asm_label : Error<"conflicting asm label">;
def err_nested_redefinition : Error<"nested redefinition of %0">;
def err_use_with_wrong_tag : Error<
"use of %0 with tag type that does not match previous declaration">;
@@ -4571,9 +4686,6 @@
def err_synthesizing_arc_weak_property_no_runtime : Error<
"cannot synthesize weak property because the current deployment target "
"does not support weak references">;
-def warn_objc_weak_compat : Warning<
- "the meaning of __weak has changed in manual reference-counting">,
- InGroup<DiagGroup<"objc-weak-compat">>, DefaultIgnore;
def err_arc_unsupported_weak_class : Error<
"class is incompatible with __weak references">;
def err_arc_weak_unavailable_assign : Error<
@@ -4835,8 +4947,8 @@
"function type">;
def err_openmp_default_simd_align_expr : Error<
"invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">;
-def err_sizeof_alignof_bitfield : Error<
- "invalid application of '%select{sizeof|alignof}0' to bit-field">;
+def err_sizeof_alignof_typeof_bitfield : Error<
+ "invalid application of '%select{sizeof|alignof|typeof}0' to bit-field">;
def err_alignof_member_of_incomplete_type : Error<
"invalid application of 'alignof' to a field of a class still being defined">;
def err_vecstep_non_scalar_vector_type : Error<
@@ -4864,9 +4976,8 @@
"comparing floating point with == or != is unsafe">,
InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
-def warn_division_by_zero : Warning<"division by zero is undefined">,
- InGroup<DivZero>;
-def warn_remainder_by_zero : Warning<"remainder by zero is undefined">,
+def warn_remainder_division_by_zero : Warning<
+ "%select{remainder|division}0 by zero is undefined">,
InGroup<DivZero>;
def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">,
InGroup<DiagGroup<"shift-negative-value">>;
@@ -4904,8 +5015,8 @@
def note_logical_instead_of_bitwise_remove_constant : Note<
"remove constant to silence this warning">;
-def warn_bitwise_and_in_bitwise_or : Warning<
- "'&' within '|'">, InGroup<BitwiseOpParentheses>;
+def warn_bitwise_op_in_bitwise_op : Warning<
+ "'%0' within '%1'">, InGroup<BitwiseOpParentheses>;
def warn_logical_and_in_logical_or : Warning<
"'&&' within '||'">, InGroup<LogicalOpParentheses>;
@@ -5155,6 +5266,9 @@
"must explicitly qualify name of member function when taking its address">;
def err_invalid_form_pointer_member_function : Error<
"cannot create a non-constant pointer to member function">;
+def err_address_of_function_with_pass_object_size_params: Error<
+ "cannot take address of function %0 because parameter %1 has "
+ "pass_object_size attribute">;
def err_parens_pointer_member_function : Error<
"cannot parenthesize the name of a method when forming a member pointer">;
def err_typecheck_invalid_lvalue_addrof_addrof_function : Error<
@@ -5536,8 +5650,7 @@
"cast between pointer-to-function and pointer-to-object is an extension">;
def ext_ms_cast_fn_obj : ExtWarn<
"static_cast between pointer-to-function and pointer-to-object is a "
- "Microsoft extension">,
- InGroup<MicrosoftCast>, DefaultError, SFINAEFailure;
+ "Microsoft extension">, InGroup<MicrosoftCast>;
def warn_cxx98_compat_cast_fn_obj : Warning<
"cast between pointer-to-function and pointer-to-object is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
@@ -5678,8 +5791,11 @@
"member %0 declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
- "incrementing expression of type bool is deprecated">,
- InGroup<DeprecatedIncrementBool>;
+ "incrementing expression of type bool is deprecated and "
+ "incompatible with C++1z">, InGroup<DeprecatedIncrementBool>;
+def ext_increment_bool : ExtWarn<
+ "ISO C++1z does not allow incrementing expression of type bool">,
+ DefaultError, InGroup<IncrementBool>;
def err_increment_decrement_enum : Error<
"cannot %select{decrement|increment}0 expression of enum type %1">;
def err_catch_incomplete_ptr : Error<
@@ -5719,11 +5835,14 @@
"%0 has virtual functions but non-virtual destructor">,
InGroup<NonVirtualDtor>, DefaultIgnore;
def warn_delete_non_virtual_dtor : Warning<
- "delete called on %0 that has virtual functions but non-virtual destructor">,
+ "%select{delete|destructor}0 called on non-final %1 that has "
+ "virtual functions but non-virtual destructor">,
InGroup<DeleteNonVirtualDtor>, DefaultIgnore;
+def note_delete_non_virtual : Note<
+ "qualify call to silence this warning">;
def warn_delete_abstract_non_virtual_dtor : Warning<
- "delete called on %0 that is abstract but has non-virtual destructor">,
- InGroup<DeleteNonVirtualDtor>;
+ "%select{delete|destructor}0 called on %1 that is abstract but has "
+ "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
@@ -5737,8 +5856,7 @@
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}2 vs "
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
- "volatile and restrict|const, volatile, and restrict}3)"
- "|: mismatch in enable_if attributes}1">;
+ "volatile and restrict|const, volatile, and restrict}3)}1">;
def warn_using_directive_in_header : Warning<
"using namespace directive in global context in header">,
InGroup<HeaderHygiene>, DefaultIgnore;
@@ -5838,8 +5956,8 @@
def err_init_capture_multiple_expressions : Error<
"initializer for lambda capture %0 contains multiple expressions">;
def err_init_capture_paren_braces : Error<
- "cannot deduce type for lambda capture %0 from "
- "parenthesized initializer list">;
+ "cannot deduce type for lambda capture %1 from "
+ "%select{parenthesized|nested}0 initializer list">;
def err_init_capture_deduction_failure : Error<
"cannot deduce type for lambda capture %0 from initializer of type %2">;
def err_init_capture_deduction_failure_from_init_list : Error<
@@ -5886,8 +6004,6 @@
def err_invalid_use_of_function_type : Error<
"a function type is not allowed here">;
def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
-def err_type_defined_in_condition : Error<
- "types may not be defined in conditions">;
def err_typecheck_bool_condition : Error<
"value of type %0 is not contextually convertible to 'bool'">;
def err_typecheck_ambiguous_condition : Error<
@@ -5975,8 +6091,7 @@
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}5 vs "
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
- "volatile and restrict|const, volatile, and restrict}6)"
- "|: cannot take the address of a potentially disabled function}4">;
+ "volatile and restrict|const, volatile, and restrict}6)}4">;
def err_typecheck_missing_return_type_incompatible : Error<
"%diff{return type $ must match previous return type $|"
"return type must match previous return type}0,1 when %select{block "
@@ -6499,6 +6614,10 @@
"asm constraint has an unexpected number of alternatives: %0 vs %1">;
def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">;
def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
+ def err_asm_invalid_global_var_reg : Error<"register '%0' unsuitable for "
+ "global register variables on this target">;
+ def err_asm_register_size_mismatch : Error<"size of register '%0' does not "
+ "match variable size">;
def err_asm_bad_register_type : Error<"bad type for named register variable">;
def err_asm_invalid_input_size : Error<
"invalid input size for constraint '%0'">;
@@ -6632,10 +6751,8 @@
def err_anonymous_struct_not_member : Error<
"anonymous %select{structs|structs and classes}0 must be "
"%select{struct or union|class}0 members">;
-def err_anonymous_union_member_redecl : Error<
- "member of anonymous union redeclares %0">;
-def err_anonymous_struct_member_redecl : Error<
- "member of anonymous struct redeclares %0">;
+def err_anonymous_record_member_redecl : Error<
+ "member of anonymous %select{struct|union}0 redeclares %1">;
def err_anonymous_record_with_type : Error<
"types cannot be declared in an anonymous %select{struct|union}0">;
def ext_anonymous_record_with_type : Extension<
@@ -6988,17 +7105,12 @@
InGroup<NonNull>;
// CHECK: returning address/reference of stack memory
-def warn_ret_stack_addr : Warning<
- "address of stack memory associated with local variable %0 returned">,
+def warn_ret_stack_addr_ref : Warning<
+ "%select{address of|reference to}0 stack memory associated with local "
+ "variable %1 returned">,
InGroup<ReturnStackAddress>;
-def warn_ret_stack_ref : Warning<
- "reference to stack memory associated with local variable %0 returned">,
- InGroup<ReturnStackAddress>;
-def warn_ret_local_temp_addr : Warning<
- "returning address of local temporary object">,
- InGroup<ReturnStackAddress>;
-def warn_ret_local_temp_ref : Warning<
- "returning reference to local temporary object">,
+def warn_ret_local_temp_addr_ref : Warning<
+ "returning %select{address of|reference to}0 local temporary object">,
InGroup<ReturnStackAddress>;
def warn_ret_addr_label : Warning<
"returning address of label, which is local">,
@@ -7572,6 +7684,10 @@
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_global_invalid_addr_space : Error<
"program scope variable must reside in %0 address space">;
+def err_missing_actual_pipe_type : Error<
+ "missing actual type specifier for pipe">;
+def err_reference_pipe_type : Error <
+ "pipes packet types cannot be of reference type">;
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
def err_opencl_kernel_attr :
Error<"attribute %0 can only be applied to a kernel function">;
@@ -7584,6 +7700,11 @@
" in the declaration statement in the program scope">;
def err_opencl_implicit_vector_conversion : Error<
"implicit conversions between vector types (%0 and %1) are not permitted">;
+
+// OpenCL Section 6.8.g
+def err_opencl_unknown_type_specifier : Error<
+ "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">;
+
} // end of sema category
let CategoryName = "OpenMP Issue" in {
@@ -7650,7 +7771,7 @@
def note_omp_collapse_ordered_expr : Note<
"as specified in %select{'collapse'|'ordered'|'collapse' and 'ordered'}0 clause%select{||s}0">;
def err_omp_negative_expression_in_clause : Error<
- "argument to '%0' clause must be a positive integer value">;
+ "argument to '%0' clause must be a %select{non-negative|strictly positive}1 integer value">;
def err_omp_not_integral : Error<
"expression must have integral or unscoped enumeration "
"type, not %0">;
@@ -7739,7 +7860,8 @@
"region cannot be%select{| closely}0 nested inside '%1' region"
"%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|"
"; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|"
- "; perhaps you forget to enclose 'omp %3' directive into a target region?}2">;
+ "; perhaps you forget to enclose 'omp %3' directive into a target region?|"
+ "; perhaps you forget to enclose 'omp %3' directive into a teams region?}2">;
def err_omp_prohibited_region_simd : Error<
"OpenMP constructs may not be nested inside a simd region">;
def err_omp_prohibited_region_atomic : Error<
@@ -7840,10 +7962,66 @@
"previous clause with directive name modifier specified here">;
def err_omp_ordered_directive_with_param : Error<
"'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">;
+def err_omp_ordered_directive_without_param : Error<
+ "'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">;
def note_omp_ordered_param : Note<
"'ordered' clause with specified parameter">;
def err_omp_expected_base_var_name : Error<
"expected variable name as a base of the array %select{subscript|section}0">;
+def err_omp_map_shared_storage : Error<
+ "variable already marked as mapped in current construct">;
+def err_omp_not_mappable_type : Error<
+ "type %0 is not mappable to target">;
+def note_omp_polymorphic_in_target : Note<
+ "mappable type cannot be polymorphic">;
+def note_omp_static_member_in_target : Note<
+ "mappable type cannot contain static members">;
+def err_omp_threadprivate_in_map : Error<
+ "threadprivate variables are not allowed in map clause">;
+def err_omp_wrong_ordered_loop_count : Error<
+ "the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause">;
+def note_collapse_loop_count : Note<
+ "parameter of the 'collapse' clause">;
+def err_omp_grainsize_num_tasks_mutually_exclusive : Error<
+ "'%0' and '%1' clause are mutually exclusive and may not appear on the same directive">;
+def note_omp_previous_grainsize_num_tasks : Note<
+ "'%0' clause is specified here">;
+def err_omp_hint_clause_no_name : Error<
+ "the name of the construct must be specified in presence of 'hint' clause">;
+def err_omp_critical_with_hint : Error<
+ "constructs with the same name must have a 'hint' clause with the same value">;
+def note_omp_critical_hint_here : Note<
+ "%select{|previous }0'hint' clause with value '%1'">;
+def note_omp_critical_no_hint : Note<
+ "%select{|previous }0directive with no 'hint' clause specified">;
+def err_omp_firstprivate_distribute_private_teams : Error<
+ "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">;
+def err_omp_firstprivate_and_lastprivate_in_distribute : Error<
+ "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">;
+def err_omp_firstprivate_distribute_in_teams_reduction : Error<
+ "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">;
+def err_omp_depend_clause_thread_simd : Error<
+ "'depend' clauses cannot be mixed with '%0' clause">;
+def err_omp_depend_sink_wrong_expr : Error<
+ "expected expression form x[+-d], where x is the loop iteration variable and d is a constant non-negative integer">;
+def err_omp_depend_sink_expected_loop_iteration : Error<
+ "expected %0 loop iteration variable">;
+def err_omp_depend_sink_unexpected_expr : Error<
+ "unexpected expression: number of expressions is larger than the number of associated loops">;
+def err_omp_depend_sink_expected_plus_minus : Error<
+ "expected '+' or '-' operation">;
+def err_omp_depend_sink_source_not_allowed : Error<
+ "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">;
+def err_omp_linear_ordered : Error<
+ "'linear' clause cannot be specified along with 'ordered' clause with a parameter">;
+def err_omp_unexpected_schedule_modifier : Error<
+ "modifier '%0' cannot be used along with modifier '%1'">;
+def err_omp_schedule_nonmonotonic_static : Error<
+ "'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind">;
+def err_omp_schedule_nonmonotonic_ordered : Error<
+ "'schedule' clause with 'nonmonotonic' modifier cannot be specified if an 'ordered' clause is specified">;
+def err_omp_ordered_simd : Error<
+ "'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -7895,6 +8073,9 @@
"extern \"C\" language linkage specification begins here">;
def err_module_import_not_at_top_level_fatal : Error<
"import of module '%0' appears within %1">, DefaultFatal;
+def ext_module_import_not_at_top_level_noop : ExtWarn<
+ "redundant #include of module '%0' appears within %1">, DefaultError,
+ InGroup<DiagGroup<"modules-import-nested-redundant">>;
def note_module_import_not_at_top_level : Note<"%0 begins here">;
def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
@@ -7916,6 +8097,8 @@
"'%select{co_await|co_yield|co_return}0' here">;
def err_coroutine_objc_method : Error<
"Objective-C methods as coroutines are not yet supported">;
+def err_coroutine_unevaluated_context : Error<
+ "'%0' cannot be used in an unevaluated context">;
def err_coroutine_outside_function : Error<
"'%0' cannot be used outside a function">;
def err_coroutine_ctor_dtor : Error<
@@ -7931,14 +8114,14 @@
def err_implied_std_coroutine_traits_not_found : Error<
"you need to include <coroutine> before defining a coroutine">;
def err_malformed_std_coroutine_traits : Error<
- "std::coroutine_traits must be a class template">;
+ "'std::coroutine_traits' must be a class template">;
def err_implied_std_coroutine_traits_promise_type_not_found : Error<
- "this function cannot be a coroutine: %0 has no member named 'promise_type'">;
+ "this function cannot be a coroutine: %q0 has no member named 'promise_type'">;
def err_implied_std_coroutine_traits_promise_type_not_class : Error<
"this function cannot be a coroutine: %0 is not a class">;
def err_coroutine_traits_missing_specialization : Error<
"this function cannot be a coroutine: missing definition of "
- "specialization %0">;
+ "specialization %q0">;
}
let CategoryName = "Documentation Issue" in {
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index cf74d49..17758ec 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -126,9 +126,9 @@
///
/// For each virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
/// directories (foo/ and foo/bar/) here.
- SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
+ SmallVector<std::unique_ptr<DirectoryEntry>, 4> VirtualDirectoryEntries;
/// \brief The virtual files that we have allocated.
- SmallVector<FileEntry*, 4> VirtualFileEntries;
+ SmallVector<std::unique_ptr<FileEntry>, 4> VirtualFileEntries;
/// \brief A cache that maps paths to directory entries (either real or
/// virtual) we have looked up
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 72c260e..594c8c7 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -133,7 +133,6 @@
BENIGN_LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery")
BENIGN_LANGOPT(ImplicitModules, 1, 1, "build modules that are not specified via -fmodule-file")
COMPATIBLE_LANGOPT(ModulesLocalVisibility, 1, 0, "local submodule visibility")
-COMPATIBLE_LANGOPT(ModulesHideInternalLinkage, 1, 1, "hiding non-visible internal linkage declarations from redeclaration lookup")
COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
COMPATIBLE_LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
@@ -166,6 +165,8 @@
LANGOPT(CUDA , 1, 0, "CUDA")
LANGOPT(OpenMP , 1, 0, "OpenMP support")
LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls")
+LANGOPT(OpenMPIsDevice , 1, 0, "Generate code only for OpenMP target device")
+
LANGOPT(CUDAIsDevice , 1, 0, "Compiling for CUDA device")
LANGOPT(CUDAAllowHostCallsFromHostDevice, 1, 0, "Allow host device functions to call host functions")
LANGOPT(CUDADisableTargetCallChecks, 1, 0, "Disable checks for call targets (host, device, etc.)")
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 3c9d23e..736d4e0 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -108,7 +108,18 @@
/// \brief Options for parsing comments.
CommentOptions CommentOpts;
-
+
+ /// \brief A list of all -fno-builtin-* function names (e.g., memset).
+ std::vector<std::string> NoBuiltinFuncs;
+
+ /// \brief Triples of the OpenMP targets that the host code codegen should
+ /// take into account in order to generate accurate offloading descriptors.
+ std::vector<llvm::Triple> OMPTargetTriples;
+
+ /// \brief Name of the IR file that contains the result of the OpenMP target
+ /// host code generation.
+ std::string OMPHostIRFile;
+
LangOptions();
// Define accessors/mutators for language options of enumeration type.
@@ -134,6 +145,10 @@
/// \brief Reset all of the options that are not considered when building a
/// module.
void resetNonModularOptions();
+
+ /// \brief Is this a libc/libm function that is no longer recognized as a
+ /// builtin because a -fno-builtin-* option has been specified?
+ bool isNoBuiltinFunc(const char *Name) const;
};
/// \brief Floating point control options
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 087320b..c95968d 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_BASIC_MODULE_H
#define LLVM_CLANG_BASIC_MODULE_H
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
@@ -35,9 +36,6 @@
namespace clang {
-class DirectoryEntry;
-class FileEntry;
-class FileManager;
class LangOptions;
class TargetInfo;
class IdentifierInfo;
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index cf51b14..6975b6c 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -308,6 +308,23 @@
}
}
+ /// Is objc_unsafeClaimAutoreleasedReturnValue available?
+ bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
+ switch (getKind()) {
+ case MacOSX:
+ return getVersion() >= VersionTuple(10, 11);
+ case iOS:
+ return getVersion() >= VersionTuple(9);
+ case WatchOS:
+ return getVersion() >= VersionTuple(2);
+ case GNUstep:
+ return false;
+
+ default:
+ return false;
+ }
+ }
+
/// \brief Try to parse an Objective-C runtime specification from the given
/// string.
///
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index ee99b42..a32e310 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -69,6 +69,18 @@
#ifndef OPENMP_ORDERED_CLAUSE
# define OPENMP_ORDERED_CLAUSE(Name)
#endif
+#ifndef OPENMP_TASKLOOP_CLAUSE
+# define OPENMP_TASKLOOP_CLAUSE(Name)
+#endif
+#ifndef OPENMP_TASKLOOP_SIMD_CLAUSE
+# define OPENMP_TASKLOOP_SIMD_CLAUSE(Name)
+#endif
+#ifndef OPENMP_CRITICAL_CLAUSE
+# define OPENMP_CRITICAL_CLAUSE(Name)
+#endif
+#ifndef OPENMP_DISTRIBUTE_CLAUSE
+#define OPENMP_DISTRIBUTE_CLAUSE(Name)
+#endif
#ifndef OPENMP_DEFAULT_KIND
# define OPENMP_DEFAULT_KIND(Name)
#endif
@@ -78,12 +90,21 @@
#ifndef OPENMP_SCHEDULE_KIND
#define OPENMP_SCHEDULE_KIND(Name)
#endif
+#ifndef OPENMP_SCHEDULE_MODIFIER
+#define OPENMP_SCHEDULE_MODIFIER(Name)
+#endif
#ifndef OPENMP_DEPEND_KIND
#define OPENMP_DEPEND_KIND(Name)
#endif
#ifndef OPENMP_LINEAR_KIND
#define OPENMP_LINEAR_KIND(Name)
#endif
+#ifndef OPENMP_MAP_KIND
+#define OPENMP_MAP_KIND(Name)
+#endif
+#ifndef OPENMP_DIST_SCHEDULE_KIND
+#define OPENMP_DIST_SCHEDULE_KIND(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
@@ -112,6 +133,9 @@
OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point")
+OPENMP_DIRECTIVE(taskloop)
+OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
+OPENMP_DIRECTIVE(distribute)
// OpenMP clauses.
OPENMP_CLAUSE(if, OMPIfClause)
@@ -146,6 +170,15 @@
OPENMP_CLAUSE(device, OMPDeviceClause)
OPENMP_CLAUSE(threads, OMPThreadsClause)
OPENMP_CLAUSE(simd, OMPSIMDClause)
+OPENMP_CLAUSE(map, OMPMapClause)
+OPENMP_CLAUSE(num_teams, OMPNumTeamsClause)
+OPENMP_CLAUSE(thread_limit, OMPThreadLimitClause)
+OPENMP_CLAUSE(priority, OMPPriorityClause)
+OPENMP_CLAUSE(grainsize, OMPGrainsizeClause)
+OPENMP_CLAUSE(nogroup, OMPNogroupClause)
+OPENMP_CLAUSE(num_tasks, OMPNumTasksClause)
+OPENMP_CLAUSE(hint, OMPHintClause)
+OPENMP_CLAUSE(dist_schedule, OMPDistScheduleClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@@ -191,6 +224,7 @@
OPENMP_FOR_SIMD_CLAUSE(simdlen)
OPENMP_FOR_SIMD_CLAUSE(linear)
OPENMP_FOR_SIMD_CLAUSE(aligned)
+OPENMP_FOR_SIMD_CLAUSE(ordered)
// Clauses allowed for OpenMP directive 'omp sections'.
OPENMP_SECTIONS_CLAUSE(private)
@@ -224,10 +258,17 @@
OPENMP_SCHEDULE_KIND(auto)
OPENMP_SCHEDULE_KIND(runtime)
+// Modifiers for 'schedule' clause.
+OPENMP_SCHEDULE_MODIFIER(monotonic)
+OPENMP_SCHEDULE_MODIFIER(nonmonotonic)
+OPENMP_SCHEDULE_MODIFIER(simd)
+
// Static attributes for 'depend' clause.
OPENMP_DEPEND_KIND(in)
OPENMP_DEPEND_KIND(out)
OPENMP_DEPEND_KIND(inout)
+OPENMP_DEPEND_KIND(source)
+OPENMP_DEPEND_KIND(sink)
// Modifiers for 'linear' clause.
OPENMP_LINEAR_KIND(val)
@@ -267,6 +308,7 @@
OPENMP_PARALLEL_FOR_SIMD_CLAUSE(simdlen)
OPENMP_PARALLEL_FOR_SIMD_CLAUSE(linear)
OPENMP_PARALLEL_FOR_SIMD_CLAUSE(aligned)
+OPENMP_PARALLEL_FOR_SIMD_CLAUSE(ordered)
// Clauses allowed for OpenMP directive 'parallel sections'.
OPENMP_PARALLEL_SECTIONS_CLAUSE(if)
@@ -290,6 +332,7 @@
OPENMP_TASK_CLAUSE(untied)
OPENMP_TASK_CLAUSE(mergeable)
OPENMP_TASK_CLAUSE(depend)
+OPENMP_TASK_CLAUSE(priority)
// Clauses allowed for OpenMP directive 'atomic'.
OPENMP_ATOMIC_CLAUSE(read)
@@ -302,11 +345,13 @@
// TODO More clauses for 'target' directive.
OPENMP_TARGET_CLAUSE(if)
OPENMP_TARGET_CLAUSE(device)
+OPENMP_TARGET_CLAUSE(map)
// Clauses allowed for OpenMP directive 'target data'.
// TODO More clauses for 'target data' directive.
OPENMP_TARGET_DATA_CLAUSE(if)
OPENMP_TARGET_DATA_CLAUSE(device)
+OPENMP_TARGET_DATA_CLAUSE(map)
// Clauses allowed for OpenMP directive 'teams'.
// TODO More clauses for 'teams' directive.
@@ -315,20 +360,85 @@
OPENMP_TEAMS_CLAUSE(firstprivate)
OPENMP_TEAMS_CLAUSE(shared)
OPENMP_TEAMS_CLAUSE(reduction)
+OPENMP_TEAMS_CLAUSE(num_teams)
+OPENMP_TEAMS_CLAUSE(thread_limit)
// Clauses allowed for OpenMP directive 'ordered'.
// TODO More clauses for 'ordered' directive.
OPENMP_ORDERED_CLAUSE(threads)
OPENMP_ORDERED_CLAUSE(simd)
+OPENMP_ORDERED_CLAUSE(depend)
+// Map types and map type modifier for 'map' clause.
+OPENMP_MAP_KIND(alloc)
+OPENMP_MAP_KIND(to)
+OPENMP_MAP_KIND(from)
+OPENMP_MAP_KIND(tofrom)
+OPENMP_MAP_KIND(delete)
+OPENMP_MAP_KIND(release)
+OPENMP_MAP_KIND(always)
+
+// Clauses allowed for OpenMP directive 'taskloop'.
+OPENMP_TASKLOOP_CLAUSE(if)
+OPENMP_TASKLOOP_CLAUSE(shared)
+OPENMP_TASKLOOP_CLAUSE(private)
+OPENMP_TASKLOOP_CLAUSE(firstprivate)
+OPENMP_TASKLOOP_CLAUSE(lastprivate)
+OPENMP_TASKLOOP_CLAUSE(default)
+OPENMP_TASKLOOP_CLAUSE(collapse)
+OPENMP_TASKLOOP_CLAUSE(final)
+OPENMP_TASKLOOP_CLAUSE(untied)
+OPENMP_TASKLOOP_CLAUSE(mergeable)
+OPENMP_TASKLOOP_CLAUSE(priority)
+OPENMP_TASKLOOP_CLAUSE(grainsize)
+OPENMP_TASKLOOP_CLAUSE(nogroup)
+OPENMP_TASKLOOP_CLAUSE(num_tasks)
+
+// Clauses allowed for OpenMP directive 'taskloop simd'.
+OPENMP_TASKLOOP_SIMD_CLAUSE(if)
+OPENMP_TASKLOOP_SIMD_CLAUSE(shared)
+OPENMP_TASKLOOP_SIMD_CLAUSE(private)
+OPENMP_TASKLOOP_SIMD_CLAUSE(firstprivate)
+OPENMP_TASKLOOP_SIMD_CLAUSE(lastprivate)
+OPENMP_TASKLOOP_SIMD_CLAUSE(default)
+OPENMP_TASKLOOP_SIMD_CLAUSE(collapse)
+OPENMP_TASKLOOP_SIMD_CLAUSE(final)
+OPENMP_TASKLOOP_SIMD_CLAUSE(untied)
+OPENMP_TASKLOOP_SIMD_CLAUSE(mergeable)
+OPENMP_TASKLOOP_SIMD_CLAUSE(priority)
+OPENMP_TASKLOOP_SIMD_CLAUSE(linear)
+OPENMP_TASKLOOP_SIMD_CLAUSE(aligned)
+OPENMP_TASKLOOP_SIMD_CLAUSE(safelen)
+OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen)
+OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize)
+OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup)
+OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks)
+
+// Clauses allowed for OpenMP directive 'critical'.
+OPENMP_CRITICAL_CLAUSE(hint)
+
+// Clauses allowed for OpenMP directive 'distribute'
+OPENMP_DISTRIBUTE_CLAUSE(private)
+OPENMP_DISTRIBUTE_CLAUSE(firstprivate)
+OPENMP_DISTRIBUTE_CLAUSE(lastprivate)
+OPENMP_DISTRIBUTE_CLAUSE(collapse)
+OPENMP_DISTRIBUTE_CLAUSE(dist_schedule)
+
+// Static attributes for 'dist_schedule' clause.
+OPENMP_DIST_SCHEDULE_KIND(static)
+
+#undef OPENMP_TASKLOOP_SIMD_CLAUSE
+#undef OPENMP_TASKLOOP_CLAUSE
#undef OPENMP_LINEAR_KIND
#undef OPENMP_DEPEND_KIND
+#undef OPENMP_SCHEDULE_MODIFIER
#undef OPENMP_SCHEDULE_KIND
#undef OPENMP_PROC_BIND_KIND
#undef OPENMP_DEFAULT_KIND
#undef OPENMP_DIRECTIVE
#undef OPENMP_DIRECTIVE_EXT
#undef OPENMP_CLAUSE
+#undef OPENMP_CRITICAL_CLAUSE
#undef OPENMP_ORDERED_CLAUSE
#undef OPENMP_CANCEL_CLAUSE
#undef OPENMP_SINGLE_CLAUSE
@@ -345,4 +455,6 @@
#undef OPENMP_SIMD_CLAUSE
#undef OPENMP_FOR_CLAUSE
#undef OPENMP_FOR_SIMD_CLAUSE
-
+#undef OPENMP_MAP_KIND
+#undef OPENMP_DISTRIBUTE_CLAUSE
+#undef OPENMP_DIST_SCHEDULE_KIND
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index d981a24..e7e87e7 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -62,6 +62,15 @@
OMPC_SCHEDULE_unknown
};
+/// \brief OpenMP modifiers for 'schedule' clause.
+enum OpenMPScheduleClauseModifier {
+ OMPC_SCHEDULE_MODIFIER_unknown = OMPC_SCHEDULE_unknown,
+#define OPENMP_SCHEDULE_MODIFIER(Name) \
+ OMPC_SCHEDULE_MODIFIER_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_SCHEDULE_MODIFIER_last
+};
+
/// \brief OpenMP attributes for 'depend' clause.
enum OpenMPDependClauseKind {
#define OPENMP_DEPEND_KIND(Name) \
@@ -78,6 +87,21 @@
OMPC_LINEAR_unknown
};
+/// \brief OpenMP mapping kind for 'map' clause.
+enum OpenMPMapClauseKind {
+#define OPENMP_MAP_KIND(Name) \
+ OMPC_MAP_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_MAP_unknown
+};
+
+/// \brief OpenMP attributes for 'dist_schedule' clause.
+enum OpenMPDistScheduleClauseKind {
+#define OPENMP_DIST_SCHEDULE_KIND(Name) OMPC_DIST_SCHEDULE_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_DIST_SCHEDULE_unknown
+};
+
OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str);
const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind);
@@ -103,6 +127,12 @@
/// otherwise - false.
bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind);
+/// \brief Checks if the specified directive is a taskloop directive.
+/// \param DKind Specified directive.
+/// \return true - the directive is a worksharing directive like 'omp taskloop',
+/// otherwise - false.
+bool isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind);
+
/// \brief Checks if the specified directive is a parallel-kind directive.
/// \param DKind Specified directive.
/// \return true - the directive is a parallel-like directive like 'omp
@@ -127,6 +157,13 @@
/// otherwise - false.
bool isOpenMPSimdDirective(OpenMPDirectiveKind DKind);
+/// \brief Checks if the specified directive is a distribute directive.
+/// \param DKind Specified directive.
+/// \return true - the directive is a distribute-directive like 'omp
+/// distribute',
+/// otherwise - false.
+bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind);
+
/// \brief Checks if the specified clause is one of private clauses like
/// 'private', 'firstprivate', 'reduction' etc..
/// \param Kind Clause kind.
diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h
index 98e70de..bfa8e51 100644
--- a/include/clang/Basic/Sanitizers.h
+++ b/include/clang/Basic/Sanitizers.h
@@ -46,8 +46,6 @@
}
struct SanitizerSet {
- SanitizerSet() : Mask(0) {}
-
/// \brief Check if a certain (single) sanitizer is enabled.
bool has(SanitizerMask K) const {
assert(llvm::isPowerOf2_64(K));
@@ -70,7 +68,7 @@
bool empty() const { return Mask == 0; }
/// \brief Bitmask of enabled sanitizers.
- SanitizerMask Mask;
+ SanitizerMask Mask = 0;
};
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 8efcd79..99392a0 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -39,6 +39,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -121,7 +122,7 @@
/// \brief The number of lines in this ContentCache.
///
/// This is only valid if SourceLineCache is non-null.
- unsigned NumLines : 31;
+ unsigned NumLines;
/// \brief Indicates whether the buffer itself was provided to override
/// the actual file contents.
@@ -134,12 +135,17 @@
/// file considered as a system one.
unsigned IsSystemFile : 1;
+ /// \brief True if this file may be transient, that is, if it might not
+ /// exist at some later point in time when this content entry is used,
+ /// after serialization and deserialization.
+ unsigned IsTransient : 1;
+
ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {}
ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
: Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt),
SourceLineCache(nullptr), NumLines(0), BufferOverridden(false),
- IsSystemFile(false) {}
+ IsSystemFile(false), IsTransient(false) {}
~ContentCache();
@@ -148,7 +154,7 @@
/// is not transferred, so this is a logical error.
ContentCache(const ContentCache &RHS)
: Buffer(nullptr, false), SourceLineCache(nullptr),
- BufferOverridden(false), IsSystemFile(false) {
+ BufferOverridden(false), IsSystemFile(false), IsTransient(false) {
OrigEntry = RHS.OrigEntry;
ContentsEntry = RHS.ContentsEntry;
@@ -388,15 +394,16 @@
/// SourceManager keeps an array of these objects, and they are uniquely
/// identified by the FileID datatype.
class SLocEntry {
- unsigned Offset; // low bit is set for expansion info.
+ unsigned Offset : 31;
+ unsigned IsExpansion : 1;
union {
FileInfo File;
ExpansionInfo Expansion;
};
public:
- unsigned getOffset() const { return Offset >> 1; }
+ unsigned getOffset() const { return Offset; }
- bool isExpansion() const { return Offset & 1; }
+ bool isExpansion() const { return IsExpansion; }
bool isFile() const { return !isExpansion(); }
const FileInfo &getFile() const {
@@ -410,15 +417,19 @@
}
static SLocEntry get(unsigned Offset, const FileInfo &FI) {
+ assert(!(Offset & (1 << 31)) && "Offset is too large");
SLocEntry E;
- E.Offset = Offset << 1;
+ E.Offset = Offset;
+ E.IsExpansion = false;
E.File = FI;
return E;
}
static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) {
+ assert(!(Offset & (1 << 31)) && "Offset is too large");
SLocEntry E;
- E.Offset = (Offset << 1) | 1;
+ E.Offset = Offset;
+ E.IsExpansion = true;
E.Expansion = Expansion;
return E;
}
@@ -560,6 +571,11 @@
/// (likely to change while trying to use them). Defaults to false.
bool UserFilesAreVolatile;
+ /// \brief True if all files read during this compilation should be treated
+ /// as transient (may not be present in later compilations using a module
+ /// file created from this compilation). Defaults to false.
+ bool FilesAreTransient;
+
struct OverriddenFilesInfoTy {
/// \brief Files that have been overridden with the contents from another
/// file.
@@ -615,7 +631,7 @@
/// have already been loaded from the external source.
///
/// Same indexing as LoadedSLocEntryTable.
- std::vector<bool> SLocEntryLoaded;
+ llvm::BitVector SLocEntryLoaded;
/// \brief An external source for source location entries.
ExternalSLocEntrySource *ExternalSLocEntries;
@@ -851,12 +867,14 @@
/// This should be called before parsing has begun.
void disableFileContentsOverride(const FileEntry *File);
- /// \brief Request that the contents of the given source file are written
- /// to a created module file if they are used in this compilation. This
- /// removes the requirement that the file still exist when the module is used
- /// (but does not make the file visible to header search and the like when
- /// the module is used).
- void embedFileContentsInModule(const FileEntry *SourceFile);
+ /// \brief Specify that a file is transient.
+ void setFileIsTransient(const FileEntry *SourceFile);
+
+ /// \brief Specify that all files that are read during this compilation are
+ /// transient.
+ void setAllFilesAreTransient(bool Transient) {
+ FilesAreTransient = Transient;
+ }
//===--------------------------------------------------------------------===//
// FileID manipulation methods.
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 47d2f31..e284171 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
namespace clang {
/// \brief Specifies the width of a type, e.g., short, long, or long long.
@@ -35,6 +36,11 @@
TSS_unsigned
};
+ enum TypeSpecifiersPipe {
+ TSP_unspecified,
+ TSP_pipe
+ };
+
/// \brief Specifies the kind of type.
enum TypeSpecifierType {
TST_unspecified,
@@ -64,6 +70,7 @@
TST_underlyingType, // __underlying_type for C++11
TST_auto, // C++11 auto
TST_decltype_auto, // C++1y decltype(auto)
+ TST_auto_type, // __auto_type extension
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
TST_error // erroneous type
@@ -156,6 +163,24 @@
return Kind != TSK_Undeclared && Kind != TSK_ExplicitSpecialization;
}
+ /// \brief True if this template specialization kind is an explicit
+ /// specialization, explicit instantiation declaration, or explicit
+ /// instantiation definition.
+ inline bool isTemplateExplicitInstantiationOrSpecialization(
+ TemplateSpecializationKind Kind) {
+ switch (Kind) {
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ return true;
+
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ return false;
+ }
+ llvm_unreachable("bad template specialization kind");
+ }
+
/// \brief Thread storage-class-specifier.
enum ThreadStorageClassSpecifier {
TSCS_unspecified,
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 6e66532..36519ea 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -145,8 +145,9 @@
def CXXFoldExpr : DStmt<Expr>;
// C++ Coroutines TS expressions
-def CoawaitExpr : DStmt<Expr>;
-def CoyieldExpr : DStmt<Expr>;
+def CoroutineSuspendExpr : DStmt<Expr, 1>;
+def CoawaitExpr : DStmt<CoroutineSuspendExpr>;
+def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
@@ -179,6 +180,7 @@
// Microsoft Extensions.
def MSPropertyRefExpr : DStmt<Expr>;
+def MSPropertySubscriptExpr : DStmt<Expr>;
def CXXUuidofExpr : DStmt<Expr>;
def SEHTryStmt : Stmt;
def SEHExceptStmt : Stmt;
@@ -217,3 +219,6 @@
def OMPTeamsDirective : DStmt<OMPExecutableDirective>;
def OMPCancellationPointDirective : DStmt<OMPExecutableDirective>;
def OMPCancelDirective : DStmt<OMPExecutableDirective>;
+def OMPTaskLoopDirective : DStmt<OMPLoopDirective>;
+def OMPTaskLoopSimdDirective : DStmt<OMPLoopDirective>;
+def OMPDistributeDirective : DStmt<OMPLoopDirective>;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index b0c8349..f1d8338 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -644,6 +644,19 @@
}
};
+ /// \brief Validate register name used for global register variables.
+ ///
+ /// This function returns true if the register passed in RegName can be used
+ /// for global register variables on this target. In addition, it returns
+ /// true in HasSizeMismatch if the size of the register doesn't match the
+ /// variable size passed in RegSize.
+ virtual bool validateGlobalRegisterVariable(StringRef RegName,
+ unsigned RegSize,
+ bool &HasSizeMismatch) const {
+ HasSizeMismatch = false;
+ return true;
+ }
+
// validateOutputConstraint, validateInputConstraint - Checks that
// a constraint is valid and provides information about it.
// FIXME: These should return a real error instead of just true/false.
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 1e0ec11..0269451 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -384,6 +384,7 @@
KEYWORD(__thread , KEYALL)
KEYWORD(__FUNCTION__ , KEYALL)
KEYWORD(__PRETTY_FUNCTION__ , KEYALL)
+KEYWORD(__auto_type , KEYALL)
// GNU Extensions (outside impl-reserved namespace)
KEYWORD(typeof , KEYGNU)
@@ -518,6 +519,8 @@
// OpenMP Type Traits
KEYWORD(__builtin_omp_required_simd_align, KEYALL)
+KEYWORD(pipe , KEYOPENCL)
+
// Borland Extensions.
KEYWORD(__pascal , KEYALL)
@@ -696,6 +699,11 @@
// handles them.
ANNOTATION(pragma_captured)
+// Annotation for #pragma clang __debug dump...
+// The lexer produces these so that the parser and semantic analysis can
+// look up and dump the operand.
+ANNOTATION(pragma_dump)
+
// Annotation for #pragma ms_struct...
// The lexer produces these so that they only take effect when the parser
// handles them.
diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h
index 1df4947..bab88c9 100644
--- a/include/clang/Basic/VirtualFileSystem.h
+++ b/include/clang/Basic/VirtualFileSystem.h
@@ -299,10 +299,7 @@
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
return WorkingDirectory;
}
- std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
- WorkingDirectory = Path.str();
- return std::error_code();
- }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
};
/// \brief Get a globally unique ID for a virtual file or directory.
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index d088da4..4863566 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -373,6 +373,10 @@
(splat $p2, $p3))>;
def OP_QDMULH_LN : Op<(call "vqdmulh", $p0, (splat $p1, $p2))>;
def OP_QRDMULH_LN : Op<(call "vqrdmulh", $p0, (splat $p1, $p2))>;
+def OP_QRDMLAH : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1, $p2))>;
+def OP_QRDMLSH : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1, $p2))>;
+def OP_QRDMLAH_LN : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1, (splat $p2, $p3)))>;
+def OP_QRDMLSH_LN : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1, (splat $p2, $p3)))>;
def OP_FMS_LN : Op<(call "vfma_lane", $p0, $p1, (op "-", $p2), $p3)>;
def OP_FMS_LNQ : Op<(call "vfma_laneq", $p0, $p1, (op "-", $p2), $p3)>;
def OP_TRN1 : Op<(shuffle $p0, $p1, (interleave (decimate mask0, 2),
@@ -473,6 +477,11 @@
def OP_SCALAR_QDMULH_LN : ScalarMulOp<"vqdmulh">;
def OP_SCALAR_QRDMULH_LN : ScalarMulOp<"vqrdmulh">;
+def OP_SCALAR_QRDMLAH_LN : Op<(call "vqadd", $p0, (call "vqrdmulh", $p1,
+ (call "vget_lane", $p2, $p3)))>;
+def OP_SCALAR_QRDMLSH_LN : Op<(call "vqsub", $p0, (call "vqrdmulh", $p1,
+ (call "vget_lane", $p2, $p3)))>;
+
def OP_SCALAR_HALF_GET_LN : Op<(bitcast "float16_t",
(call "vget_lane",
(bitcast "int16x4_t", $p0), $p1))>;
@@ -514,6 +523,12 @@
def VMLSL : SOpInst<"vmlsl", "wwdd", "csiUcUsUi", OP_MLSL>;
def VQDMULH : SInst<"vqdmulh", "ddd", "siQsQi">;
def VQRDMULH : SInst<"vqrdmulh", "ddd", "siQsQi">;
+
+let ArchGuard = "defined(__ARM_FEATURE_QRDMX)" in {
+def VQRDMLAH : SOpInst<"vqrdmlah", "dddd", "siQsQi", OP_QRDMLAH>;
+def VQRDMLSH : SOpInst<"vqrdmlsh", "dddd", "siQsQi", OP_QRDMLSH>;
+}
+
def VQDMLAL : SInst<"vqdmlal", "wwdd", "si">;
def VQDMLSL : SInst<"vqdmlsl", "wwdd", "si">;
def VMULL : SInst<"vmull", "wdd", "csiUcUsUiPc">;
@@ -741,6 +756,12 @@
def VQDMULH_LANE : SOpInst<"vqdmulh_lane", "ddgi", "siQsQi", OP_QDMULH_LN>;
def VQRDMULH_N : SInst<"vqrdmulh_n", "dda", "siQsQi">;
def VQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "ddgi", "siQsQi", OP_QRDMULH_LN>;
+
+let ArchGuard = "defined(__ARM_FEATURE_QRDMX)" in {
+def VQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "dddgi", "siQsQi", OP_QRDMLAH_LN>;
+def VQRDMLSH_LANE : SOpInst<"vqrdmlsh_lane", "dddgi", "siQsQi", OP_QRDMLSH_LN>;
+}
+
def VMLA_N : IOpInst<"vmla_n", "ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>;
def VMLAL_N : SOpInst<"vmlal_n", "wwda", "siUsUi", OP_MLAL_N>;
def VQDMLAL_N : SInst<"vqdmlal_n", "wwda", "si">;
@@ -803,7 +824,10 @@
////////////////////////////////////////////////////////////////////////////////
// Vector fused multiply-add operations
-def VFMA : SInst<"vfma", "dddd", "fQf">;
+let ArchGuard = "defined(__ARM_FEATURE_FMA)" in {
+ def VFMA : SInst<"vfma", "dddd", "fQf">;
+ def VFMS : SInst<"vfms", "dddd", "fQf">;
+}
////////////////////////////////////////////////////////////////////////////////
// fp16 vector operations
@@ -887,7 +911,7 @@
////////////////////////////////////////////////////////////////////////////////
// Vector fused multiply-add operations
def FMLA : SInst<"vfma", "dddd", "dQd">;
-def FMLS : SInst<"vfms", "dddd", "fdQfQd">;
+def FMLS : SInst<"vfms", "dddd", "dQd">;
////////////////////////////////////////////////////////////////////////////////
// MUL, MLA, MLS, FMA, FMS definitions with scalar argument
@@ -1160,6 +1184,11 @@
def VQDMULH_LANEQ : SOpInst<"vqdmulh_laneq", "ddji", "siQsQi", OP_QDMULH_LN>;
def VQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ddji", "siQsQi", OP_QRDMULH_LN>;
+let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in {
+def VQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "dddji", "siQsQi", OP_QRDMLAH_LN>;
+def VQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "dddji", "siQsQi", OP_QRDMLSH_LN>;
+}
+
// Note: d type implemented by SCALAR_VMULX_LANE
def VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "fQfQd", OP_MULX_LN>;
// Note: d type is implemented by SCALAR_VMULX_LANEQ
@@ -1405,6 +1434,16 @@
// Scalar Integer Saturating Rounding Doubling Multiply Half High
def SCALAR_SQRDMULH : SInst<"vqrdmulh", "sss", "SsSi">;
+let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in {
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half
+def SCALAR_SQRDMLAH : SOpInst<"vqrdmlah", "ssss", "SsSi", OP_QRDMLAH>;
+
+////////////////////////////////////////////////////////////////////////////////
+// Signed Saturating Rounding Doubling Multiply Subtract Returning High Half
+def SCALAR_SQRDMLSH : SOpInst<"vqrdmlsh", "ssss", "SsSi", OP_QRDMLSH>;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Scalar Floating-point Multiply Extended
def SCALAR_FMULX : IInst<"vmulx", "sss", "SfSd">;
@@ -1606,6 +1645,16 @@
def SCALAR_SQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "ssdi", "SsSi", OP_SCALAR_QRDMULH_LN>;
def SCALAR_SQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ssji", "SsSi", OP_SCALAR_QRDMULH_LN>;
+let ArchGuard = "defined(__ARM_FEATURE_QRDMX) && defined(__aarch64__)" in {
+// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half
+def SCALAR_SQRDMLAH_LANE : SOpInst<"vqrdmlah_lane", "sssdi", "SsSi", OP_SCALAR_QRDMLAH_LN>;
+def SCALAR_SQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "sssji", "SsSi", OP_SCALAR_QRDMLAH_LN>;
+
+// Signed Saturating Rounding Doubling Multiply Subtract Returning High Half
+def SCALAR_SQRDMLSH_LANE : SOpInst<"vqrdmlsh_lane", "sssdi", "SsSi", OP_SCALAR_QRDMLSH_LN>;
+def SCALAR_SQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "sssji", "SsSi", OP_SCALAR_QRDMLSH_LN>;
+}
+
def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
}
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index 8586e77..d375a78 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -11,6 +11,8 @@
#define LLVM_CLANG_CODEGEN_BACKENDUTIL_H
#include "clang/Basic/LLVM.h"
+#include "llvm/IR/FunctionInfo.h"
+#include <memory>
namespace llvm {
class Module;
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
index a3ce8c2..bb6ceb4 100644
--- a/include/clang/CodeGen/CGFunctionInfo.h
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -509,6 +509,29 @@
}
};
+/// CGCalleeInfo - Class to encapsulate the information about a callee to be
+/// used during the generation of call/invoke instructions.
+class CGCalleeInfo {
+ /// \brief The function proto type of the callee.
+ const FunctionProtoType *CalleeProtoTy;
+ /// \brief The function declaration of the callee.
+ const Decl *CalleeDecl;
+
+public:
+ explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const Decl *calleeDecl)
+ : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
+
+ const FunctionProtoType *getCalleeFunctionProtoType() {
+ return CalleeProtoTy;
+ }
+ const Decl *getCalleeDecl() { return CalleeDecl; }
+};
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h
index d3a3a9b..9d9504a 100644
--- a/include/clang/CodeGen/CodeGenABITypes.h
+++ b/include/clang/CodeGen/CodeGenABITypes.h
@@ -36,6 +36,7 @@
namespace clang {
class ASTContext;
class CXXRecordDecl;
+class CXXMethodDecl;
class CodeGenOptions;
class CoverageSourceInfo;
class DiagnosticsEngine;
@@ -60,12 +61,13 @@
const CGFunctionInfo &arrangeObjCMessageSendSignature(
const ObjCMethodDecl *MD,
QualType receiverType);
- const CGFunctionInfo &arrangeFreeFunctionType(
- CanQual<FunctionProtoType> Ty);
+ const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
+ const FunctionDecl *FD);
const CGFunctionInfo &arrangeFreeFunctionType(
CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP);
+ const FunctionProtoType *FTP,
+ const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeFreeFunctionCall(CanQualType returnType,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 077f1a9..2cf53bc 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -15,6 +15,9 @@
#include "llvm/ADT/SmallVector.h"
namespace llvm {
+
+class StringRef;
+
namespace opt {
class Arg;
}
@@ -32,6 +35,9 @@
/// single primary output, at least in terms of controlling the
/// compilation. Actions can produce auxiliary files, but can only
/// produce a single output to feed into subsequent actions.
+///
+/// Actions are usually owned by a Compilation, which creates new
+/// actions via MakeAction().
class Action {
public:
typedef ActionList::size_type size_type;
@@ -70,27 +76,20 @@
ActionList Inputs;
- unsigned OwnsInputs : 1;
-
protected:
- Action(ActionClass Kind, types::ID Type)
- : Kind(Kind), Type(Type), OwnsInputs(true) {}
- Action(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type)
- : Kind(Kind), Type(Type), Inputs(1, Input.release()), OwnsInputs(true) {
- }
- Action(ActionClass Kind, std::unique_ptr<Action> Input)
- : Kind(Kind), Type(Input->getType()), Inputs(1, Input.release()),
- OwnsInputs(true) {}
+ Action(ActionClass Kind, types::ID Type) : Action(Kind, ActionList(), Type) {}
+ Action(ActionClass Kind, Action *Input, types::ID Type)
+ : Action(Kind, ActionList({Input}), Type) {}
+ Action(ActionClass Kind, Action *Input)
+ : Action(Kind, ActionList({Input}), Input->getType()) {}
Action(ActionClass Kind, const ActionList &Inputs, types::ID Type)
- : Kind(Kind), Type(Type), Inputs(Inputs), OwnsInputs(true) {}
+ : Kind(Kind), Type(Type), Inputs(Inputs) {}
+
public:
virtual ~Action();
const char *getClassName() const { return Action::getClassName(getKind()); }
- bool getOwnsInputs() { return OwnsInputs; }
- void setOwnsInputs(bool Value) { OwnsInputs = Value; }
-
ActionClass getKind() const { return Kind; }
types::ID getType() const { return Type; }
@@ -126,7 +125,7 @@
const char *ArchName;
public:
- BindArchAction(std::unique_ptr<Action> Input, const char *ArchName);
+ BindArchAction(Action *Input, const char *ArchName);
const char *getArchName() const { return ArchName; }
@@ -137,21 +136,26 @@
class CudaDeviceAction : public Action {
virtual void anchor();
- /// GPU architecture to bind -- e.g 'sm_35'.
+ /// GPU architecture to bind. Always of the form /sm_\d+/ or null (when the
+ /// action applies to multiple architectures).
const char *GpuArchName;
- const char *DeviceTriple;
/// True when action results are not consumed by the host action (e.g when
/// -fsyntax-only or --cuda-device-only options are used).
bool AtTopLevel;
public:
- CudaDeviceAction(std::unique_ptr<Action> Input, const char *ArchName,
- const char *DeviceTriple, bool AtTopLevel);
+ CudaDeviceAction(Action *Input, const char *ArchName, bool AtTopLevel);
const char *getGpuArchName() const { return GpuArchName; }
- const char *getDeviceTriple() const { return DeviceTriple; }
+
+ /// Gets the compute_XX that corresponds to getGpuArchName(). Returns null
+ /// when getGpuArchName() is null.
+ const char *getComputeArchName() const;
+
bool isAtTopLevel() const { return AtTopLevel; }
+ static bool IsValidGpuArchName(llvm::StringRef ArchName);
+
static bool classof(const Action *A) {
return A->getKind() == CudaDeviceClass;
}
@@ -160,16 +164,11 @@
class CudaHostAction : public Action {
virtual void anchor();
ActionList DeviceActions;
- const char *DeviceTriple;
public:
- CudaHostAction(std::unique_ptr<Action> Input, const ActionList &DeviceActions,
- const char *DeviceTriple);
- ~CudaHostAction() override;
+ CudaHostAction(Action *Input, const ActionList &DeviceActions);
- ActionList &getDeviceActions() { return DeviceActions; }
const ActionList &getDeviceActions() const { return DeviceActions; }
- const char *getDeviceTriple() const { return DeviceTriple; }
static bool classof(const Action *A) { return A->getKind() == CudaHostClass; }
};
@@ -177,7 +176,7 @@
class JobAction : public Action {
virtual void anchor();
protected:
- JobAction(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type);
+ JobAction(ActionClass Kind, Action *Input, types::ID Type);
JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
public:
@@ -190,7 +189,7 @@
class PreprocessJobAction : public JobAction {
void anchor() override;
public:
- PreprocessJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ PreprocessJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PreprocessJobClass;
@@ -200,7 +199,7 @@
class PrecompileJobAction : public JobAction {
void anchor() override;
public:
- PrecompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ PrecompileJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PrecompileJobClass;
@@ -210,7 +209,7 @@
class AnalyzeJobAction : public JobAction {
void anchor() override;
public:
- AnalyzeJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ AnalyzeJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AnalyzeJobClass;
@@ -220,7 +219,7 @@
class MigrateJobAction : public JobAction {
void anchor() override;
public:
- MigrateJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ MigrateJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == MigrateJobClass;
@@ -230,7 +229,7 @@
class CompileJobAction : public JobAction {
void anchor() override;
public:
- CompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ CompileJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == CompileJobClass;
@@ -240,7 +239,7 @@
class BackendJobAction : public JobAction {
void anchor() override;
public:
- BackendJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ BackendJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == BackendJobClass;
@@ -250,7 +249,7 @@
class AssembleJobAction : public JobAction {
void anchor() override;
public:
- AssembleJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ AssembleJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AssembleJobClass;
@@ -290,8 +289,7 @@
class VerifyJobAction : public JobAction {
void anchor() override;
public:
- VerifyJobAction(ActionClass Kind, std::unique_ptr<Action> Input,
- types::ID Type);
+ VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass ||
A->getKind() == VerifyPCHJobClass;
@@ -301,7 +299,7 @@
class VerifyDebugInfoJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyDebugInfoJobAction(std::unique_ptr<Action> Input, types::ID Type);
+ VerifyDebugInfoJobAction(Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass;
}
@@ -310,7 +308,7 @@
class VerifyPCHJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyPCHJobAction(std::unique_ptr<Action> Input, types::ID Type);
+ VerifyPCHJobAction(Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyPCHJobClass;
}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 24d32ee..837fbff 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -134,6 +134,7 @@
def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
def dwarf_version_EQ : Joined<["-"], "dwarf-version=">;
+def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">;
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
HelpText<"The compilation directory to embed in the debug info.">;
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
@@ -251,6 +252,8 @@
HelpText<"Run the BB vectorization passes">;
def dependent_lib : Joined<["--"], "dependent-lib=">,
HelpText<"Add dependent library">;
+def linker_option : Joined<["--"], "linker-option=">,
+ HelpText<"Add linker option">;
def fsanitize_coverage_type : Joined<["-"], "fsanitize-coverage-type=">,
HelpText<"Sanitizer coverage type">;
def fsanitize_coverage_indirect_calls
@@ -381,6 +384,9 @@
MetaVarName<"<file>">,
HelpText<"Embed the contents of the specified file into the module file "
"being compiled.">;
+def fmodules_embed_all_files : Joined<["-"], "fmodules-embed-all-files">,
+ HelpText<"Embed the contents of all files read by this compilation into "
+ "the produced module file.">;
def fmodules_local_submodule_visibility :
Flag<["-"], "fmodules-local-submodule-visibility">,
HelpText<"Enforce name visibility rules across submodules of the same "
@@ -388,10 +394,6 @@
def fmodule_format_EQ : Joined<["-"], "fmodule-format=">,
HelpText<"Select the container format for clang modules and PCH. "
"Supported options are 'raw' and 'obj'.">;
-def fno_modules_hide_internal_linkage :
- Flag<["-"], "fno-modules-hide-internal-linkage">,
- HelpText<"Make all declarations visible to redeclaration lookup, "
- "even if they have internal linkage.">;
def ftest_module_file_extension_EQ :
Joined<["-"], "ftest-module-file-extension=">,
HelpText<"introduce a module file extension for testing purposes. "
@@ -677,6 +679,15 @@
def fcuda_target_overloads : Flag<["-"], "fcuda-target-overloads">,
HelpText<"Enable function overloads based on CUDA target attributes.">;
+//===----------------------------------------------------------------------===//
+// OpenMP Options
+//===----------------------------------------------------------------------===//
+
+def fopenmp_is_device : Flag<["-"], "fopenmp-is-device">,
+ HelpText<"Generate code only for an OpenMP target device.">;
+def omp_host_ir_file_path : Separate<["-"], "omp-host-ir-file-path">,
+ HelpText<"Path to the IR file produced by the frontend for the host.">;
+
} // let Flags = [CC1Option]
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index a8282b4..16a5b72 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -52,6 +52,12 @@
// (We don't put any of these in cl_compile_Group as the options they alias are
// already in the right group.)
+def _SLASH_Brepro : CLFlag<"Brepro">,
+ HelpText<"Emit an object file which can be reproduced over time">,
+ Alias<mincremental_linker_compatible>;
+def _SLASH_Brepro_ : CLFlag<"Brepro-">,
+ HelpText<"Emit an object file which cannot be reproduced over time">,
+ Alias<mno_incremental_linker_compatible>;
def _SLASH_C : CLFlag<"C">,
HelpText<"Don't discard comments when preprocessing">, Alias<C>;
def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>;
@@ -119,8 +125,8 @@
def _SLASH_W1 : CLFlag<"W1">, HelpText<"Enable -Wall">, Alias<Wall>;
def _SLASH_W2 : CLFlag<"W2">, HelpText<"Enable -Wall">, Alias<Wall>;
def _SLASH_W3 : CLFlag<"W3">, HelpText<"Enable -Wall">, Alias<Wall>;
-def _SLASH_W4 : CLFlag<"W4">, HelpText<"Enable -Wall">, Alias<Wall>;
-def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Wall">, Alias<Wall>;
+def _SLASH_W4 : CLFlag<"W4">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>;
+def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>;
def _SLASH_WX : CLFlag<"WX">, HelpText<"Treat warnings as errors">,
Alias<W_Joined>, AliasArgs<["error"]>;
def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">,
@@ -128,10 +134,12 @@
def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias<w>;
def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>,
AliasArgs<["no-macro-redefined"]>;
-def _SLASH_wd4996 : CLFlag<"wd4996">, Alias<W_Joined>,
- AliasArgs<["no-deprecated-declarations"]>;
+def _SLASH_wd4100 : CLFlag<"wd4100">, Alias<W_Joined>,
+ AliasArgs<["no-unused-parameter"]>;
def _SLASH_wd4910 : CLFlag<"wd4910">, Alias<W_Joined>,
AliasArgs<["no-dllexport-explicit-instantiation-decl"]>;
+def _SLASH_wd4996 : CLFlag<"wd4996">, Alias<W_Joined>,
+ AliasArgs<["no-deprecated-declarations"]>;
def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">,
Alias<vtordisp_mode_EQ>;
def _SLASH_Zc_sizedDealloc : CLFlag<"Zc:sizedDealloc">,
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index f0c1bed..3ed1913 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_DRIVER_COMPILATION_H
#define LLVM_CLANG_DRIVER_COMPILATION_H
+#include "clang/Driver/Action.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/DenseMap.h"
@@ -25,7 +26,6 @@
namespace clang {
namespace driver {
class Driver;
- class JobAction;
class JobList;
class ToolChain;
@@ -38,6 +38,9 @@
/// The default tool chain.
const ToolChain &DefaultToolChain;
+ const ToolChain *CudaHostToolChain;
+ const ToolChain *CudaDeviceToolChain;
+
/// The original (untranslated) input argument list.
llvm::opt::InputArgList *Args;
@@ -45,7 +48,12 @@
/// own argument translation.
llvm::opt::DerivedArgList *TranslatedArgs;
- /// The list of actions.
+ /// The list of actions we've created via MakeAction. This is not accessible
+ /// to consumers; it's here just to manage ownership.
+ std::vector<std::unique_ptr<Action>> AllActions;
+
+ /// The list of actions. This is maintained and modified by consumers, via
+ /// getActions().
ActionList Actions;
/// The root list of jobs.
@@ -81,6 +89,17 @@
const Driver &getDriver() const { return TheDriver; }
const ToolChain &getDefaultToolChain() const { return DefaultToolChain; }
+ const ToolChain *getCudaHostToolChain() const { return CudaHostToolChain; }
+ const ToolChain *getCudaDeviceToolChain() const {
+ return CudaDeviceToolChain;
+ }
+
+ void setCudaHostToolChain(const ToolChain *HostToolChain) {
+ CudaHostToolChain = HostToolChain;
+ }
+ void setCudaDeviceToolChain(const ToolChain *DeviceToolChain) {
+ CudaDeviceToolChain = DeviceToolChain;
+ }
const llvm::opt::InputArgList &getInputArgs() const { return *Args; }
@@ -91,6 +110,15 @@
ActionList &getActions() { return Actions; }
const ActionList &getActions() const { return Actions; }
+ /// Creates a new Action owned by this Compilation.
+ ///
+ /// The new Action is *not* added to the list returned by getActions().
+ template <typename T, typename... Args> T *MakeAction(Args &&... Arg) {
+ T *RawPtr = new T(std::forward<Args>(Arg)...);
+ AllActions.push_back(std::unique_ptr<Action>(RawPtr));
+ return RawPtr;
+ }
+
JobList &getJobs() { return Jobs; }
const JobList &getJobs() const { return Jobs; }
@@ -179,7 +207,7 @@
void initCompilationForDiagnostics();
/// Return true if we're compiling for diagnostics.
- bool isForDiagnostics() { return ForDiagnostics; }
+ bool isForDiagnostics() const { return ForDiagnostics; }
};
} // end namespace driver
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 213ae38..250211c 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -18,10 +18,11 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo
-#include <memory>
- // lands.
+#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo lands.
+
#include <list>
+#include <map>
+#include <memory>
#include <set>
#include <string>
@@ -297,22 +298,21 @@
/// BuildActions - Construct the list of actions to perform for the
/// given arguments, which are only done for a single architecture.
///
+ /// \param C - The compilation that is being built.
/// \param TC - The default host tool chain.
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
- void BuildActions(const ToolChain &TC, llvm::opt::DerivedArgList &Args,
- const InputList &Inputs, ActionList &Actions) const;
+ void BuildActions(Compilation &C, const ToolChain &TC,
+ llvm::opt::DerivedArgList &Args, const InputList &Inputs,
+ ActionList &Actions) const;
/// BuildUniversalActions - Construct the list of actions to perform
/// for the given arguments, which may require a universal build.
///
+ /// \param C - The compilation that is being built.
/// \param TC - The default host tool chain.
- /// \param Args - The input arguments.
- /// \param Actions - The list to store the resulting actions onto.
- void BuildUniversalActions(const ToolChain &TC,
- llvm::opt::DerivedArgList &Args,
- const InputList &BAInputs,
- ActionList &Actions) const;
+ void BuildUniversalActions(Compilation &C, const ToolChain &TC,
+ const InputList &BAInputs) const;
/// BuildJobs - Bind actions to concrete tools and translate
/// arguments to form the list of jobs to run.
@@ -376,20 +376,19 @@
/// ConstructAction - Construct the appropriate action to do for
/// \p Phase on the \p Input, taking in to account arguments
/// like -fsyntax-only or --analyze.
- std::unique_ptr<Action>
- ConstructPhaseAction(const ToolChain &TC, const llvm::opt::ArgList &Args,
- phases::ID Phase, std::unique_ptr<Action> Input) const;
+ Action *ConstructPhaseAction(Compilation &C, const ToolChain &TC,
+ const llvm::opt::ArgList &Args, phases::ID Phase,
+ Action *Input) const;
- /// BuildJobsForAction - Construct the jobs to perform for the
- /// action \p A.
- void BuildJobsForAction(Compilation &C,
- const Action *A,
- const ToolChain *TC,
- const char *BoundArch,
- bool AtTopLevel,
- bool MultipleArchs,
- const char *LinkingOutput,
- InputInfo &Result) const;
+ /// BuildJobsForAction - Construct the jobs to perform for the action \p A and
+ /// return an InputInfo for the result of running \p A. Will only construct
+ /// jobs for a given (Action, ToolChain, BoundArch) tuple once.
+ InputInfo BuildJobsForAction(Compilation &C, const Action *A,
+ const ToolChain *TC, const char *BoundArch,
+ bool AtTopLevel, bool MultipleArchs,
+ const char *LinkingOutput,
+ std::map<std::pair<const Action *, std::string>,
+ InputInfo> &CachedResults) const;
/// Returns the default name for linked images (e.g., "a.out").
const char *getDefaultImageName() const;
@@ -446,6 +445,16 @@
/// the driver mode.
std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const;
+ /// Helper used in BuildJobsForAction. Doesn't use the cache when building
+ /// jobs specifically for the given action, but will use the cache when
+ /// building jobs for the Action's inputs.
+ InputInfo BuildJobsForActionNoCache(
+ Compilation &C, const Action *A, const ToolChain *TC,
+ const char *BoundArch, bool AtTopLevel, bool MultipleArchs,
+ const char *LinkingOutput,
+ std::map<std::pair<const Action *, std::string>, InputInfo>
+ &CachedResults) const;
+
public:
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
/// return the grouped values as integers. Numbers which are not
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 82b6651..55297d8 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -71,17 +71,31 @@
def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>;
def g_Group : OptionGroup<"<g group>">;
+def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>;
+def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>;
+def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>;
def g_flags_Group : OptionGroup<"<g flags group>">;
def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>;
def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>;
def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>;
-def m_x86_Features_Group : OptionGroup<"<m x86 features group>">, Group<m_Group>, Flags<[CoreOption]>;
-def m_hexagon_Features_Group : OptionGroup<"<m hexagon features group>">, Group<m_Group>;
-def m_arm_Features_Group : OptionGroup<"<m arm features group>">, Group<m_Group>;
-def m_aarch64_Features_Group : OptionGroup<"<m aarch64 features group>">, Group<m_Group>;
-def m_ppc_Features_Group : OptionGroup<"<m ppc features group>">, Group<m_Group>;
-def m_wasm_Features_Group : OptionGroup<"<m wasm features group>">,
- Group<m_Group>;
+
+// Feature groups - these take command line options that correspond directly to
+// target specific features and can be translated directly from command line
+// options.
+def m_x86_Features_Group : OptionGroup<"<x86 features group>">,
+ Group<m_Group>,
+ Flags<[CoreOption]>;
+def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">,
+ Group<m_Group>;
+def m_arm_Features_Group : OptionGroup<"<arm features group>">,
+ Group<m_Group>;
+def m_aarch64_Features_Group : OptionGroup<"<aarch64 features group>">,
+ Group<m_Group>;
+def m_ppc_Features_Group : OptionGroup<"<ppc features group>">,
+ Group<m_Group>;
+def m_wasm_Features_Group : OptionGroup<"<wasm features group>">,
+ Group<m_Group>;
+
def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>;
def u_Group : OptionGroup<"<u group>">;
@@ -295,6 +309,7 @@
HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
MetaVarName<"<arg>">;
def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option]>;
+def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option]>;
def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>;
def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>;
def Wextra : Flag<["-"], "Wextra">, Group<W_Group>, Flags<[CC1Option]>;
@@ -321,6 +336,10 @@
def Xclang : Separate<["-"], "Xclang">,
HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">,
Flags<[DriverOption, CoreOption]>;
+def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">,
+ HelpText<"Pass <arg> to fatbinary invocation">, MetaVarName<"<arg>">;
+def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">,
+ HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">;
def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">;
def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
@@ -627,6 +646,18 @@
Group<f_clang_Group>;
def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
Group<f_clang_Group>;
+def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">;
+def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
+def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable sanitizer statistics gathering.">;
+def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Disable sanitizer statistics gathering.">;
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
@@ -701,6 +732,9 @@
HelpText<"Enable LTO in 'full' mode">;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>,
HelpText<"Disable LTO mode (default)">;
+def fthinlto_index_EQ : Joined<["-"], "fthinlto-index=">,
+ Flags<[CC1Option]>, Group<f_Group>,
+ HelpText<"Perform ThinLTO importing using provided function summary index">;
def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">,
Group<f_Group>, Flags<[DriverOption, CoreOption]>;
def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>;
@@ -798,7 +832,7 @@
def fno_borland_extensions : Flag<["-"], "fno-borland-extensions">, Group<f_Group>;
def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable implicit builtin knowledge of functions">;
-def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<clang_ignored_f_Group>,
+def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable implicit builtin knowledge of a specific function">;
def fno_math_builtin : Flag<["-"], "fno-math-builtin">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable implicit builtin knowledge of math functions">;
@@ -1128,26 +1162,28 @@
HelpText<"remap file source paths in debug info">;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
HelpText<"Generate source-level debug information">;
-def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<g_Group>,
+def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<gN_Group>,
HelpText<"Emit debug line number tables only">;
def gmlt : Flag<["-"], "gmlt">, Alias<gline_tables_only>;
-def g0 : Flag<["-"], "g0">, Group<g_Group>;
-def g1 : Flag<["-"], "g1">, Group<g_Group>, Alias<gline_tables_only>;
-def g2 : Flag<["-"], "g2">, Group<g_Group>;
-def g3 : Flag<["-"], "g3">, Group<g_Group>;
-def ggdb : Flag<["-"], "ggdb">, Group<g_Group>;
-def ggdb0 : Flag<["-"], "ggdb0">, Alias<g0>;
-// Redirect ggdb1 to <gline_tables_only>, not <g1>,
-// because aliases of aliases aren't allowed.
-def ggdb1 : Flag<["-"], "ggdb1">, Alias<gline_tables_only>;
-def ggdb2 : Flag<["-"], "ggdb2">, Alias<g2>;
-def ggdb3 : Flag<["-"], "ggdb3">, Alias<g3>;
+def g0 : Flag<["-"], "g0">, Group<gN_Group>;
+def g1 : Flag<["-"], "g1">, Group<gN_Group>, Alias<gline_tables_only>;
+def g2 : Flag<["-"], "g2">, Group<gN_Group>;
+def g3 : Flag<["-"], "g3">, Group<gN_Group>;
+def ggdb : Flag<["-"], "ggdb">, Group<gTune_Group>;
+def ggdb0 : Flag<["-"], "ggdb0">, Group<ggdbN_Group>;
+def ggdb1 : Flag<["-"], "ggdb1">, Group<ggdbN_Group>;
+def ggdb2 : Flag<["-"], "ggdb2">, Group<ggdbN_Group>;
+def ggdb3 : Flag<["-"], "ggdb3">, Group<ggdbN_Group>;
+def glldb : Flag<["-"], "glldb">, Group<gTune_Group>;
+def gsce : Flag<["-"], "gsce">, Group<gTune_Group>;
def gdwarf_2 : Flag<["-"], "gdwarf-2">, Group<g_Group>,
HelpText<"Generate source-level debug information with dwarf version 2">;
def gdwarf_3 : Flag<["-"], "gdwarf-3">, Group<g_Group>,
HelpText<"Generate source-level debug information with dwarf version 3">;
def gdwarf_4 : Flag<["-"], "gdwarf-4">, Group<g_Group>,
HelpText<"Generate source-level debug information with dwarf version 4">;
+def gdwarf_5 : Flag<["-"], "gdwarf-5">, Group<g_Group>,
+ HelpText<"Generate source-level debug information with dwarf version 5">;
def gcodeview : Flag<["-"], "gcodeview">,
HelpText<"Generate CodeView debug information">,
Flags<[CC1Option, CC1AsOption, CoreOption]>;
@@ -1281,6 +1317,8 @@
Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
+def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
+ HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">;
def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Force realign the stack at entry to every function">;
def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags<[CC1Option]>,
@@ -1349,6 +1387,7 @@
def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>;
def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>;
def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>;
+def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
@@ -1364,6 +1403,8 @@
def marm : Flag<["-"], "marm">, Alias<mno_thumb>;
def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_arm_Features_Group>,
HelpText<"Reserve the r9 register (ARM only)">;
+def mno_movt : Flag<["-"], "mno-movt">, Group<m_arm_Features_Group>,
+ HelpText<"Disallow use of movt/movw pairs (ARM only)">;
def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>,
HelpText<"Allow use of CRC instructions (ARM only)">;
def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>,
@@ -1410,8 +1451,10 @@
def mno_cmpb : Flag<["-"], "mno-cmpb">, Group<m_ppc_Features_Group>;
def misel : Flag<["-"], "misel">, Group<m_ppc_Features_Group>;
def mno_isel : Flag<["-"], "mno-isel">, Group<m_ppc_Features_Group>;
-def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_ppc_Features_Group>;
-def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_ppc_Features_Group>;
+def mmfocrf : Flag<["-"], "mmfocrf">, Group<m_ppc_Features_Group>;
+def mmfcrf : Flag<["-"], "mmfcrf">, Alias<mmfocrf>;
+def mno_mfocrf : Flag<["-"], "mno-mfocrf">, Group<m_ppc_Features_Group>;
+def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Alias<mno_mfocrf>;
def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_ppc_Features_Group>;
def mno_popcntd : Flag<["-"], "mno-popcntd">, Group<m_ppc_Features_Group>;
def mqpx : Flag<["-"], "mqpx">, Group<m_ppc_Features_Group>;
@@ -1450,6 +1493,11 @@
def mregparm_EQ : Joined<["-"], "mregparm=">, Group<m_Group>;
def mrelax_all : Flag<["-"], "mrelax-all">, Group<m_Group>, Flags<[CC1Option,CC1AsOption]>,
HelpText<"(integrated-as) Relax all machine instructions">;
+def mincremental_linker_compatible : Flag<["-"], "mincremental-linker-compatible">, Group<m_Group>,
+ Flags<[CC1Option,CC1AsOption]>,
+ HelpText<"(integrated-as) Emit an object file which can be used with an incremental linker">;
+def mno_incremental_linker_compatible : Flag<["-"], "mno-incremental-linker-compatible">, Group<m_Group>,
+ HelpText<"(integrated-as) Emit an object file which cannot be used with an incremental linker">;
def mrtd : Flag<["-"], "mrtd">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Make StdCall calling convention the default">;
def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">, Group<m_Group>;
@@ -1493,6 +1541,7 @@
def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>;
def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>;
+def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>;
def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>;
def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>;
def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>;
@@ -1602,6 +1651,8 @@
def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">;
def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>,
HelpText<"Disable builtin #include directories">;
+def nocudainc : Flag<["-"], "nocudainc">;
+def nocudalib : Flag<["-"], "nocudalib">;
def nodefaultlibs : Flag<["-"], "nodefaultlibs">;
def nofixprebinding : Flag<["-"], "nofixprebinding">;
def nolibc : Flag<["-"], "nolibc">;
@@ -1618,6 +1669,8 @@
def object : Flag<["-"], "object">;
def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>,
HelpText<"Write output to <file>">, MetaVarName<"<file>">;
+def omptargets_EQ : CommaJoined<["-"], "omptargets=">, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">;
def pagezero__size : JoinedOrSeparate<["-"], "pagezero_size">;
def pass_exit_codes : Flag<["-", "--"], "pass-exit-codes">, Flags<[Unsupported]>;
def pedantic_errors : Flag<["-", "--"], "pedantic-errors">, Group<pedantic_Group>, Flags<[CC1Option]>;
@@ -1870,16 +1923,22 @@
def _ : Joined<["--"], "">, Flags<[Unsupported]>;
def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group<m_hexagon_Features_Group>;
-def mv1 : Flag<["-"], "mv1">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
- AliasArgs<["v1"]>;
-def mv2 : Flag<["-"], "mv2">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
- AliasArgs<["v2"]>;
-def mv3 : Flag<["-"], "mv3">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
- AliasArgs<["v3"]>;
-def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
- AliasArgs<["v4"]>;
-def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<march_EQ>,
- AliasArgs<["v5"]>;
+def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv4"]>;
+def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>,
+ AliasArgs<["hexagonv5"]>;
+def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>;
+def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>;
+def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>,
+ Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">;
+def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>,
+ Flags<[CC1Option]>, HelpText<"Disable Hexagon Vector eXtensions">;
+def mhexagon_hvx_double : Flag<["-"], "mhvx-double">, Group<m_hexagon_Features_Group>,
+ Flags<[CC1Option]>, HelpText<"Enable Hexagon Double Vector eXtensions">;
+def mno_hexagon_hvx_double : Flag<["-"], "mno-hvx-double">, Group<m_hexagon_Features_Group>,
+ Flags<[CC1Option]>, HelpText<"Disable Hexagon Double Vector eXtensions">;
// These are legacy user-facing driver-level option spellings. They are always
// aliases for options that are spelled using the more common Unix / GNU flag
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index d088cc0..072ddee 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -28,13 +28,15 @@
std::vector<std::string> BlacklistFiles;
std::vector<std::string> ExtraDeps;
- int CoverageFeatures;
- int MsanTrackOrigins;
- bool MsanUseAfterDtor;
- int AsanFieldPadding;
- bool AsanSharedRuntime;
- bool LinkCXXRuntimes;
- bool NeedPIE;
+ int CoverageFeatures = 0;
+ int MsanTrackOrigins = 0;
+ bool MsanUseAfterDtor = false;
+ bool CfiCrossDso = false;
+ int AsanFieldPadding = 0;
+ bool AsanSharedRuntime = false;
+ bool LinkCXXRuntimes = false;
+ bool NeedPIE = false;
+ bool Stats = false;
public:
/// Parses the sanitizer arguments from an argument list.
@@ -53,15 +55,15 @@
bool needsSafeStackRt() const {
return Sanitizers.has(SanitizerKind::SafeStack);
}
+ bool needsCfiRt() const;
+ bool needsCfiDiagRt() const;
+ bool needsStatsRt() const { return Stats; }
bool requiresPIE() const;
bool needsUnwindTables() const;
bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const;
-
- private:
- void clear();
};
} // namespace driver
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 03b057e..1778680 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Path.h"
+#include "llvm/Target/TargetOptions.h"
#include <memory>
#include <string>
@@ -92,6 +93,7 @@
protected:
MultilibSet Multilibs;
+ const char *DefaultLinker = "ld";
ToolChain(const Driver &D, const llvm::Triple &T,
const llvm::opt::ArgList &Args);
@@ -132,7 +134,7 @@
StringRef getOS() const { return Triple.getOSName(); }
/// \brief Provide the default architecture name (as expected by -arch) for
- /// this toolchain. Note t
+ /// this toolchain.
StringRef getDefaultUniversalArchName() const;
std::string getTripleString() const {
@@ -185,7 +187,7 @@
/// Choose a tool to use to handle the action \p JA.
///
/// This can be overridden when a particular ToolChain needs to use
- /// a C compiler other than Clang.
+ /// a compiler other than Clang.
virtual Tool *SelectTool(const JobAction &JA) const;
// Helper methods
@@ -226,7 +228,7 @@
virtual bool IsIntegratedAssemblerDefault() const { return false; }
/// \brief Check if the toolchain should use the integrated assembler.
- bool useIntegratedAs() const;
+ virtual bool useIntegratedAs() const;
/// IsMathErrnoDefault - Does this tool chain use -fmath-errno by default.
virtual bool IsMathErrnoDefault() const { return true; }
@@ -303,6 +305,11 @@
// i.e. a value of 'true' does not imply that debugging is wanted.
virtual bool GetDefaultStandaloneDebug() const { return false; }
+ // Return the default debugger "tuning."
+ virtual llvm::DebuggerKind getDefaultDebuggerTuning() const {
+ return llvm::DebuggerKind::GDB;
+ }
+
/// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
virtual bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const {
return false;
@@ -377,6 +384,10 @@
virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ /// AddFilePathLibArgs - Add each thing in getFilePaths() as a "-L" option.
+ void AddFilePathLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
/// AddCCKextLibArgs - Add the system specific linker arguments to use
/// for kernel extensions (Darwin-specific).
virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
@@ -393,6 +404,10 @@
virtual void addProfileRTLibs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ /// \brief Add arguments to use system-specific CUDA includes.
+ virtual void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
/// \brief Return sanitizers which are available in this toolchain.
virtual SanitizerMask getSupportedSanitizers() const;
};
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index d1b6915..baaa411 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -93,4 +93,5 @@
TYPE("image", Image, INVALID, "out", "")
TYPE("dSYM", dSYM, INVALID, "dSYM", "A")
TYPE("dependencies", Dependencies, INVALID, "d", "")
+TYPE("cuda-fatbin", CUDA_FATBIN, INVALID, "fatbin","A")
TYPE("none", Nothing, INVALID, nullptr, "u")
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index dd95d65..22122c7 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -63,6 +63,9 @@
/// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
bool isCXX(ID Id);
+ /// Is this LLVM IR.
+ bool isLLVMIR(ID Id);
+
/// isCuda - Is this a CUDA input.
bool isCuda(ID Id);
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index d4f1d7b..6d051e0 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -100,6 +100,13 @@
/// \brief If \c true, horizontally align operands of binary and ternary
/// expressions.
+ ///
+ /// Specifically, this aligns operands of a single expression that needs to be
+ /// split over multiple lines, e.g.:
+ /// \code
+ /// int aaa = bbbbbbbbbbbbbbb +
+ /// ccccccccccccccc;
+ /// \endcode
bool AlignOperands;
/// \brief If \c true, aligns trailing comments.
@@ -149,13 +156,33 @@
DRTBS_None,
/// Always break after the return type.
DRTBS_All,
- /// Always break after the return types of top level functions.
+ /// Always break after the return types of top-level functions.
DRTBS_TopLevel,
};
- /// \brief The function definition return type breaking style to use.
+ /// \brief Different ways to break after the function definition or
+ /// declaration return type.
+ enum ReturnTypeBreakingStyle {
+ /// Break after return type automatically.
+ /// \c PenaltyReturnTypeOnItsOwnLine is taken into account.
+ RTBS_None,
+ /// Always break after the return type.
+ RTBS_All,
+ /// Always break after the return types of top-level functions.
+ RTBS_TopLevel,
+ /// Always break after the return type of function definitions.
+ RTBS_AllDefinitions,
+ /// Always break after the return type of top-level definitions.
+ RTBS_TopLevelDefinitions,
+ };
+
+ /// \brief The function definition return type breaking style to use. This
+ /// option is deprecated and is retained for backwards compatibility.
DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType;
+ /// \brief The function declaration return type breaking style to use.
+ ReturnTypeBreakingStyle AlwaysBreakAfterReturnType;
+
/// \brief If \c true, always break before multiline string literals.
///
/// This flag is mean to make cases where there are multiple multiline strings
@@ -336,7 +363,7 @@
/// \brief The regular expression that this category matches.
std::string Regex;
/// \brief The priority to assign to this category.
- unsigned Priority;
+ int Priority;
bool operator==(const IncludeCategory &Other) const {
return Regex == Other.Regex && Priority == Other.Priority;
}
@@ -351,10 +378,12 @@
/// according to increasing category number and then alphabetically within
/// each category.
///
- /// If none of the regular expressions match, UINT_MAX is assigned as
- /// category. The main header for a source file automatically gets category 0,
- /// so that it is kept at the beginning of the #includes
- /// (http://llvm.org/docs/CodingStandards.html#include-style).
+ /// If none of the regular expressions match, INT_MAX is assigned as
+ /// category. The main header for a source file automatically gets category 0.
+ /// so that it is generally kept at the beginning of the #includes
+ /// (http://llvm.org/docs/CodingStandards.html#include-style). However, you
+ /// can also assign negative priorities if you have certain headers that
+ /// always need to be first.
///
/// To configure this in the .clang-format file, use:
/// \code
@@ -398,7 +427,9 @@
LK_JavaScript,
/// Should be used for Protocol Buffers
/// (https://developers.google.com/protocol-buffers/).
- LK_Proto
+ LK_Proto,
+ /// Should be used for TableGen code.
+ LK_TableGen
};
/// \brief Language, this format style is targeted at.
@@ -466,9 +497,15 @@
PAS_Middle
};
- /// Pointer and reference alignment style.
+ /// \brief Pointer and reference alignment style.
PointerAlignmentStyle PointerAlignment;
+ /// \brief If true, clang-format will attempt to re-flow comments.
+ bool ReflowComments;
+
+ /// \brief If true, clang-format will sort #includes.
+ bool SortIncludes;
+
/// \brief If \c true, a space may be inserted after C style casts.
bool SpaceAfterCStyleCast;
@@ -569,8 +606,7 @@
AllowShortIfStatementsOnASingleLine ==
R.AllowShortIfStatementsOnASingleLine &&
AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
- AlwaysBreakAfterDefinitionReturnType ==
- R.AlwaysBreakAfterDefinitionReturnType &&
+ AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType &&
AlwaysBreakBeforeMultilineStrings ==
R.AlwaysBreakBeforeMultilineStrings &&
AlwaysBreakTemplateDeclarations ==
@@ -685,7 +721,8 @@
/// are affected by 'Ranges'.
tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
- StringRef FileName);
+ StringRef FileName,
+ unsigned *Cursor = nullptr);
/// \brief Reformats the given \p Ranges in the file \p ID.
///
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index d326a53..a5f7af5 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -737,14 +737,15 @@
/// \brief Helper function for \c LoadFromCompilerInvocation() and
/// \c LoadFromCommandLine(), which loads an AST from a compiler invocation.
///
- /// \param PrecompilePreamble Whether to precompile the preamble of this
- /// translation unit, to improve the performance of reparsing.
+ /// \param PrecompilePreambleAfterNParses After how many parses the preamble
+ /// of this translation unit should be precompiled, to improve the performance
+ /// of reparsing. Set to zero to disable preambles.
///
/// \returns \c true if a catastrophic failure occurred (which means that the
/// \c ASTUnit itself is invalid), or \c false otherwise.
bool LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool PrecompilePreamble);
+ unsigned PrecompilePreambleAfterNParses);
public:
@@ -783,7 +784,8 @@
ASTFrontendAction *Action = nullptr, ASTUnit *Unit = nullptr,
bool Persistent = true, StringRef ResourceFilesPath = StringRef(),
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
- bool PrecompilePreamble = false, bool CacheCodeCompletionResults = false,
+ unsigned PrecompilePreambleAfterNParses = 0,
+ bool CacheCodeCompletionResults = false,
bool IncludeBriefCommentsInCodeCompletion = false,
bool UserFilesAreVolatile = false,
std::unique_ptr<ASTUnit> *ErrAST = nullptr);
@@ -807,7 +809,8 @@
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
- bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete,
+ unsigned PrecompilePreambleAfterNParses = 0,
+ TranslationUnitKind TUKind = TU_Complete,
bool CacheCodeCompletionResults = false,
bool IncludeBriefCommentsInCodeCompletion = false,
bool UserFilesAreVolatile = false);
@@ -842,7 +845,8 @@
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
ArrayRef<RemappedFile> RemappedFiles = None,
bool RemappedFilesKeepOriginalName = true,
- bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete,
+ unsigned PrecompilePreambleAfterNParses = 0,
+ TranslationUnitKind TUKind = TU_Complete,
bool CacheCodeCompletionResults = false,
bool IncludeBriefCommentsInCodeCompletion = false,
bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false,
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 5b8483c..7a6a7dc 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -75,6 +75,9 @@
///< compile step.
CODEGENOPT(EmitFunctionSummary, 1, 0) ///< Set when -flto=thin is enabled on the
///< compile step.
+CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can
+ ///< be used with an incremental
+ ///< linker.
CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants.
CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled.
CODEGENOPT(MSVolatile , 1, 0) ///< Set when /volatile:ms is enabled.
@@ -120,6 +123,7 @@
///< MemorySanitizer
CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
///< in MemorySanitizer
+CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI.
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
///< instrumentation.
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
@@ -130,6 +134,7 @@
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
///< in sanitizer coverage.
+CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
@@ -166,6 +171,10 @@
CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain
///< external references to a PCH or module.
+CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should
+ ///< contain explicit imports for
+ ///< anonymous namespaces
+
CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
/// The user specified number of registers to be used for integral arguments,
@@ -178,6 +187,9 @@
/// The kind of generated debug info.
ENUM_CODEGENOPT(DebugInfo, DebugInfoKind, 3, NoDebugInfo)
+/// Tune the debug info for this debugger.
+ENUM_CODEGENOPT(DebuggerTuning, DebuggerKind, 2, DebuggerKindDefault)
+
/// Dwarf version. Version zero indicates to LLVM that no DWARF should be
/// emitted.
VALUE_CODEGENOPT(DwarfVersion, 3, 0)
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 4923192..e18b55c 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -82,6 +82,13 @@
FullDebugInfo /// Generate complete debug info.
};
+ enum DebuggerKind {
+ DebuggerKindDefault,
+ DebuggerKindGDB,
+ DebuggerKindLLDB,
+ DebuggerKindSCE
+ };
+
enum TLSModel {
GeneralDynamicTLSModel,
LocalDynamicTLSModel,
@@ -157,6 +164,9 @@
/// A list of dependent libraries.
std::vector<std::string> DependentLibraries;
+ /// A list of linker options to embed in the object file.
+ std::vector<std::string> LinkerOptions;
+
/// Name of the profile file to use as output for -fprofile-instr-generate
/// and -fprofile-generate.
std::string InstrProfileOutput;
@@ -167,6 +177,10 @@
/// Name of the profile file to use as input for -fprofile-instr-use
std::string InstrProfileInput;
+ /// Name of the function summary index file to use for ThinLTO function
+ /// importing.
+ std::string ThinLTOIndexFile;
+
/// The EABI version to use
std::string EABIVersion;
@@ -207,6 +221,9 @@
/// Set of sanitizer checks that trap rather than diagnose.
SanitizerSet SanitizeTrap;
+ /// \brief A list of all -fno-builtin-* function names (e.g., memset).
+ std::vector<std::string> NoBuiltinFuncs;
+
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
@@ -216,6 +233,14 @@
#include "clang/Frontend/CodeGenOptions.def"
CodeGenOptions();
+
+ /// \brief Is this a libc/libm function that is no longer recognized as a
+ /// builtin because a -fno-builtin-* option has been specified?
+ bool isNoBuiltinFunc(const char *Name) const;
+
+ const std::vector<std::string> &getNoBuiltinFuncs() const {
+ return NoBuiltinFuncs;
+ }
};
} // end namespace clang
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 186e8cf..c800a51 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -150,6 +150,8 @@
///< dumps in AST dumps.
unsigned BuildingImplicitModule : 1; ///< Whether we are performing an
///< implicit module build.
+ unsigned ModulesEmbedAllFiles : 1; ///< Whether we should embed all used
+ ///< files into the PCM file.
CodeCompleteOptions CodeCompleteOpts;
@@ -272,7 +274,7 @@
FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
SkipFunctionBodies(false), UseGlobalModuleIndex(true),
GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false),
- BuildingImplicitModule(false),
+ BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None),
ProgramAction(frontend::ParseSyntaxOnly)
{}
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 873af03..9782829 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -44,7 +44,7 @@
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
void HandleImplicitImportDecl(ImportDecl *D) override;
- void HandleLinkerOptionPragma(llvm::StringRef Opts) override;
+ void HandleLinkerOption(llvm::StringRef Opts) override;
void HandleDetectMismatch(llvm::StringRef Name,
llvm::StringRef Value) override;
void HandleDependentLibrary(llvm::StringRef Lib) override;
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index af4e7a1..915dbf7 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -141,7 +141,7 @@
/// \brief The set of macro names that should be ignored for the purposes
/// of computing the module hash.
- llvm::SetVector<std::string> ModulesIgnoreMacros;
+ llvm::SmallSetVector<std::string, 16> ModulesIgnoreMacros;
/// \brief The set of user-provided virtual filesystem overlay files.
std::vector<std::string> VFSOverlayFiles;
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 5210e3f..d568614 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -166,6 +166,7 @@
bool hadError() const { return HadError; }
bool isAscii() const { return Kind == tok::char_constant; }
bool isWide() const { return Kind == tok::wide_char_constant; }
+ bool isUTF8() const { return Kind == tok::utf8_char_constant; }
bool isUTF16() const { return Kind == tok::utf16_char_constant; }
bool isUTF32() const { return Kind == tok::utf32_char_constant; }
bool isMultiChar() const { return IsMultiChar; }
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index f6154b6..5ffa482 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -1185,6 +1185,17 @@
return CachedTokens[CachedLexPos-1].getLastLoc();
}
+ /// \brief Whether \p Tok is the most recent token (`CachedLexPos - 1`) in
+ /// CachedTokens.
+ bool IsPreviousCachedToken(const Token &Tok) const;
+
+ /// \brief Replace token in `CachedLexPos - 1` in CachedTokens by the tokens
+ /// in \p NewToks.
+ ///
+ /// Useful when a token needs to be split in smaller ones and CachedTokens
+ /// most recent token must to be updated to reflect that.
+ void ReplacePreviousCachedToken(ArrayRef<Token> NewToks);
+
/// \brief Replace the last token with an annotation token.
///
/// Like AnnotateCachedTokens(), this routine replaces an
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index 3119736..fdeed44 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -175,7 +175,7 @@
/// macro, other active macros, and anything left on the current physical
/// source line of the expanded buffer. Handle this by returning the
/// first token on the next line.
- void HandleMicrosoftCommentPaste(Token &Tok);
+ void HandleMicrosoftCommentPaste(Token &Tok, SourceLocation OpLoc);
/// \brief If \p loc is a FileID and points inside the current macro
/// definition, returns the appropriate source location pointing at the
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 67a3b7d..00885a5 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -502,6 +502,10 @@
void HandlePragmaAlign();
/// \brief Handle the annotation token produced for
+ /// #pragma clang __debug dump...
+ void HandlePragmaDump();
+
+ /// \brief Handle the annotation token produced for
/// #pragma weak id...
void HandlePragmaWeak();
@@ -1640,13 +1644,22 @@
/// A SmallVector of types.
typedef SmallVector<ParsedType, 12> TypeVector;
- StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr);
+ StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
+ bool AllowOpenMPStandalone = false);
+ enum AllowedContsructsKind {
+ /// \brief Allow any declarations, statements, OpenMP directives.
+ ACK_Any,
+ /// \brief Allow only statements and non-standalone OpenMP directives.
+ ACK_StatementsOpenMPNonStandalone,
+ /// \brief Allow statements and all executable OpenMP directives
+ ACK_StatementsOpenMPAnyExecutable
+ };
StmtResult
- ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+ ParseStatementOrDeclaration(StmtVector &Stmts, AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc = nullptr);
StmtResult ParseStatementOrDeclarationAfterAttributes(
StmtVector &Stmts,
- bool OnlyStatement,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
StmtResult ParseExprStatement();
@@ -1674,7 +1687,8 @@
StmtResult ParseReturnStatement();
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
- StmtResult ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
+ StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
@@ -2337,8 +2351,8 @@
void DiagnoseUnexpectedNamespace(NamedDecl *Context);
- Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
- SourceLocation InlineLoc = SourceLocation());
+ DeclGroupPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
+ SourceLocation InlineLoc = SourceLocation());
void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
std::vector<IdentifierInfo*>& Ident,
std::vector<SourceLocation>& NamespaceLoc,
@@ -2439,11 +2453,13 @@
bool AllowScopeSpecifier);
/// \brief Parses declarative or executable directive.
///
- /// \param StandAloneAllowed true if allowed stand-alone directives,
- /// false - otherwise
+ /// \param Allowed ACK_Any, if any directives are allowed,
+ /// ACK_StatementsOpenMPAnyExecutable - if any executable directives are
+ /// allowed, ACK_StatementsOpenMPNonStandalone - if only non-standalone
+ /// executable directives are allowed.
///
StmtResult
- ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed);
+ ParseOpenMPDeclarativeOrExecutableDirective(AllowedContsructsKind Allowed);
/// \brief Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.
@@ -2478,7 +2494,9 @@
///
/// \param Kind Kind of current clause.
///
- OMPClause *ParseOpenMPVarListClause(OpenMPClauseKind Kind);
+ OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind Kind);
+
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 8be5547..1a53a2c 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -557,8 +557,10 @@
/// Create a new pool for a factory.
AttributePool(AttributeFactory &factory) : Factory(factory), Head(nullptr) {}
+ AttributePool(const AttributePool &) = delete;
+
/// Move the given pool's allocations to this pool.
- AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) {
+ AttributePool(AttributePool &&pool) : Factory(pool.Factory), Head(pool.Head) {
pool.Head = nullptr;
}
@@ -853,7 +855,8 @@
ExpectedStructOrTypedef,
ExpectedObjectiveCInterfaceOrProtocol,
ExpectedKernelFunction,
- ExpectedFunctionWithProtoType
+ ExpectedFunctionWithProtoType,
+ ExpectedVariableFieldOrTypedef
};
} // end namespace clang
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 9c8f2bb..fd50f51 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -31,7 +31,6 @@
#include "clang/Lex/Token.h"
#include "clang/Sema/AttributeList.h"
#include "clang/Sema/Ownership.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
@@ -41,14 +40,10 @@
class CXXRecordDecl;
class TypeLoc;
class LangOptions;
- class DiagnosticsEngine;
class IdentifierInfo;
class NamespaceAliasDecl;
class NamespaceDecl;
- class NestedNameSpecifier;
- class NestedNameSpecifierLoc;
class ObjCDeclSpec;
- class Preprocessor;
class Sema;
class Declarator;
struct TemplateIdAnnotation;
@@ -301,6 +296,7 @@
static const TST TST_decltype_auto = clang::TST_decltype_auto;
static const TST TST_underlyingType = clang::TST_underlyingType;
static const TST TST_auto = clang::TST_auto;
+ static const TST TST_auto_type = clang::TST_auto_type;
static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
static const TST TST_atomic = clang::TST_atomic;
static const TST TST_error = clang::TST_error;
@@ -341,6 +337,7 @@
unsigned TypeAltiVecPixel : 1;
unsigned TypeAltiVecBool : 1;
unsigned TypeSpecOwned : 1;
+ unsigned TypeSpecPipe : 1;
// type-qualifiers
unsigned TypeQualifiers : 4; // Bitwise OR of TQ.
@@ -389,6 +386,7 @@
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc;
+ SourceLocation TQ_pipeLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
@@ -424,6 +422,7 @@
TypeAltiVecPixel(false),
TypeAltiVecBool(false),
TypeSpecOwned(false),
+ TypeSpecPipe(false),
TypeQualifiers(TQ_unspecified),
FS_inline_specified(false),
FS_forceinline_specified(false),
@@ -477,6 +476,7 @@
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
bool isTypeSpecOwned() const { return TypeSpecOwned; }
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
+ bool isTypeSpecPipe() const { return TypeSpecPipe; }
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
@@ -512,7 +512,8 @@
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
bool containsPlaceholderType() const {
- return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto;
+ return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type ||
+ TypeSpecType == TST_decltype_auto);
}
bool hasTagDefinition() const;
@@ -535,6 +536,7 @@
SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
+ SourceLocation getPipeLoc() const { return TQ_pipeLoc; }
/// \brief Clear out all of the type qualifiers.
void ClearTypeQualifiers() {
@@ -543,6 +545,7 @@
TQ_restrictLoc = SourceLocation();
TQ_volatileLoc = SourceLocation();
TQ_atomicLoc = SourceLocation();
+ TQ_pipeLoc = SourceLocation();
}
// function-specifier
@@ -646,6 +649,9 @@
bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy);
+ bool SetTypePipe(bool isPipe, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy);
bool SetTypeSpecError();
void UpdateDeclRep(Decl *Rep) {
assert(isDeclRep((TST) TypeSpecType));
@@ -742,8 +748,7 @@
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
- void Finish(DiagnosticsEngine &D, Preprocessor &PP,
- const PrintingPolicy &Policy);
+ void Finish(Sema &S, const PrintingPolicy &Policy);
const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
return writtenBS;
@@ -795,7 +800,8 @@
DQ_PR_strong = 0x400,
DQ_PR_unsafe_unretained = 0x800,
DQ_PR_nullability = 0x1000,
- DQ_PR_null_resettable = 0x2000
+ DQ_PR_null_resettable = 0x2000,
+ DQ_PR_class = 0x4000
};
ObjCDeclSpec()
@@ -855,7 +861,7 @@
ObjCDeclQualifier objcDeclQualifier : 7;
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
- unsigned PropertyAttributes : 14;
+ unsigned PropertyAttributes : 15;
unsigned Nullability : 2;
@@ -1085,7 +1091,7 @@
/// This is intended to be a small value object.
struct DeclaratorChunk {
enum {
- Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren
+ Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe
} Kind;
/// Loc - The place where this type was defined.
@@ -1413,6 +1419,13 @@
}
};
+ struct PipeTypeInfo : TypeInfoCommon {
+ /// The access writes.
+ unsigned AccessWrites : 3;
+
+ void destroy() {}
+ };
+
union {
TypeInfoCommon Common;
PointerTypeInfo Ptr;
@@ -1421,6 +1434,7 @@
FunctionTypeInfo Fun;
BlockPointerTypeInfo Cls;
MemberPointerTypeInfo Mem;
+ PipeTypeInfo PipeInfo;
};
void destroy() {
@@ -1432,6 +1446,7 @@
case DeclaratorChunk::Array: return Arr.destroy();
case DeclaratorChunk::MemberPointer: return Mem.destroy();
case DeclaratorChunk::Paren: return;
+ case DeclaratorChunk::Pipe: return PipeInfo.destroy();
}
}
@@ -1530,6 +1545,17 @@
return I;
}
+ /// \brief Return a DeclaratorChunk for a block.
+ static DeclaratorChunk getPipe(unsigned TypeQuals,
+ SourceLocation Loc) {
+ DeclaratorChunk I;
+ I.Kind = Pipe;
+ I.Loc = Loc;
+ I.Cls.TypeQuals = TypeQuals;
+ I.Cls.AttrList = 0;
+ return I;
+ }
+
static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS,
unsigned TypeQuals,
SourceLocation Loc) {
@@ -2030,6 +2056,7 @@
case DeclaratorChunk::Array:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return false;
}
llvm_unreachable("Invalid type chunk");
@@ -2265,6 +2292,13 @@
SourceLocation LastLocation;
};
+enum class LambdaCaptureInitKind {
+ NoInit, //!< [a]
+ CopyInit, //!< [a = b], [a = {b}]
+ DirectInit, //!< [a(b)]
+ ListInit //!< [a{b}]
+};
+
/// \brief Represents a complete lambda introducer.
struct LambdaIntroducer {
/// \brief An individual capture in a lambda introducer.
@@ -2273,13 +2307,15 @@
SourceLocation Loc;
IdentifierInfo *Id;
SourceLocation EllipsisLoc;
+ LambdaCaptureInitKind InitKind;
ExprResult Init;
ParsedType InitCaptureType;
LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
IdentifierInfo *Id, SourceLocation EllipsisLoc,
- ExprResult Init, ParsedType InitCaptureType)
- : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init),
- InitCaptureType(InitCaptureType) {}
+ LambdaCaptureInitKind InitKind, ExprResult Init,
+ ParsedType InitCaptureType)
+ : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc),
+ InitKind(InitKind), Init(Init), InitCaptureType(InitCaptureType) {}
};
SourceRange Range;
@@ -2295,10 +2331,11 @@
SourceLocation Loc,
IdentifierInfo* Id,
SourceLocation EllipsisLoc,
+ LambdaCaptureInitKind InitKind,
ExprResult Init,
ParsedType InitCaptureType) {
- Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init,
- InitCaptureType));
+ Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init,
+ InitCaptureType));
}
};
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 74de00f..d4f57b7 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -828,6 +828,9 @@
/// \brief Initializer has a placeholder type which cannot be
/// resolved by initialization.
FK_PlaceholderType,
+ /// \brief Trying to take the address of a function that doesn't support
+ /// having its address taken.
+ FK_AddressOfUnaddressableFunction,
/// \brief List-copy-initialization chose an explicit constructor.
FK_ExplicitConstructor
};
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 1162a1d..7efb19f 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -139,8 +139,7 @@
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
- AllowHidden(Redecl == Sema::ForRedeclaration),
- AllowHiddenInternal(AllowHidden),
+ AllowHidden(false),
Shadowed(false)
{
configure();
@@ -162,8 +161,7 @@
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
- AllowHidden(Redecl == Sema::ForRedeclaration),
- AllowHiddenInternal(AllowHidden),
+ AllowHidden(false),
Shadowed(false)
{
configure();
@@ -184,7 +182,6 @@
HideTags(Other.HideTags),
Diagnose(false),
AllowHidden(Other.AllowHidden),
- AllowHiddenInternal(Other.AllowHiddenInternal),
Shadowed(false)
{}
@@ -226,27 +223,16 @@
/// \brief Specify whether hidden declarations are visible, e.g.,
/// for recovery reasons.
void setAllowHidden(bool AH) {
- AllowHiddenInternal = AllowHidden = AH;
- }
-
- /// \brief Specify whether hidden internal declarations are visible.
- void setAllowHiddenInternal(bool AHI) {
- AllowHiddenInternal = AHI;
+ AllowHidden = AH;
}
/// \brief Determine whether this lookup is permitted to see hidden
/// declarations, such as those in modules that have not yet been imported.
bool isHiddenDeclarationVisible(NamedDecl *ND) const {
- // If a using-shadow declaration is hidden, it's never visible, not
- // even to redeclaration lookup.
- // FIXME: Should this apply to typedefs and namespace aliases too?
- if (isa<UsingShadowDecl>(ND) && LookupKind != Sema::LookupUsingDeclName)
- return false;
- return (AllowHidden &&
- (AllowHiddenInternal || ND->isExternallyVisible())) ||
- LookupKind == Sema::LookupTagName;
+ return AllowHidden ||
+ (isForRedeclaration() && ND->isExternallyVisible());
}
-
+
/// Sets whether tag declarations should be hidden by non-tag
/// declarations during resolution. The default is true.
void setHideTags(bool Hide) {
@@ -317,7 +303,7 @@
if (!D->isInIdentifierNamespace(IDNS))
return nullptr;
- if (isHiddenDeclarationVisible(D) || isVisible(getSema(), D))
+ if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D))
return D;
return getAcceptableDeclSlow(D);
@@ -526,10 +512,10 @@
/// \brief Change this lookup's redeclaration kind.
void setRedeclarationKind(Sema::RedeclarationKind RK) {
Redecl = RK;
- AllowHiddenInternal = AllowHidden = (RK == Sema::ForRedeclaration);
configure();
}
+ void dump();
void print(raw_ostream &);
/// Suppress the diagnostics that would normally fire because of this
@@ -698,9 +684,6 @@
/// \brief True if we should allow hidden declarations to be 'visible'.
bool AllowHidden;
- /// \brief True if we should allow hidden internal declarations to be visible.
- bool AllowHiddenInternal;
-
/// \brief True if the found declarations were shadowed by some other
/// declaration that we skipped. This only happens when \c LookupKind
/// is \c LookupRedeclarationWithLinkage.
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 20958b0..6243795 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -570,8 +570,8 @@
/// This conversion candidate is not viable because its result
/// type is not implicitly convertible to the desired type.
ovl_fail_bad_final_conversion,
-
- /// This conversion function template specialization candidate is not
+
+ /// This conversion function template specialization candidate is not
/// viable because the final conversion was not an exact match.
ovl_fail_final_conversion_not_exact,
@@ -582,7 +582,10 @@
/// This candidate function was not viable because an enable_if
/// attribute disabled it.
- ovl_fail_enable_if
+ ovl_fail_enable_if,
+
+ /// This candidate was not viable because its address could not be taken.
+ ovl_fail_addr_not_available
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index 8acf9e8..dfde374 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -43,13 +43,13 @@
/// compatible with "Type" pointers for example.
template <class PtrTy>
class OpaquePtr {
- void *Ptr;
+ void *Ptr = nullptr;
explicit OpaquePtr(void *Ptr) : Ptr(Ptr) {}
typedef llvm::PointerLikeTypeTraits<PtrTy> Traits;
public:
- OpaquePtr() : Ptr(nullptr) {}
+ OpaquePtr(std::nullptr_t = nullptr) {}
static OpaquePtr make(PtrTy P) { OpaquePtr OP; OP.set(P); return OP; }
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 77801bd..d13667e 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -164,7 +164,7 @@
/// \brief A list of parameters which have the nonnull attribute and are
/// modified in the function.
- llvm::SmallPtrSet<const ParmVarDecl*, 8> ModifiedNonNullParams;
+ llvm::SmallPtrSet<const ParmVarDecl*, 8> ModifiedNonNullParams;
public:
/// Represents a simple identification of a weak object.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index f20d1f5..ebdffc6 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -146,6 +146,7 @@
class ObjCProtocolDecl;
class OMPThreadPrivateDecl;
class OMPClause;
+ struct OverloadCandidate;
class OverloadCandidateSet;
class OverloadExpr;
class ParenListExpr;
@@ -278,10 +279,9 @@
// it will keep having external linkage. If it has internal linkage, we
// will not link it. Since it has no previous decls, it will remain
// with internal linkage.
- if (getLangOpts().ModulesHideInternalLinkage)
- return isVisible(Old) || New->isExternallyVisible();
- return true;
+ return isVisible(Old) || New->isExternallyVisible();
}
+ bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New);
public:
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
@@ -1010,6 +1010,24 @@
bool OldFPContractState : 1;
};
+ /// Records and restores the vtordisp state on entry/exit of C++ method body.
+ class VtorDispStackRAII {
+ public:
+ VtorDispStackRAII(Sema &S, bool ShouldSaveAndRestore)
+ : S(S), ShouldSaveAndRestore(ShouldSaveAndRestore), OldVtorDispStack() {
+ if (ShouldSaveAndRestore)
+ OldVtorDispStack = S.VtorDispModeStack;
+ }
+ ~VtorDispStackRAII() {
+ if (ShouldSaveAndRestore)
+ S.VtorDispModeStack = OldVtorDispStack;
+ }
+ private:
+ Sema &S;
+ bool ShouldSaveAndRestore;
+ SmallVector<MSVtorDispAttr::Mode, 2> OldVtorDispStack;
+ };
+
void addImplicitTypedef(StringRef Name, QualType T);
public:
@@ -1253,6 +1271,8 @@
SourceLocation Loc, DeclarationName Entity);
QualType BuildParenType(QualType T);
QualType BuildAtomicType(QualType T, SourceLocation Loc);
+ QualType BuildPipeType(QualType T,
+ SourceLocation Loc);
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
@@ -1300,9 +1320,7 @@
/// \brief Abstract class used to diagnose incomplete types.
struct TypeDiagnoser {
- bool Suppressed;
-
- TypeDiagnoser(bool Suppressed = false) : Suppressed(Suppressed) { }
+ TypeDiagnoser() {}
virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0;
virtual ~TypeDiagnoser() {}
@@ -1332,17 +1350,17 @@
void emit(const SemaDiagnosticBuilder &DB,
llvm::index_sequence<Is...>) const {
// Apply all tuple elements to the builder in order.
- bool Dummy[] = {(DB << getPrintable(std::get<Is>(Args)))...};
+ bool Dummy[] = {false, (DB << getPrintable(std::get<Is>(Args)))...};
(void)Dummy;
}
public:
BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args)
- : TypeDiagnoser(DiagID == 0), DiagID(DiagID), Args(Args...) {}
+ : TypeDiagnoser(), DiagID(DiagID), Args(Args...) {
+ assert(DiagID != 0 && "no diagnostic for type diagnoser");
+ }
void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
- if (Suppressed)
- return;
const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID);
emit(DB, llvm::index_sequence_for<Ts...>());
DB << T;
@@ -1351,7 +1369,7 @@
private:
bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
- TypeDiagnoser &Diagnoser);
+ TypeDiagnoser *Diagnoser);
VisibleModuleSet VisibleModules;
llvm::SmallVector<VisibleModuleSet, 16> VisibleModulesStack;
@@ -1397,6 +1415,9 @@
SourceLocation Loc, const NamedDecl *D,
ArrayRef<const NamedDecl *> Equiv);
+ bool isCompleteType(SourceLocation Loc, QualType T) {
+ return !RequireCompleteTypeImpl(Loc, T, nullptr);
+ }
bool RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
bool RequireCompleteType(SourceLocation Loc, QualType T,
@@ -1409,6 +1430,7 @@
return RequireCompleteType(Loc, T, Diagnoser);
}
+ void completeExprArrayBound(Expr *E);
bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser);
bool RequireCompleteExprType(Expr *E, unsigned DiagID);
@@ -1465,9 +1487,8 @@
ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS = nullptr,
- bool isClassName = false,
- bool HasTrailingDot = false,
- ParsedType ObjectType = ParsedType(),
+ bool isClassName = false, bool HasTrailingDot = false,
+ ParsedType ObjectType = nullptr,
bool IsCtorOrDtorName = false,
bool WantNontrivialTypeSourceInfo = false,
IdentifierInfo **CorrectedII = nullptr);
@@ -2120,10 +2141,16 @@
SwiftNameAttr *mergeSwiftNameAttr(Decl *D, SourceRange Range,
StringRef Name, bool Override,
unsigned AttrSpellingListIndex);
+ InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex);
+ CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex);
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
- void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
+ void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
+ LookupResult &OldDecls);
bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S,
bool MergeTypeWithOld);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
@@ -2206,7 +2233,8 @@
bool CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
- bool IgnoreBaseAccess);
+ bool IgnoreBaseAccess,
+ bool Diagnose = true);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType);
@@ -2457,6 +2485,14 @@
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
bool MissingImplicitThis = false);
+ /// Returns whether the given function's address can be taken or not,
+ /// optionally emitting a diagnostic if the address can't be taken.
+ ///
+ /// Returns false if taking the address of the function is illegal.
+ bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
+ bool Complain = false,
+ SourceLocation Loc = SourceLocation());
+
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
@@ -2519,7 +2555,8 @@
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
- bool AllowTypoCorrection=true);
+ bool AllowTypoCorrection=true,
+ bool CalleesAddressIsTaken=false);
bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
MultiExprArg Args, SourceLocation RParenLoc,
@@ -2527,12 +2564,12 @@
ExprResult *Result);
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
- unsigned Opc,
+ UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *input);
ExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
- unsigned Opc,
+ BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS);
@@ -3037,11 +3074,9 @@
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
- const bool isAssign,
const bool isReadWrite,
- const unsigned Attributes,
+ unsigned &Attributes,
const unsigned AttributesAsWritten,
- bool *isOverridingProperty,
QualType T,
TypeSourceInfo *TSI,
tok::ObjCKeywordKind MethodImplKind);
@@ -3055,7 +3090,6 @@
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
- const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -3397,7 +3431,6 @@
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset, SourceLocation AsmLoc);
ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member,
- unsigned &Offset,
llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc);
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
@@ -3494,6 +3527,11 @@
void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
SourceLocation OpLoc);
+ /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a
+ /// _Nonnull one.
+ void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
+ SourceLocation Loc);
+
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
return DelayedDiagnostics.push(pool);
}
@@ -4073,7 +4111,8 @@
SourceLocation IdentLoc,
IdentifierInfo *Ident,
SourceLocation LBrace,
- AttributeList *AttrList);
+ AttributeList *AttrList,
+ UsingDirectiveDecl * &UsingDecl);
void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace);
NamespaceDecl *getStdNamespace() const;
@@ -4670,6 +4709,10 @@
ExprResult ActOnCXXDelete(SourceLocation StartLoc,
bool UseGlobal, bool ArrayForm,
Expr *Operand);
+ void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
+ bool IsDelete, bool CallCanBeVirtual,
+ bool WarnOnNonAbstractTypes,
+ SourceLocation DtorLoc);
DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D);
ExprResult CheckConditionVariable(VarDecl *ConditionVar,
@@ -4979,15 +5022,25 @@
/// \brief Perform initialization analysis of the init-capture and perform
/// any implicit conversions such as an lvalue-to-rvalue conversion if
/// not being used to initialize a reference.
- QualType performLambdaInitCaptureInitialization(SourceLocation Loc,
- bool ByRef, IdentifierInfo *Id, Expr *&Init);
+ ParsedType actOnLambdaInitCaptureInitialization(
+ SourceLocation Loc, bool ByRef, IdentifierInfo *Id,
+ LambdaCaptureInitKind InitKind, Expr *&Init) {
+ return ParsedType::make(buildLambdaInitCaptureInitialization(
+ Loc, ByRef, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init));
+ }
+ QualType buildLambdaInitCaptureInitialization(SourceLocation Loc, bool ByRef,
+ IdentifierInfo *Id,
+ bool DirectInit, Expr *&Init);
+
/// \brief Create a dummy variable within the declcontext of the lambda's
/// call operator, for name lookup purposes for a lambda init capture.
///
/// CodeGen handles emission of lambda captures, ignoring these dummy
/// variables appropriately.
- VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
- QualType InitCaptureType, IdentifierInfo *Id, Expr *Init);
+ VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
+ QualType InitCaptureType,
+ IdentifierInfo *Id,
+ unsigned InitStyle, Expr *Init);
/// \brief Build the implicit field for an init-capture.
FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
@@ -5052,8 +5105,7 @@
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
- Expr **Strings,
- unsigned NumStrings);
+ ArrayRef<Expr *> Strings);
ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S);
@@ -5078,8 +5130,7 @@
ObjCMethodDecl *setterMethod);
ExprResult BuildObjCDictionaryLiteral(SourceRange SR,
- ObjCDictionaryElement *Elements,
- unsigned NumElements);
+ MutableArrayRef<ObjCDictionaryElement> Elements);
ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc,
TypeSourceInfo *EncodedTypeInfo,
@@ -5332,13 +5383,14 @@
SourceLocation BaseLoc,
SourceLocation EllipsisLoc);
- bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
- unsigned NumBases);
- void ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
- unsigned NumBases);
+ bool AttachBaseSpecifiers(CXXRecordDecl *Class,
+ MutableArrayRef<CXXBaseSpecifier *> Bases);
+ void ActOnBaseSpecifiers(Decl *ClassDecl,
+ MutableArrayRef<CXXBaseSpecifier *> Bases);
- bool IsDerivedFrom(QualType Derived, QualType Base);
- bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
+ bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base);
+ bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base,
+ CXXBasePaths &Paths);
// FIXME: I don't like this name.
void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath);
@@ -5352,7 +5404,8 @@
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name,
- CXXCastPath *BasePath);
+ CXXCastPath *BasePath,
+ bool IgnoreAccess = false);
std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
@@ -5467,6 +5520,7 @@
AbstractArrayType
};
+ bool isAbstractType(SourceLocation Loc, QualType T);
bool RequireNonAbstractType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
template <typename... Ts>
@@ -5478,9 +5532,6 @@
void DiagnoseAbstractType(const CXXRecordDecl *RD);
- bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
- AbstractDiagSelID SelID = AbstractNone);
-
//===--------------------------------------------------------------------===//
// C++ Overloaded Operators [C++ 13.5]
//
@@ -5551,7 +5602,7 @@
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ ArrayRef<Decl *> Params,
SourceLocation RAngleLoc);
/// \brief The context in which we are checking a template parameter list.
@@ -6270,6 +6321,9 @@
/// \brief Substitution of the deduced template argument values
/// resulted in an error.
TDK_SubstitutionFailure,
+ /// \brief After substituting deduced template arguments, a dependent
+ /// parameter type did not match the corresponding argument.
+ TDK_DeducedMismatch,
/// \brief A non-depnedent component of the parameter did not match the
/// corresponding component of the argument.
TDK_NonDeducedMismatch,
@@ -6379,6 +6433,11 @@
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
+ QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
+ QualType Type, TypeSourceInfo *TSI,
+ SourceRange Range, bool DirectInit,
+ Expr *Init);
+
TypeLoc getReturnTypeLoc(FunctionDecl *FD) const;
bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
@@ -6961,8 +7020,6 @@
///
/// \param Exprs The list of expressions to substitute into.
///
- /// \param NumExprs The number of expressions in \p Exprs.
- ///
/// \param IsCall Whether this is some form of call, in which case
/// default arguments will be dropped.
///
@@ -6971,7 +7028,7 @@
/// \param Outputs Will receive all of the substituted arguments.
///
/// \returns true if an error occurred, false otherwise.
- bool SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
+ bool SubstExprs(ArrayRef<Expr *> Exprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<Expr *> &Outputs);
@@ -7297,7 +7354,6 @@
SourceLocation LParenLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
Selector GetterSel, Selector SetterSel,
- bool *OverridingProperty,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC = nullptr);
@@ -7307,7 +7363,8 @@
bool ImplKind,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar,
- SourceLocation PropertyIvarLoc);
+ SourceLocation PropertyIvarLoc,
+ ObjCPropertyQueryKind QueryKind);
enum ObjCSpecialMethodKind {
OSMK_None,
@@ -7475,14 +7532,15 @@
ObjCMethodDecl *&ClassMethod,
ObjCMethodDecl *&InstanceMethod,
TypedefNameDecl *&TDNDecl,
- bool CfToNs);
-
+ bool CfToNs, bool Diagnose = true);
+
bool CheckObjCBridgeRelatedConversions(SourceLocation Loc,
QualType DestType, QualType SrcType,
- Expr *&SrcExpr);
-
- bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr);
-
+ Expr *&SrcExpr, bool Diagnose = true);
+
+ bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr,
+ bool Diagnose = true);
+
bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
/// \brief Check whether the given new method is a valid override of the
@@ -7596,6 +7654,9 @@
void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
StringLiteral *SegmentName);
+ /// \brief Called on #pragma clang __debug dump II
+ void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II);
+
/// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
@@ -7718,7 +7779,7 @@
ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E);
StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E);
- void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body);
+ void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body);
//===--------------------------------------------------------------------===//
// OpenMP directives and clauses.
@@ -7728,9 +7789,17 @@
/// \brief Initialization of data-sharing attributes stack.
void InitDataSharingAttributesStack();
void DestroyDataSharingAttributesStack();
- ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
- OpenMPClauseKind CKind);
+ ExprResult
+ VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind,
+ bool StrictlyPositive = true);
+
public:
+ /// \brief Return true if the provided declaration \a VD should be captured by
+ /// reference in the provided scope \a RSI. This will take into account the
+ /// semantics of the directive and associated clauses.
+ bool IsOpenMPCapturedByRef(VarDecl *VD,
+ const sema::CapturedRegionScopeInfo *RSI);
+
/// \brief Check if the specified variable is used in one of the private
/// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP
/// constructs.
@@ -7838,6 +7907,7 @@
/// \brief Called on well-formed '\#pragma omp critical' after parsing of the
/// associated statement.
StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName,
+ ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed '\#pragma omp parallel for' after parsing
@@ -7914,6 +7984,24 @@
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion);
+ /// \brief Called on well-formed '\#pragma omp taskloop' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
+ /// \brief Called on well-formed '\#pragma omp taskloop simd' after parsing of
+ /// the associated statement.
+ StmtResult ActOnOpenMPTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
+ /// \brief Called on well-formed '\#pragma omp distribute' after parsing
+ /// of the associated statement.
+ StmtResult ActOnOpenMPDistributeDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA);
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
@@ -7955,6 +8043,18 @@
ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc,
SourceLocation LParenLoc = SourceLocation(),
Expr *NumForLoops = nullptr);
+ /// \brief Called on well-formed 'grainsize' clause.
+ OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'num_tasks' clause.
+ OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'hint' clause.
+ OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
unsigned Argument,
@@ -7975,20 +8075,17 @@
SourceLocation LParenLoc,
SourceLocation EndLoc);
- OMPClause *ActOnOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
- unsigned Argument, Expr *Expr,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation ArgumentLoc,
- SourceLocation DelimLoc,
- SourceLocation EndLoc);
+ OMPClause *ActOnOpenMPSingleExprWithArgClause(
+ OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ ArrayRef<SourceLocation> ArgumentsLoc, SourceLocation DelimLoc,
+ SourceLocation EndLoc);
/// \brief Called on well-formed 'schedule' clause.
- OMPClause *ActOnOpenMPScheduleClause(OpenMPScheduleClauseKind Kind,
- Expr *ChunkSize, SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation KindLoc,
- SourceLocation CommaLoc,
- SourceLocation EndLoc);
+ OMPClause *ActOnOpenMPScheduleClause(
+ OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
+ OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc,
+ SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc);
OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc,
SourceLocation EndLoc);
@@ -8022,6 +8119,9 @@
/// \brief Called on well-formed 'simd' clause.
OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'nogroup' clause.
+ OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc,
+ SourceLocation EndLoc);
OMPClause *ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *TailExpr,
@@ -8029,7 +8129,8 @@
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
- OpenMPLinearClauseKind LinKind, SourceLocation DepLinLoc);
+ OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc);
/// \brief Called on well-formed 'private' clause.
OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
@@ -8095,7 +8196,30 @@
OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
-
+ /// \brief Called on well-formed 'map' clause.
+ OMPClause *ActOnOpenMPMapClause(
+ OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType,
+ SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc);
+ /// \brief Called on well-formed 'num_teams' clause.
+ OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'thread_limit' clause.
+ OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'priority' clause.
+ OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'dist_schedule' clause.
+ OMPClause *ActOnOpenMPDistScheduleClause(
+ OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc,
+ SourceLocation CommaLoc, SourceLocation EndLoc);
+
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
/// \brief An implicit conversion.
@@ -8136,12 +8260,13 @@
// DefaultFunctionArrayConversion - converts functions and arrays
// to their respective pointers (C99 6.3.2.1).
- ExprResult DefaultFunctionArrayConversion(Expr *E);
+ ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true);
// DefaultFunctionArrayLvalueConversion - converts functions and
// arrays to their respective pointers and performs the
// lvalue-to-rvalue conversion.
- ExprResult DefaultFunctionArrayLvalueConversion(Expr *E);
+ ExprResult DefaultFunctionArrayLvalueConversion(Expr *E,
+ bool Diagnose = true);
// DefaultLvalueConversion - performs lvalue-to-rvalue conversion on
// the operand. This is DefaultFunctionArrayLvalueConversion,
@@ -8369,22 +8494,23 @@
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
bool IsCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
- QualType* CompLHSTy = nullptr);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr);
QualType CheckSubtractionOperands( // C99 6.5.6
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
QualType* CompLHSTy = nullptr);
QualType CheckShiftOperands( // C99 6.5.7
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
- bool IsCompAssign = false);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc, bool IsCompAssign = false);
QualType CheckCompareOperands( // C99 6.5.8/9
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned OpaqueOpc,
- bool isRelational);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc, bool isRelational);
QualType CheckBitwiseOperands( // C99 6.5.[10...12]
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
bool IsCompAssign = false);
QualType CheckLogicalOperands( // C99 6.5.[13,14]
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc);
// CheckAssignmentOperands is used for both simple and compound assignment.
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
@@ -8493,6 +8619,10 @@
bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
CastKind &Kind);
+ /// \brief Prepare `SplattedExpr` for a vector splat operation, adding
+ /// implicit casts if necessary.
+ ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr);
+
// CheckExtVectorCast - check type constraints for extended vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size,
@@ -8513,6 +8643,7 @@
ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
QualType castType, Expr *&op,
CheckedConversionKind CCK,
+ bool Diagnose = true,
bool DiagnoseCFAudited = false,
BinaryOperatorKind Opc = BO_PtrMemD
);
@@ -8805,8 +8936,8 @@
DeclGroupPtrTy IterationVar);
void CodeCompleteObjCSelector(Scope *S,
ArrayRef<IdentifierInfo *> SelIdents);
- void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
- unsigned NumProtocols);
+ void CodeCompleteObjCProtocolReferences(
+ ArrayRef<IdentifierLocPair> Protocols);
void CodeCompleteObjCProtocolDecl(Scope *S);
void CodeCompleteObjCInterfaceDecl(Scope *S);
void CodeCompleteObjCSuperclass(Scope *S,
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 229eb71..c22c703 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -140,6 +140,9 @@
/// TDK_SubstitutionFailure: this argument is the template
/// argument we were instantiating when we encountered an error.
///
+ /// TDK_DeducedMismatch: this is the parameter type, after substituting
+ /// deduced arguments.
+ ///
/// TDK_NonDeducedMismatch: this is the component of the 'parameter'
/// of the deduction, directly provided in the source code.
TemplateArgument FirstArg;
@@ -147,18 +150,32 @@
/// \brief The second template argument to which the template
/// argument deduction failure refers.
///
+ /// TDK_Inconsistent: this argument is the second value deduced
+ /// for the corresponding template parameter.
+ ///
+ /// TDK_DeducedMismatch: this is the (adjusted) call argument type.
+ ///
/// TDK_NonDeducedMismatch: this is the mismatching component of the
/// 'argument' of the deduction, from which we are deducing arguments.
///
/// FIXME: Finish documenting this.
TemplateArgument SecondArg;
- /// \brief The expression which caused a deduction failure.
- ///
- /// TDK_FailedOverloadResolution: this argument is the reference to
- /// an overloaded function which could not be resolved to a specific
- /// function.
- Expr *Expression;
+ union {
+ /// \brief The expression which caused a deduction failure.
+ ///
+ /// TDK_FailedOverloadResolution: this argument is the reference to
+ /// an overloaded function which could not be resolved to a specific
+ /// function.
+ Expr *Expression;
+
+ /// \brief The index of the function argument that caused a deduction
+ /// failure.
+ ///
+ /// TDK_DeducedMismatch: this is the index of the argument that had a
+ /// different argument type from its substituted parameter type.
+ unsigned CallArgIndex;
+ };
/// \brief Information on packs that we're currently expanding.
///
@@ -211,6 +228,10 @@
/// if any.
Expr *getExpr();
+ /// \brief Return the index of the call argument that this deduction
+ /// failure refers to, if any.
+ llvm::Optional<unsigned> getCallArgIndex();
+
/// \brief Free any memory associated with this deduction failure.
void Destroy();
};
@@ -236,7 +257,7 @@
}
/// Diagnose a template argument deduction failure.
- void NoteDeductionFailure(Sema &S);
+ void NoteDeductionFailure(Sema &S, bool ForTakingAddress);
};
/// TemplateSpecCandidateSet - A set of generalized overload candidates,
@@ -246,6 +267,10 @@
class TemplateSpecCandidateSet {
SmallVector<TemplateSpecCandidate, 16> Candidates;
SourceLocation Loc;
+ // Stores whether we're taking the address of these candidates. This helps us
+ // produce better error messages when dealing with the pass_object_size
+ // attribute on parameters.
+ bool ForTakingAddress;
TemplateSpecCandidateSet(
const TemplateSpecCandidateSet &) = delete;
@@ -254,7 +279,8 @@
void destroyCandidates();
public:
- TemplateSpecCandidateSet(SourceLocation Loc) : Loc(Loc) {}
+ TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false)
+ : Loc(Loc), ForTakingAddress(ForTakingAddress) {}
~TemplateSpecCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 958aab0..3b0385e 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -72,15 +72,15 @@
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
- IdentifierInfo* getCorrectionAsIdentifierInfo() const {
+ IdentifierInfo *getCorrectionAsIdentifierInfo() const {
return CorrectionName.getAsIdentifierInfo();
}
/// \brief Gets the NestedNameSpecifier needed to use the typo correction
- NestedNameSpecifier* getCorrectionSpecifier() const {
+ NestedNameSpecifier *getCorrectionSpecifier() const {
return CorrectionNameSpec;
}
- void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
+ void setCorrectionSpecifier(NestedNameSpecifier *NNS) {
CorrectionNameSpec = NNS;
ForceSpecifierReplacement = (NNS != nullptr);
}
@@ -129,9 +129,16 @@
return Normalized ? NormalizeEditDistance(ED) : ED;
}
+ /// \brief Get the correction declaration found by name lookup (before we
+ /// looked through using shadow declarations and the like).
+ NamedDecl *getFoundDecl() const {
+ return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
+ }
+
/// \brief Gets the pointer to the declaration of the typo correction
NamedDecl *getCorrectionDecl() const {
- return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
+ auto *D = getFoundDecl();
+ return D ? D->getUnderlyingDecl() : nullptr;
}
template <class DeclClass>
DeclClass *getCorrectionDeclAs() const {
@@ -180,8 +187,7 @@
// Check if this TypoCorrection is a keyword by checking if the first
// item in CorrectionDecls is NULL.
bool isKeyword() const {
- return !CorrectionDecls.empty() &&
- CorrectionDecls.front() == nullptr;
+ return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr;
}
// Check if this TypoCorrection is the given keyword.
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index a37bafd..910c577 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -907,7 +907,9 @@
/// \brief A DecayedType record.
TYPE_DECAYED = 41,
/// \brief An AdjustedType record.
- TYPE_ADJUSTED = 42
+ TYPE_ADJUSTED = 42,
+ /// \brief A PipeType record.
+ TYPE_PIPE = 43
};
/// \brief The type IDs for special types constructed by semantic
@@ -985,13 +987,19 @@
/// \brief The internal '__make_integer_seq' template.
PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 13,
+
+ /// \brief The internal '__NSConstantString' typedef.
+ PREDEF_DECL_CF_CONSTANT_STRING_ID = 14,
+
+ /// \brief The internal '__NSConstantString' tag type.
+ PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 15,
};
/// \brief The number of declaration IDs that are predefined.
///
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
- const unsigned int NUM_PREDEF_DECL_IDS = 14;
+ const unsigned int NUM_PREDEF_DECL_IDS = 16;
/// \brief Record code for a list of local redeclarations of a declaration.
const unsigned int LOCAL_REDECLARATIONS = 50;
@@ -1413,6 +1421,7 @@
// Microsoft
EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr
+ EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr
EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr).
EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type).
STMT_SEH_LEAVE, // SEHLeaveStmt
@@ -1446,6 +1455,9 @@
STMT_OMP_TASKGROUP_DIRECTIVE,
STMT_OMP_CANCELLATION_POINT_DIRECTIVE,
STMT_OMP_CANCEL_DIRECTIVE,
+ STMT_OMP_TASKLOOP_DIRECTIVE,
+ STMT_OMP_TASKLOOP_SIMD_DIRECTIVE,
+ STMT_OMP_DISTRIBUTE_DIRECTIVE,
EXPR_OMP_ARRAY_SECTION,
// ARC
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index eb61380..588a6a9 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -1058,6 +1058,7 @@
off_t StoredSize;
time_t StoredTime;
bool Overridden;
+ bool Transient;
};
/// \brief Reads the stored information about an input file.
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index ed34547..ef8c653 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -871,6 +871,7 @@
const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
+ void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 3fdb33f..d6d16a0 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H
#define LLVM_CLANG_SERIALIZATION_MODULE_H
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
@@ -32,7 +33,6 @@
namespace clang {
-class FileEntry;
class DeclContext;
class Module;
diff --git a/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
new file mode 100644
index 0000000..28cfbef
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -0,0 +1,233 @@
+//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SValExplainer, a class for pretty-printing a
+// human-readable description of a symbolic value. For example,
+// "reg_$0<x>" is turned into "initial value of variable 'x'".
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+
+namespace clang {
+
+namespace ento {
+
+class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
+private:
+ ASTContext &ACtx;
+
+ std::string printStmt(const Stmt *S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
+ return OS.str();
+ }
+
+ bool isThisObject(const SymbolicRegion *R) {
+ if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
+ if (isa<CXXThisRegion>(S->getRegion()))
+ return true;
+ return false;
+ }
+
+public:
+ SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
+
+ std::string VisitUnknownVal(UnknownVal V) {
+ return "unknown value";
+ }
+
+ std::string VisitUndefinedVal(UndefinedVal V) {
+ return "undefined value";
+ }
+
+ std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
+ const MemRegion *R = V.getRegion();
+ // Avoid the weird "pointer to pointee of ...".
+ if (auto SR = dyn_cast<SymbolicRegion>(R)) {
+ // However, "pointer to 'this' object" is fine.
+ if (!isThisObject(SR))
+ return Visit(SR->getSymbol());
+ }
+ return "pointer to " + Visit(R);
+ }
+
+ std::string VisitLocConcreteInt(loc::ConcreteInt V) {
+ llvm::APSInt I = V.getValue();
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "concrete memory address '" << I << "'";
+ return OS.str();
+ }
+
+ std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ return Visit(V.getSymbol());
+ }
+
+ std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
+ llvm::APSInt I = V.getValue();
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
+ << "-bit integer '" << I << "'";
+ return OS.str();
+ }
+
+ std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
+ return "lazily frozen compound value of " + Visit(V.getRegion());
+ }
+
+ std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
+ const MemRegion *R = S->getRegion();
+ // Special handling for argument values.
+ if (auto V = dyn_cast<VarRegion>(R))
+ if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
+ return "argument '" + D->getQualifiedNameAsString() + "'";
+ return "initial value of " + Visit(R);
+ }
+
+ std::string VisitSymbolConjured(const SymbolConjured *S) {
+ return "symbol of type '" + S->getType().getAsString() +
+ "' conjured at statement '" + printStmt(S->getStmt()) + "'";
+ }
+
+ std::string VisitSymbolDerived(const SymbolDerived *S) {
+ return "value derived from (" + Visit(S->getParentSymbol()) +
+ ") for " + Visit(S->getRegion());
+ }
+
+ std::string VisitSymbolExtent(const SymbolExtent *S) {
+ return "extent of " + Visit(S->getRegion());
+ }
+
+ std::string VisitSymbolMetadata(const SymbolMetadata *S) {
+ return "metadata of type '" + S->getType().getAsString() + "' tied to " +
+ Visit(S->getRegion());
+ }
+
+ std::string VisitSymIntExpr(const SymIntExpr *S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "(" << Visit(S->getLHS()) << ") "
+ << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
+ << S->getRHS();
+ return OS.str();
+ }
+
+ // TODO: IntSymExpr doesn't appear in practice.
+ // Add the relevant code once it does.
+
+ std::string VisitSymSymExpr(const SymSymExpr *S) {
+ return "(" + Visit(S->getLHS()) + ") " +
+ std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
+ " (" + Visit(S->getRHS()) + ")";
+ }
+
+ // TODO: SymbolCast doesn't appear in practice.
+ // Add the relevant code once it does.
+
+ std::string VisitSymbolicRegion(const SymbolicRegion *R) {
+ // Explain 'this' object here.
+ // TODO: Explain CXXThisRegion itself, find a way to test it.
+ if (isThisObject(R))
+ return "'this' object";
+ return "pointee of " + Visit(R->getSymbol());
+ }
+
+ std::string VisitAllocaRegion(const AllocaRegion *R) {
+ return "region allocated by '" + printStmt(R->getExpr()) + "'";
+ }
+
+ std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
+ return "compound literal " + printStmt(R->getLiteralExpr());
+ }
+
+ std::string VisitStringRegion(const StringRegion *R) {
+ return "string literal " + R->getString();
+ }
+
+ std::string VisitElementRegion(const ElementRegion *R) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "element of type '" << R->getElementType().getAsString()
+ << "' with index ";
+ // For concrete index: omit type of the index integer.
+ if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
+ OS << I->getValue();
+ else
+ OS << "'" << Visit(R->getIndex()) << "'";
+ OS << " of " + Visit(R->getSuperRegion());
+ return OS.str();
+ }
+
+ std::string VisitVarRegion(const VarRegion *R) {
+ const VarDecl *VD = R->getDecl();
+ std::string Name = VD->getQualifiedNameAsString();
+ if (isa<ParmVarDecl>(VD))
+ return "parameter '" + Name + "'";
+ else if (VD->hasLocalStorage())
+ return "local variable '" + Name + "'";
+ else if (VD->isStaticLocal())
+ return "static local variable '" + Name + "'";
+ else if (VD->hasGlobalStorage())
+ return "global variable '" + Name + "'";
+ else
+ llvm_unreachable("A variable is either local or global");
+ }
+
+ std::string VisitFieldRegion(const FieldRegion *R) {
+ return "field '" + R->getDecl()->getNameAsString() + "' of " +
+ Visit(R->getSuperRegion());
+ }
+
+ std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
+ return "temporary object constructed at statement '" +
+ printStmt(R->getExpr()) + "'";
+ }
+
+ std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
+ return "base object '" + R->getDecl()->getQualifiedNameAsString() +
+ "' inside " + Visit(R->getSuperRegion());
+ }
+
+ std::string VisitSVal(SVal V) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << V;
+ return "a value unsupported by the explainer: (" +
+ std::string(OS.str()) + ")";
+ }
+
+ std::string VisitSymExpr(SymbolRef S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ S->dumpToStream(OS);
+ return "a symbolic expression unsupported by the explainer: (" +
+ std::string(OS.str()) + ")";
+ }
+
+ std::string VisitMemRegion(const MemRegion *R) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << R;
+ return "a memory region unsupported by the explainer (" +
+ std::string(OS.str()) + ")";
+ }
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 197d27a..c954bbf 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/FoldingSet.h"
namespace clang {
+class CFGBlock;
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/IssueHash.h b/include/clang/StaticAnalyzer/Core/IssueHash.h
index 913ab79..b3c4f14 100644
--- a/include/clang/StaticAnalyzer/Core/IssueHash.h
+++ b/include/clang/StaticAnalyzer/Core/IssueHash.h
@@ -15,6 +15,7 @@
class Decl;
class SourceManager;
class FullSourceLoc;
+class LangOptions;
/// \brief Get an MD5 hash to help identify bugs.
///
@@ -37,13 +38,14 @@
llvm::SmallString<32> GetIssueHash(const SourceManager &SM,
FullSourceLoc &IssueLoc,
llvm::StringRef CheckerName,
- llvm::StringRef BugType, const Decl *D);
+ llvm::StringRef BugType, const Decl *D,
+ const LangOptions &LangOpts);
/// \brief Get the string representation of issue hash. See GetIssueHash() for
/// more information.
std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc,
llvm::StringRef CheckerName, llvm::StringRef BugType,
- const Decl *D);
+ const Decl *D, const LangOptions &LangOpts);
} // namespace clang
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 77d73cf..55fd4b8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -49,6 +49,27 @@
class CallEvent;
class CallEventManager;
+/// This class represents a description of a function call using the number of
+/// arguments and the name of the function.
+class CallDescription {
+ friend CallEvent;
+ mutable IdentifierInfo *II;
+ StringRef FuncName;
+ unsigned RequiredArgs;
+
+public:
+ const static unsigned NoArgRequirement = ~0;
+ /// \brief Constructs a CallDescription object.
+ ///
+ /// @param FuncName The name of the function that will be matched.
+ ///
+ /// @param RequiredArgs The number of arguments that is expected to match a
+ /// call. Omit this parameter to match every occurance of call with a given
+ /// name regardless the number of arguments.
+ CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
+ : II(nullptr), FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+};
+
template<typename T = CallEvent>
class CallEventRef : public IntrusiveRefCntPtr<const T> {
public:
@@ -227,6 +248,13 @@
return false;
}
+ /// \brief Returns true if the CallEvent is a call to a function that matches
+ /// the CallDescription.
+ ///
+ /// Note that this function is not intended to be used to match Obj-C method
+ /// calls.
+ bool isCalled(const CallDescription &CD) const;
+
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
@@ -506,8 +534,55 @@
return BR->getDecl();
}
+ bool isConversionFromLambda() const {
+ const BlockDecl *BD = getDecl();
+ if (!BD)
+ return false;
+
+ return BD->isConversionFromLambda();
+ }
+
+ /// \brief For a block converted from a C++ lambda, returns the block
+ /// VarRegion for the variable holding the captured C++ lambda record.
+ const VarRegion *getRegionStoringCapturedLambda() const {
+ assert(isConversionFromLambda());
+ const BlockDataRegion *BR = getBlockRegion();
+ assert(BR && "Block converted from lambda must have a block region");
+
+ auto I = BR->referenced_vars_begin();
+ assert(I != BR->referenced_vars_end());
+
+ return I.getCapturedRegion();
+ }
+
RuntimeDefinition getRuntimeDefinition() const override {
- return RuntimeDefinition(getDecl());
+ if (!isConversionFromLambda())
+ return RuntimeDefinition(getDecl());
+
+ // Clang converts lambdas to blocks with an implicit user-defined
+ // conversion operator method on the lambda record that looks (roughly)
+ // like:
+ //
+ // typedef R(^block_type)(P1, P2, ...);
+ // operator block_type() const {
+ // auto Lambda = *this;
+ // return ^(P1 p1, P2 p2, ...){
+ // /* return Lambda(p1, p2, ...); */
+ // };
+ // }
+ //
+ // Here R is the return type of the lambda and P1, P2, ... are
+ // its parameter types. 'Lambda' is a fake VarDecl captured by the block
+ // that is initialized to a copy of the lambda.
+ //
+ // Sema leaves the body of a lambda-converted block empty (it is
+ // produced by CodeGen), so we can't analyze it directly. Instead, we skip
+ // the block body and analyze the operator() method on the captured lambda.
+ const VarDecl *LambdaVD = getRegionStoringCapturedLambda()->getDecl();
+ const CXXRecordDecl *LambdaDecl = LambdaVD->getType()->getAsCXXRecordDecl();
+ CXXMethodDecl* LambdaCallOperator = LambdaDecl->getLambdaCallOperator();
+
+ return RuntimeDefinition(LambdaCallOperator);
}
bool argumentsMayEscape() const override {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index f777cd7..e380982 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -263,6 +263,10 @@
Eng.getBugReporter().emitReport(std::move(R));
}
+ /// \brief Returns the word that should be used to refer to the declaration
+ /// in the report.
+ StringRef getDeclDescription(const Decl *D);
+
/// \brief Get the declaration of the called function (path-sensitive).
const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
@@ -316,7 +320,7 @@
// The analyzer may stop exploring if it sees a state it has previously
// visited ("cache out"). The early return here is a defensive check to
// prevent accidental caching out by checker API clients. Unless there is a
- // tag or the the client checker has requested that the generated node be
+ // tag or the client checker has requested that the generated node be
// marked as a sink, we assume that a client requesting a transition to a
// state that is the same as the predecessor state has made a mistake. We
// return the predecessor rather than cache out.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index cc3779d..a66e1a1 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -26,6 +26,7 @@
class EnvironmentManager;
class SValBuilder;
+class SymbolReaper;
/// An entry in the environment consists of a Stmt and an LocationContext.
/// This allows the environment to manage context-sensitive bindings,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 8337f77..99083c9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -604,6 +604,28 @@
const LocationContext *LC,
const Expr *E,
const Expr *ResultE = nullptr);
+
+ /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
+ /// block to find the constructor expression that directly constructed into
+ /// the storage for this statement. Returns null if the constructor for this
+ /// statement created a temporary object region rather than directly
+ /// constructing into an existing region.
+ const CXXConstructExpr *findDirectConstructorForCurrentCFGElement();
+
+ /// For a CXXConstructExpr, walk forward in the current CFG block to find the
+ /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is
+ /// directly constructed by this constructor. Returns None if the current
+ /// constructor expression did not directly construct into an existing
+ /// region.
+ Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor();
+
+ /// For a given constructor, look forward in the current CFG block to
+ /// determine the region into which an object will be constructed by \p CE.
+ /// Returns either a field or local variable region if the object will be
+ /// directly constructed in an existing region or a temporary object region
+ /// if not.
+ const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE,
+ ExplodedNode *Pred);
};
/// Traits for storing the call processing policy inside GDM.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index faa3500..ce81c98 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
+#include "clang/AST/Decl.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -22,7 +23,6 @@
#include <deque>
namespace clang {
-class Decl;
namespace ento {
typedef std::deque<Decl*> SetOfDecls;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
index aac600c..3168733 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -1,4 +1,4 @@
-//===--- LoopWidening.h - Instruction class definition ----------*- C++ -*-===//
+//===--- LoopWidening.h - Widen loops ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -28,8 +28,7 @@
/// by the loop body in any iteration.
ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
const LocationContext *LCtx,
- unsigned BlockCount,
- const Stmt *LoopStmt);
+ unsigned BlockCount, const Stmt *LoopStmt);
} // end namespace ento
} // end namespace clang
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 77841ce..41935ae 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -19,7 +19,9 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
@@ -75,51 +77,13 @@
/// MemRegion - The root abstract class for all memory regions.
class MemRegion : public llvm::FoldingSetNode {
- friend class MemRegionManager;
public:
enum Kind {
- // Memory spaces.
- GenericMemSpaceRegionKind,
- StackLocalsSpaceRegionKind,
- StackArgumentsSpaceRegionKind,
- HeapSpaceRegionKind,
- UnknownSpaceRegionKind,
- StaticGlobalSpaceRegionKind,
- GlobalInternalSpaceRegionKind,
- GlobalSystemSpaceRegionKind,
- GlobalImmutableSpaceRegionKind,
- BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
- END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
- END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEG_MEMSPACES = GenericMemSpaceRegionKind,
- END_MEMSPACES = GlobalImmutableSpaceRegionKind,
- // Untyped regions.
- SymbolicRegionKind,
- AllocaRegionKind,
- // Typed regions.
- BEG_TYPED_REGIONS,
- FunctionTextRegionKind = BEG_TYPED_REGIONS,
- BlockTextRegionKind,
- BlockDataRegionKind,
- BEG_TYPED_VALUE_REGIONS,
- CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
- CXXThisRegionKind,
- StringRegionKind,
- ObjCStringRegionKind,
- ElementRegionKind,
- // Decl Regions.
- BEG_DECL_REGIONS,
- VarRegionKind = BEG_DECL_REGIONS,
- FieldRegionKind,
- ObjCIvarRegionKind,
- END_DECL_REGIONS = ObjCIvarRegionKind,
- CXXTempObjectRegionKind,
- CXXBaseObjectRegionKind,
- END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind,
- END_TYPED_REGIONS = CXXBaseObjectRegionKind
+#define REGION(Id, Parent) Id ## Kind,
+#define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
};
-
+
private:
const Kind kind;
@@ -192,12 +156,9 @@
/// for example, the set of global variables, the stack frame, etc.
class MemSpaceRegion : public MemRegion {
protected:
- friend class MemRegionManager;
-
MemRegionManager *Mgr;
- MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind)
- : MemRegion(k), Mgr(mgr) {
+ MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
assert(classof(this));
}
@@ -210,10 +171,26 @@
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_MEMSPACES && k <= END_MEMSPACES;
+ return k >= BEGIN_MEMSPACES && k <= END_MEMSPACES;
}
};
-
+
+/// CodeSpaceRegion - The memory space that holds the executable code of
+/// functions and blocks.
+class CodeSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ CodeSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, CodeSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == CodeSpaceRegionKind;
+ }
+};
+
class GlobalsSpaceRegion : public MemSpaceRegion {
virtual void anchor();
protected:
@@ -222,7 +199,7 @@
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
+ return k >= BEGIN_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
}
};
@@ -258,17 +235,15 @@
/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
- friend class MemRegionManager;
-
protected:
NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
: GlobalsSpaceRegion(mgr, k) {}
-
+
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES &&
+ return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES &&
k <= END_NON_STATIC_GLOBAL_MEMSPACES;
}
};
@@ -356,7 +331,7 @@
return R->getKind() == UnknownSpaceRegionKind;
}
};
-
+
class StackSpaceRegion : public MemSpaceRegion {
private:
const StackFrameContext *SFC;
@@ -367,18 +342,17 @@
assert(classof(this));
}
-public:
+public:
const StackFrameContext *getStackFrame() const { return SFC; }
-
+
void Profile(llvm::FoldingSetNodeID &ID) const override;
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= StackLocalsSpaceRegionKind &&
- k <= StackArgumentsSpaceRegionKind;
- }
+ return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES;
+ }
};
-
+
class StackLocalsSpaceRegion : public StackSpaceRegion {
virtual void anchor();
friend class MemRegionManager;
@@ -490,7 +464,7 @@
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ return k >= BEGIN_TYPED_REGIONS && k <= END_TYPED_REGIONS;
}
};
@@ -522,7 +496,7 @@
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
+ return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
}
};
@@ -537,16 +511,16 @@
static bool classof(const MemRegion* R) {
Kind k = R->getKind();
- return k >= FunctionTextRegionKind && k <= BlockTextRegionKind;
+ return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS;
}
};
-/// FunctionTextRegion - A region that represents code texts of function.
-class FunctionTextRegion : public CodeTextRegion {
+/// FunctionCodeRegion - A region that represents code texts of function.
+class FunctionCodeRegion : public CodeTextRegion {
const NamedDecl *FD;
public:
- FunctionTextRegion(const NamedDecl *fd, const MemRegion* sreg)
- : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {
+ FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg)
+ : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
}
@@ -576,27 +550,27 @@
const MemRegion*);
static bool classof(const MemRegion* R) {
- return R->getKind() == FunctionTextRegionKind;
+ return R->getKind() == FunctionCodeRegionKind;
}
};
-/// BlockTextRegion - A region that represents code texts of blocks (closures).
-/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// BlockCodeRegion - A region that represents code texts of blocks (closures).
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
/// represent the "code", while BlockDataRegions represent instances of blocks,
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
-class BlockTextRegion : public CodeTextRegion {
+class BlockCodeRegion : public CodeTextRegion {
friend class MemRegionManager;
const BlockDecl *BD;
AnalysisDeclContext *AC;
CanQualType locTy;
- BlockTextRegion(const BlockDecl *bd, CanQualType lTy,
+ BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
AnalysisDeclContext *ac, const MemRegion* sreg)
- : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+ : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {}
public:
QualType getLocationType() const override {
@@ -618,32 +592,32 @@
const MemRegion*);
static bool classof(const MemRegion* R) {
- return R->getKind() == BlockTextRegionKind;
+ return R->getKind() == BlockCodeRegionKind;
}
};
/// BlockDataRegion - A region that represents a block instance.
-/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
/// represent the "code", while BlockDataRegions represent instances of blocks,
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
- const BlockTextRegion *BC;
+ const BlockCodeRegion *BC;
const LocationContext *LC; // Can be null */
unsigned BlockCount;
void *ReferencedVars;
void *OriginalVars;
- BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
+ BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
unsigned count, const MemRegion *sreg)
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
BlockCount(count),
ReferencedVars(nullptr), OriginalVars(nullptr) {}
public:
- const BlockTextRegion *getCodeRegion() const { return BC; }
+ const BlockCodeRegion *getCodeRegion() const { return BC; }
const BlockDecl *getDecl() const { return BC->getDecl(); }
@@ -690,7 +664,7 @@
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *,
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
const LocationContext *, unsigned,
const MemRegion *);
@@ -855,7 +829,7 @@
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS;
+ return k >= BEGIN_DECL_REGIONS && k <= END_DECL_REGIONS;
}
};
@@ -1137,7 +1111,7 @@
HeapSpaceRegion *heap;
UnknownSpaceRegion *unknown;
- MemSpaceRegion *code;
+ CodeSpaceRegion *code;
public:
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a)
@@ -1173,9 +1147,9 @@
/// getUnknownRegion - Retrieve the memory region associated with unknown
/// memory space.
- const MemSpaceRegion *getUnknownRegion();
+ const UnknownSpaceRegion *getUnknownRegion();
- const MemSpaceRegion *getCodeRegion();
+ const CodeSpaceRegion *getCodeRegion();
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
@@ -1261,8 +1235,8 @@
baseReg->isVirtual());
}
- const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
- const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
+ const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD);
+ const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD,
CanQualType locTy,
AnalysisDeclContext *AC);
@@ -1270,7 +1244,7 @@
/// of a block. Unlike many other MemRegions, the LocationContext*
/// argument is allowed to be NULL for cases where we have no known
/// context.
- const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
+ const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc,
const LocationContext *lc,
unsigned blockCount);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
new file mode 100644
index 0000000..c84a1ff
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
@@ -0,0 +1,89 @@
+//===-- Regions.def - Metadata about MemRegion kinds ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of regions (MemRegion sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define one or more
+// of the three macros:
+//
+// REGION(Id, Parent) - for specific MemRegion sub-classes, reserving
+// enum value IdKind for their kind.
+//
+// ABSTRACT_REGION(Id, Parent) - for abstract region classes,
+//
+// REGION_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a region
+// based on the kind-enum value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef REGION
+#define REGION(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_REGION
+#define ABSTRACT_REGION(Id, Parent)
+#endif
+
+#ifndef REGION_RANGE
+#define REGION_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_REGION(MemSpaceRegion, MemRegion)
+ REGION(CodeSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(GlobalsSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(NonStaticGlobalSpaceRegion, GlobalsSpaceRegion)
+ REGION(GlobalImmutableSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalInternalSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalSystemSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION_RANGE(NON_STATIC_GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ GlobalSystemSpaceRegionKind)
+ REGION(StaticGlobalSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ StaticGlobalSpaceRegionKind)
+ REGION(HeapSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(StackSpaceRegion, MemSpaceRegion)
+ REGION(StackArgumentsSpaceRegion, StackSpaceRegion)
+ REGION(StackLocalsSpaceRegion, StackSpaceRegion)
+ REGION_RANGE(STACK_MEMSPACES, StackArgumentsSpaceRegionKind,
+ StackLocalsSpaceRegionKind)
+ REGION(UnknownSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(MEMSPACES, CodeSpaceRegionKind,
+ UnknownSpaceRegionKind)
+ABSTRACT_REGION(SubRegion, MemRegion)
+ REGION(AllocaRegion, SubRegion)
+ REGION(SymbolicRegion, SubRegion)
+ ABSTRACT_REGION(TypedRegion, SubRegion)
+ REGION(BlockDataRegion, TypedRegion)
+ ABSTRACT_REGION(CodeTextRegion, TypedRegion)
+ REGION(BlockCodeRegion, CodeTextRegion)
+ REGION(FunctionCodeRegion, CodeTextRegion)
+ REGION_RANGE(CODE_TEXT_REGIONS, BlockCodeRegionKind,
+ FunctionCodeRegionKind)
+ ABSTRACT_REGION(TypedValueRegion, TypedRegion)
+ REGION(CompoundLiteralRegion, TypedValueRegion)
+ REGION(CXXBaseObjectRegion, TypedValueRegion)
+ REGION(CXXTempObjectRegion, TypedValueRegion)
+ REGION(CXXThisRegion, TypedValueRegion)
+ ABSTRACT_REGION(DeclRegion, TypedValueRegion)
+ REGION(FieldRegion, DeclRegion)
+ REGION(ObjCIvarRegion, DeclRegion)
+ REGION(VarRegion, DeclRegion)
+ REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+ VarRegionKind)
+ REGION(ElementRegion, TypedValueRegion)
+ REGION(ObjCStringRegion, TypedValueRegion)
+ REGION(StringRegion, TypedValueRegion)
+ REGION_RANGE(TYPED_VALUE_REGIONS, CompoundLiteralRegionKind,
+ StringRegionKind)
+ REGION_RANGE(TYPED_REGIONS, BlockDataRegionKind,
+ StringRegionKind)
+
+#undef REGION_RANGE
+#undef ABSTRACT_REGION
+#undef REGION
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a68d341..e4be349 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
namespace clang {
@@ -65,7 +66,7 @@
SymMgr(context, BasicVals, alloc),
MemMgr(context, alloc),
StateMgr(stateMgr),
- ArrayIndexTy(context.IntTy),
+ ArrayIndexTy(context.LongLongTy),
ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
virtual ~SValBuilder() {}
@@ -83,7 +84,11 @@
}
SVal evalCast(SVal val, QualType castTy, QualType originalType);
-
+
+ // Handles casts of type CK_IntegralCast.
+ SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
+ QualType originalType);
+
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
new file mode 100644
index 0000000..f87fdce
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
@@ -0,0 +1,151 @@
+//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
+// interfaces, and also FullSValVisitor, which visits all three hierarchies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+
+namespace clang {
+
+namespace ento {
+
+/// SValVisitor - this class implements a simple visitor for SVal
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SValVisitor {
+public:
+
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
+
+ RetTy Visit(SVal V) {
+ // Dispatch to VisitFooVal for each FooVal.
+ // Take namespaces (loc:: and nonloc::) into account.
+ switch (V.getBaseKind()) {
+#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ case SVal::LocKind:
+ switch (V.getSubKind()) {
+#define LOC_SVAL(Id, Parent) \
+ case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown Loc sub-kind!");
+ case SVal::NonLocKind:
+ switch (V.getSubKind()) {
+#define NONLOC_SVAL(Id, Parent) \
+ case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown NonLoc sub-kind!");
+ }
+ llvm_unreachable("Unknown SVal kind!");
+ }
+
+#define BASIC_SVAL(Id, Parent) \
+ RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
+#define ABSTRACT_SVAL(Id, Parent) \
+ BASIC_SVAL(Id, Parent)
+#define LOC_SVAL(Id, Parent) \
+ RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
+#define NONLOC_SVAL(Id, Parent) \
+ RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSVal(SVal V) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// SymExprVisitor - this class implements a simple visitor for SymExpr
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
+
+ RetTy Visit(SymbolRef S) {
+ // Dispatch to VisitSymbolFoo for each SymbolFoo.
+ switch (S->getKind()) {
+#define SYMBOL(Id, Parent) \
+ case SymExpr::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ }
+ llvm_unreachable("Unknown SymExpr kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
+#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// MemRegionVisitor - this class implements a simple visitor for MemRegion
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
+
+ RetTy Visit(const MemRegion *R) {
+ // Dispatch to VisitFooRegion for each FooRegion.
+ switch (R->getKind()) {
+#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+ }
+ llvm_unreachable("Unknown MemRegion kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define REGION(Id, Parent) \
+ RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
+#define ABSTRACT_REGION(Id, Parent) \
+ REGION(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// FullSValVisitor - a convenient mixed visitor for all three:
+/// SVal, SymExpr and MemRegion subclasses.
+template <typename ImplClass, typename RetTy = void>
+class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
+ public SymExprVisitor<ImplClass, RetTy>,
+ public MemRegionVisitor<ImplClass, RetTy> {
+public:
+ using SValVisitor<ImplClass, RetTy>::Visit;
+ using SymExprVisitor<ImplClass, RetTy>::Visit;
+ using MemRegionVisitor<ImplClass, RetTy>::Visit;
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
new file mode 100644
index 0000000..2faec67
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
@@ -0,0 +1,74 @@
+//===-- SVals.def - Metadata about SVal kinds -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbolic values (SVal kinds and sub-kinds) used in the Static
+// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is
+// currently hardcoded, because it is too peculiar and explicit to be handled
+// uniformly. In order to use this information, users of this file must define
+// one or more of the following macros:
+//
+// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are
+// neither in loc:: nor in nonloc:: namespace; these classes occupy
+// their own base kind IdKind.
+//
+// ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are
+// neither in loc:: nor in nonloc:: namespace,
+//
+// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also
+// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind
+// identifier IdKind, much like BASIC_SVALs.
+//
+// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind
+// loc::IdKind.
+//
+// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a
+// sub-kind nonloc::IdKind.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BASIC_SVAL
+#define BASIC_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL
+#define ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL_WITH_KIND
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef LOC_SVAL
+#define LOC_SVAL(Id, Parent)
+#endif
+
+#ifndef NONLOC_SVAL
+#define NONLOC_SVAL(Id, Parent)
+#endif
+
+BASIC_SVAL(UndefinedVal, SVal)
+ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
+ BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal)
+ LOC_SVAL(ConcreteInt, Loc)
+ LOC_SVAL(GotoLabel, Loc)
+ LOC_SVAL(MemRegionVal, Loc)
+ ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal)
+ NONLOC_SVAL(CompoundVal, NonLoc)
+ NONLOC_SVAL(ConcreteInt, NonLoc)
+ NONLOC_SVAL(LazyCompoundVal, NonLoc)
+ NONLOC_SVAL(LocAsInteger, NonLoc)
+ NONLOC_SVAL(SymbolVal, NonLoc)
+
+#undef NONLOC_SVAL
+#undef LOC_SVAL
+#undef ABSTRACT_SVAL_WITH_KIND
+#undef ABSTRACT_SVAL
+#undef BASIC_SVAL
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 642e11a..dbc7c99 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -15,9 +15,11 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
+#include "clang/AST/Expr.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
@@ -45,11 +47,9 @@
public:
enum BaseKind {
// The enumerators must be representable using 2 bits.
- UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value)
- UnknownKind = 1, // for subclass UnknownVal (a void value)
- LocKind = 2, // for subclass Loc (an L-value)
- NonLocKind = 3 // for subclass NonLoc (an R-value that's not
- // an L-value)
+#define BASIC_SVAL(Id, Parent) Id ## Kind,
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
};
enum { BaseBits = 2, BaseMask = 0x3 };
@@ -115,19 +115,19 @@
}
inline bool isUnknown() const {
- return getRawKind() == UnknownKind;
+ return getRawKind() == UnknownValKind;
}
inline bool isUndef() const {
- return getRawKind() == UndefinedKind;
+ return getRawKind() == UndefinedValKind;
}
inline bool isUnknownOrUndef() const {
- return getRawKind() <= UnknownKind;
+ return getRawKind() <= UnknownValKind;
}
inline bool isValid() const {
- return getRawKind() > UnknownKind;
+ return getRawKind() > UnknownValKind;
}
bool isConstant() const;
@@ -190,12 +190,12 @@
class UndefinedVal : public SVal {
public:
- UndefinedVal() : SVal(UndefinedKind) {}
+ UndefinedVal() : SVal(UndefinedValKind) {}
private:
friend class SVal;
static bool isKind(const SVal& V) {
- return V.getBaseKind() == UndefinedKind;
+ return V.getBaseKind() == UndefinedValKind;
}
};
@@ -223,12 +223,12 @@
class UnknownVal : public DefinedOrUnknownSVal {
public:
- explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
+ explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
private:
friend class SVal;
static bool isKind(const SVal &V) {
- return V.getBaseKind() == UnknownKind;
+ return V.getBaseKind() == UnknownValKind;
}
};
@@ -306,8 +306,10 @@
namespace nonloc {
-enum Kind { ConcreteIntKind, SymbolValKind,
- LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
/// \brief Represents symbolic expression.
class SymbolVal : public NonLoc {
@@ -465,7 +467,10 @@
namespace loc {
-enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
class GotoLabel : public Loc {
public:
@@ -490,7 +495,7 @@
class MemRegionVal : public Loc {
public:
- explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
+ explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {}
/// \brief Get the underlining region.
const MemRegion* getRegion() const {
@@ -518,11 +523,11 @@
MemRegionVal() {}
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind &&
- V.getSubKind() == MemRegionKind;
+ V.getSubKind() == MemRegionValKind;
}
static bool isKind(const Loc& V) {
- return V.getSubKind() == MemRegionKind;
+ return V.getSubKind() == MemRegionValKind;
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
new file mode 100644
index 0000000..be9646b
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -0,0 +1,109 @@
+//== SymExpr.h - Management of Symbolic Values ------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymExpr and SymbolData.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+
+#include "clang/AST/Type.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Symbolic value. These values used to capture symbolic execution of
+/// the program.
+class SymExpr : public llvm::FoldingSetNode {
+ virtual void anchor();
+
+public:
+ enum Kind {
+#define SYMBOL(Id, Parent) Id##Kind,
+#define SYMBOL_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ };
+
+private:
+ Kind K;
+
+protected:
+ SymExpr(Kind k) : K(k) {}
+
+public:
+ virtual ~SymExpr() {}
+
+ Kind getKind() const { return K; }
+
+ virtual void dump() const;
+
+ virtual void dumpToStream(raw_ostream &os) const {}
+
+ virtual QualType getType() const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID &profile) = 0;
+
+ /// \brief Iterator over symbols that the current symbol depends on.
+ ///
+ /// For SymbolData, it's the symbol itself; for expressions, it's the
+ /// expression symbol and all the operands in it. Note, SymbolDerived is
+ /// treated as SymbolData - the iterator will NOT visit the parent region.
+ class symbol_iterator {
+ SmallVector<const SymExpr *, 5> itr;
+ void expand();
+
+ public:
+ symbol_iterator() {}
+ symbol_iterator(const SymExpr *SE);
+
+ symbol_iterator &operator++();
+ const SymExpr *operator*();
+
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
+ };
+
+ symbol_iterator symbol_begin() const { return symbol_iterator(this); }
+ static symbol_iterator symbol_end() { return symbol_iterator(); }
+
+ unsigned computeComplexity() const;
+};
+
+typedef const SymExpr *SymbolRef;
+typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+
+typedef unsigned SymbolID;
+/// \brief A symbol representing data which can be stored in a memory location
+/// (region).
+class SymbolData : public SymExpr {
+ void anchor() override;
+ const SymbolID Sym;
+
+protected:
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+
+public:
+ ~SymbolData() override {}
+
+ SymbolID getSymbolID() const { return Sym; }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr *SE) {
+ Kind k = SE->getKind();
+ return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
+ }
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 05de02d..30481ea 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -19,7 +19,9 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
@@ -32,106 +34,22 @@
namespace ento {
class BasicValueFactory;
- class MemRegion;
class SubRegion;
class TypedValueRegion;
class VarRegion;
-/// \brief Symbolic value. These values used to capture symbolic execution of
-/// the program.
-class SymExpr : public llvm::FoldingSetNode {
- virtual void anchor();
-public:
- enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
- MetadataKind,
- BEGIN_SYMBOLS = RegionValueKind,
- END_SYMBOLS = MetadataKind,
- SymIntKind, IntSymKind, SymSymKind,
- BEGIN_BINARYSYMEXPRS = SymIntKind,
- END_BINARYSYMEXPRS = SymSymKind,
- CastSymbolKind };
-private:
- Kind K;
-
-protected:
- SymExpr(Kind k) : K(k) {}
-
-public:
- virtual ~SymExpr() {}
-
- Kind getKind() const { return K; }
-
- virtual void dump() const;
-
- virtual void dumpToStream(raw_ostream &os) const {}
-
- virtual QualType getType() const = 0;
- virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
-
- /// \brief Iterator over symbols that the current symbol depends on.
- ///
- /// For SymbolData, it's the symbol itself; for expressions, it's the
- /// expression symbol and all the operands in it. Note, SymbolDerived is
- /// treated as SymbolData - the iterator will NOT visit the parent region.
- class symbol_iterator {
- SmallVector<const SymExpr*, 5> itr;
- void expand();
- public:
- symbol_iterator() {}
- symbol_iterator(const SymExpr *SE);
-
- symbol_iterator &operator++();
- const SymExpr* operator*();
-
- bool operator==(const symbol_iterator &X) const;
- bool operator!=(const symbol_iterator &X) const;
- };
-
- symbol_iterator symbol_begin() const {
- return symbol_iterator(this);
- }
- static symbol_iterator symbol_end() { return symbol_iterator(); }
-
- unsigned computeComplexity() const;
-};
-
-typedef const SymExpr* SymbolRef;
-typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
-
-typedef unsigned SymbolID;
-/// \brief A symbol representing data which can be stored in a memory location
-/// (region).
-class SymbolData : public SymExpr {
- void anchor() override;
- const SymbolID Sym;
-
-protected:
- SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
-
-public:
- ~SymbolData() override {}
-
- SymbolID getSymbolID() const { return Sym; }
-
- // Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
- Kind k = SE->getKind();
- return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
- }
-};
-
///\brief A symbol representing the value stored at a MemRegion.
class SymbolRegionValue : public SymbolData {
const TypedValueRegion *R;
public:
SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
- : SymbolData(RegionValueKind, sym), R(r) {}
+ : SymbolData(SymbolRegionValueKind, sym), R(r) {}
const TypedValueRegion* getRegion() const { return R; }
static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
- profile.AddInteger((unsigned) RegionValueKind);
+ profile.AddInteger((unsigned) SymbolRegionValueKind);
profile.AddPointer(R);
}
@@ -145,7 +63,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == RegionValueKind;
+ return SE->getKind() == SymbolRegionValueKind;
}
};
@@ -160,11 +78,9 @@
public:
SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
- QualType t, unsigned count,
- const void *symbolTag)
- : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
- LCtx(lctx),
- SymbolTag(symbolTag) {}
+ QualType t, unsigned count, const void *symbolTag)
+ : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
+ LCtx(lctx), SymbolTag(symbolTag) {}
const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
@@ -177,7 +93,7 @@
static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
QualType T, unsigned Count, const LocationContext *LCtx,
const void *SymbolTag) {
- profile.AddInteger((unsigned) ConjuredKind);
+ profile.AddInteger((unsigned) SymbolConjuredKind);
profile.AddPointer(S);
profile.AddPointer(LCtx);
profile.Add(T);
@@ -191,7 +107,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == ConjuredKind;
+ return SE->getKind() == SymbolConjuredKind;
}
};
@@ -203,7 +119,7 @@
public:
SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
- : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
+ : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {}
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
@@ -214,7 +130,7 @@
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
const TypedValueRegion *r) {
- profile.AddInteger((unsigned) DerivedKind);
+ profile.AddInteger((unsigned) SymbolDerivedKind);
profile.AddPointer(r);
profile.AddPointer(parent);
}
@@ -225,7 +141,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == DerivedKind;
+ return SE->getKind() == SymbolDerivedKind;
}
};
@@ -237,7 +153,7 @@
public:
SymbolExtent(SymbolID sym, const SubRegion *r)
- : SymbolData(ExtentKind, sym), R(r) {}
+ : SymbolData(SymbolExtentKind, sym), R(r) {}
const SubRegion *getRegion() const { return R; }
@@ -246,7 +162,7 @@
void dumpToStream(raw_ostream &os) const override;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
- profile.AddInteger((unsigned) ExtentKind);
+ profile.AddInteger((unsigned) SymbolExtentKind);
profile.AddPointer(R);
}
@@ -256,7 +172,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == ExtentKind;
+ return SE->getKind() == SymbolExtentKind;
}
};
@@ -273,7 +189,7 @@
public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
unsigned count, const void *tag)
- : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
+ : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
const MemRegion *getRegion() const { return R; }
const Stmt *getStmt() const { return S; }
@@ -287,7 +203,7 @@
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
const void *Tag) {
- profile.AddInteger((unsigned) MetadataKind);
+ profile.AddInteger((unsigned) SymbolMetadataKind);
profile.AddPointer(R);
profile.AddPointer(S);
profile.Add(T);
@@ -301,7 +217,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == MetadataKind;
+ return SE->getKind() == SymbolMetadataKind;
}
};
@@ -315,7 +231,7 @@
public:
SymbolCast(const SymExpr *In, QualType From, QualType To) :
- SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
+ SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { }
QualType getType() const override { return ToTy; }
@@ -325,7 +241,7 @@
static void Profile(llvm::FoldingSetNodeID& ID,
const SymExpr *In, QualType From, QualType To) {
- ID.AddInteger((unsigned) CastSymbolKind);
+ ID.AddInteger((unsigned) SymbolCastKind);
ID.AddPointer(In);
ID.Add(From);
ID.Add(To);
@@ -337,7 +253,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == CastSymbolKind;
+ return SE->getKind() == SymbolCastKind;
}
};
@@ -372,7 +288,7 @@
public:
SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t)
- : BinarySymExpr(SymIntKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {}
void dumpToStream(raw_ostream &os) const override;
@@ -382,7 +298,7 @@
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
QualType t) {
- ID.AddInteger((unsigned) SymIntKind);
+ ID.AddInteger((unsigned) SymIntExprKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(&rhs);
@@ -395,7 +311,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == SymIntKind;
+ return SE->getKind() == SymIntExprKind;
}
};
@@ -407,7 +323,7 @@
public:
IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t)
- : BinarySymExpr(IntSymKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
void dumpToStream(raw_ostream &os) const override;
@@ -417,7 +333,7 @@
static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t) {
- ID.AddInteger((unsigned) IntSymKind);
+ ID.AddInteger((unsigned) IntSymExprKind);
ID.AddPointer(&lhs);
ID.AddInteger(op);
ID.AddPointer(rhs);
@@ -430,7 +346,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == IntSymKind;
+ return SE->getKind() == IntSymExprKind;
}
};
@@ -442,7 +358,7 @@
public:
SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t)
- : BinarySymExpr(SymSymKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
@@ -451,7 +367,7 @@
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
- ID.AddInteger((unsigned) SymSymKind);
+ ID.AddInteger((unsigned) SymSymExprKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(rhs);
@@ -464,7 +380,7 @@
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == SymSymKind;
+ return SE->getKind() == SymSymExprKind;
}
};
@@ -639,6 +555,7 @@
}
void markLive(const MemRegion *region);
+ void markElementIndicesLive(const MemRegion *region);
/// \brief Set to the value of the symbolic store after
/// StoreManager::removeDeadBindings has been called.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
new file mode 100644
index 0000000..7d4d8fe
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
@@ -0,0 +1,55 @@
+//===-- Symbols.def - Metadata about SymExpr kinds --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbols (SymExpr sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define
+// one or more of the three macros:
+//
+// SYMBOL(Id, Parent) - for specific SymExpr sub-classes, reserving the
+// IdKind identifier for its kind enumeration value.
+//
+// ABSTRACT_SYMBOL(Id, Parent) - for abstract symbol classes,
+//
+// SYMBOL_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a symbol
+// based on the kind enumeration value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SYMBOL
+#define SYMBOL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SYMBOL
+#define ABSTRACT_SYMBOL(Id, Parent)
+#endif
+
+#ifndef SYMBOL_RANGE
+#define SYMBOL_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_SYMBOL(BinarySymExpr, SymExpr)
+ SYMBOL(IntSymExpr, BinarySymExpr)
+ SYMBOL(SymIntExpr, BinarySymExpr)
+ SYMBOL(SymSymExpr, BinarySymExpr)
+SYMBOL_RANGE(BINARYSYMEXPRS, IntSymExprKind, SymSymExprKind)
+
+SYMBOL(SymbolCast, SymExpr)
+
+ABSTRACT_SYMBOL(SymbolData, SymExpr)
+ SYMBOL(SymbolConjured, SymbolData)
+ SYMBOL(SymbolDerived, SymbolData)
+ SYMBOL(SymbolExtent, SymbolData)
+ SYMBOL(SymbolMetadata, SymbolData)
+ SYMBOL(SymbolRegionValue, SymbolData)
+SYMBOL_RANGE(SYMBOLS, SymbolConjuredKind, SymbolRegionValueKind)
+
+#undef SYMBOL
+#undef ABSTRACT_SYMBOL
+#undef SYMBOL_RANGE
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 28b6d16..a3e18ff 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -108,6 +108,9 @@
umbrella "StaticAnalyzer/Core"
textual header "StaticAnalyzer/Core/Analyses.def"
+ textual header "StaticAnalyzer/Core/PathSensitive/SVals.def"
+ textual header "StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ textual header "StaticAnalyzer/Core/PathSensitive/Regions.def"
module * { export * }
}
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 7e84994..1be724c 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -588,7 +588,7 @@
if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
return;
- for (auto *Prop : D->properties()) {
+ for (auto *Prop : D->instance_properties()) {
if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
!Prop->isDeprecated())
migratePropertyNsReturnsInnerPointer(Ctx, Prop);
@@ -605,7 +605,7 @@
// in class interface.
bool HasAtleastOneRequiredProperty = false;
if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
- for (const auto *Property : PDecl->properties()) {
+ for (const auto *Property : PDecl->instance_properties()) {
if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
HasAtleastOneRequiredProperty = true;
@@ -615,7 +615,8 @@
// or dynamic declaration. Class is implementing a property coming from
// another protocol. This still makes the target protocol as conforming.
if (!ImpDecl->FindPropertyImplDecl(
- Property->getDeclName().getAsIdentifierInfo()))
+ Property->getDeclName().getAsIdentifierInfo(),
+ Property->getQueryKind()))
return false;
}
else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
@@ -1524,7 +1525,7 @@
FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
- // Trivial case of when funciton is annotated and has no argument.
+ // Trivial case of when function is annotated and has no argument.
if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
return CF_BRIDGING_NONE;
@@ -1653,7 +1654,7 @@
Editor->commit(commit);
}
- // Trivial case of when funciton is annotated and has no argument.
+ // Trivial case of when function is annotated and has no argument.
if (MethodIsReturnAnnotated &&
(MethodDecl->param_begin() == MethodDecl->param_end()))
return;
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index 8667bc2..389b036 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -76,7 +76,7 @@
static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
AtPropDeclsTy *PrevAtProps = nullptr) {
- for (auto *Prop : D->properties()) {
+ for (auto *Prop : D->instance_properties()) {
if (Prop->getAtLoc().isInvalid())
continue;
unsigned RawLoc = Prop->getAtLoc().getRawEncoding();
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4009915..06fb46e 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Comment.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -660,8 +661,7 @@
nullptr,
TemplateParameterList::Create(*this, SourceLocation(),
SourceLocation(),
- CanonParams.data(),
- CanonParams.size(),
+ CanonParams,
SourceLocation()));
// Get the new insert position for the node we care about.
@@ -738,12 +738,13 @@
BuiltinVaListDecl(nullptr), BuiltinMSVaListDecl(nullptr),
ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr),
ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
- CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr),
- FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr),
- ucontext_tDecl(nullptr), BlockDescriptorType(nullptr),
- BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr),
- FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr),
- MakeIntegerSeqDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
+ CFConstantStringTagDecl(nullptr), CFConstantStringTypeDecl(nullptr),
+ ObjCInstanceTypeDecl(nullptr), FILEDecl(nullptr), jmp_bufDecl(nullptr),
+ sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr),
+ BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr),
+ cudaConfigureCallDecl(nullptr), FirstLocalImport(), LastLocalImport(),
+ ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr), SourceMgr(SM),
+ LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
@@ -761,10 +762,8 @@
ReleaseDeclContextMaps();
// Call all of the deallocation functions on all of their targets.
- for (DeallocationMap::const_iterator I = Deallocations.begin(),
- E = Deallocations.end(); I != E; ++I)
- for (unsigned J = 0, N = I->second.size(); J != N; ++J)
- (I->first)((I->second)[J]);
+ for (auto &Pair : Deallocations)
+ (Pair.first)(Pair.second);
// ASTRecordLayout objects in ASTRecordLayouts must always be destroyed
// because they can contain DenseMaps.
@@ -813,7 +812,7 @@
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
- Deallocations[Callback].push_back(Data);
+ Deallocations.push_back({Callback, Data});
}
void
@@ -1482,7 +1481,7 @@
unsigned Align = EltInfo.second.getQuantity();
if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
Context.getTargetInfo().getPointerWidth(0) == 64)
- Width = llvm::RoundUpToAlignment(Width, Align);
+ Width = llvm::alignTo(Width, Align);
return std::make_pair(CharUnits::fromQuantity(Width),
CharUnits::fromQuantity(Align));
}
@@ -1566,7 +1565,7 @@
Align = EltInfo.Align;
if (!getTargetInfo().getCXXABI().isMicrosoft() ||
getTargetInfo().getPointerWidth(0) == 64)
- Width = llvm::RoundUpToAlignment(Width, Align);
+ Width = llvm::alignTo(Width, Align);
break;
}
case Type::ExtVector:
@@ -1579,7 +1578,7 @@
// This happens for non-power-of-2 length vectors.
if (Align & (Align-1)) {
Align = llvm::NextPowerOf2(Align);
- Width = llvm::RoundUpToAlignment(Width, Align);
+ Width = llvm::alignTo(Width, Align);
}
// Adjust the alignment based on the target max.
uint64_t TargetVectorAlign = Target->getMaxVectorAlign();
@@ -1838,6 +1837,13 @@
Align = static_cast<unsigned>(Width);
}
}
+ break;
+
+ case Type::Pipe: {
+ TypeInfo Info = getTypeInfo(cast<PipeType>(T)->getElementType());
+ Width = Info.Width;
+ Align = Info.Align;
+ }
}
@@ -2065,6 +2071,17 @@
ObjCImpls[CatD] = ImplD;
}
+const ObjCMethodDecl *
+ASTContext::getObjCMethodRedeclaration(const ObjCMethodDecl *MD) const {
+ return ObjCMethodRedecls.lookup(MD);
+}
+
+void ASTContext::setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
+ const ObjCMethodDecl *Redecl) {
+ assert(!getObjCMethodRedeclaration(MD) && "MD already has a redeclaration");
+ ObjCMethodRedecls[MD] = Redecl;
+}
+
const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
const NamedDecl *ND) const {
if (const ObjCInterfaceDecl *ID =
@@ -2654,6 +2671,7 @@
case Type::FunctionProto:
case Type::BlockPointer:
case Type::MemberPointer:
+ case Type::Pipe:
return type;
// These types can be variably-modified. All these modifications
@@ -3108,6 +3126,32 @@
return QualType(FTP, 0);
}
+/// Return pipe type for the specified type.
+QualType ASTContext::getPipeType(QualType T) const {
+ llvm::FoldingSetNodeID ID;
+ PipeType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(PT, 0);
+
+ // If the pipe element type isn't canonical, this won't be a canonical type
+ // either, so fill in the canonical type field.
+ QualType Canonical;
+ if (!T.isCanonical()) {
+ Canonical = getPipeType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!NewIP && "Shouldn't be in the map!");
+ (void)NewIP;
+ }
+ PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical);
+ Types.push_back(New);
+ PipeTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
#ifndef NDEBUG
static bool NeedsInjectedClassNameType(const RecordDecl *D) {
if (!isa<CXXRecordDecl>(D)) return false;
@@ -3649,14 +3693,13 @@
return DeclarationName::compare((*LHS)->getDeclName(), (*RHS)->getDeclName());
}
-static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols,
- unsigned NumProtocols) {
- if (NumProtocols == 0) return true;
+static bool areSortedAndUniqued(ArrayRef<ObjCProtocolDecl *> Protocols) {
+ if (Protocols.empty()) return true;
if (Protocols[0]->getCanonicalDecl() != Protocols[0])
return false;
- for (unsigned i = 1; i != NumProtocols; ++i)
+ for (unsigned i = 1; i != Protocols.size(); ++i)
if (CmpProtocolNames(&Protocols[i - 1], &Protocols[i]) >= 0 ||
Protocols[i]->getCanonicalDecl() != Protocols[i])
return false;
@@ -3721,8 +3764,7 @@
[&](QualType type) {
return type.isCanonical();
});
- bool protocolsSorted = areSortedAndUniqued(protocols.data(),
- protocols.size());
+ bool protocolsSorted = areSortedAndUniqued(protocols);
if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) {
// Determine the canonical type arguments.
ArrayRef<QualType> canonTypeArgs;
@@ -3983,20 +4025,20 @@
/// getAutoType - Return the uniqued reference to the 'auto' type which has been
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
/// canonical deduced-but-dependent 'auto' type.
-QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto,
+QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
bool IsDependent) const {
- if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent)
+ if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
return getAutoDeductType();
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent);
+ AutoType::Profile(ID, DeducedType, Keyword, IsDependent);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
- IsDecltypeAuto,
+ Keyword,
IsDependent);
Types.push_back(AT);
if (InsertPos)
@@ -4036,7 +4078,7 @@
QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
- new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false,
+ new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
/*dependent*/false),
0);
return AutoDeductTy;
@@ -4827,11 +4869,12 @@
return 1;
}
-// getCFConstantStringType - Return the type used for constant CFStrings.
-QualType ASTContext::getCFConstantStringType() const {
+TypedefDecl *ASTContext::getCFConstantStringDecl() const {
if (!CFConstantStringTypeDecl) {
- CFConstantStringTypeDecl = buildImplicitRecord("NSConstantString");
- CFConstantStringTypeDecl->startDefinition();
+ assert(!CFConstantStringTagDecl &&
+ "tag and typedef should be initialized together");
+ CFConstantStringTagDecl = buildImplicitRecord("__NSConstantString_tag");
+ CFConstantStringTagDecl->startDefinition();
QualType FieldTypes[4];
@@ -4846,7 +4889,7 @@
// Create fields
for (unsigned i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
+ FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTagDecl,
SourceLocation(),
SourceLocation(), nullptr,
FieldTypes[i], /*TInfo=*/nullptr,
@@ -4854,13 +4897,29 @@
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
- CFConstantStringTypeDecl->addDecl(Field);
+ CFConstantStringTagDecl->addDecl(Field);
}
- CFConstantStringTypeDecl->completeDefinition();
+ CFConstantStringTagDecl->completeDefinition();
+ // This type is designed to be compatible with NSConstantString, but cannot
+ // use the same name, since NSConstantString is an interface.
+ auto tagType = getTagDeclType(CFConstantStringTagDecl);
+ CFConstantStringTypeDecl =
+ buildImplicitTypedef(tagType, "__NSConstantString");
}
- return getTagDeclType(CFConstantStringTypeDecl);
+ return CFConstantStringTypeDecl;
+}
+
+RecordDecl *ASTContext::getCFConstantStringTagDecl() const {
+ if (!CFConstantStringTagDecl)
+ getCFConstantStringDecl(); // Build the tag and the typedef.
+ return CFConstantStringTagDecl;
+}
+
+// getCFConstantStringType - Return the type used for constant CFStrings.
+QualType ASTContext::getCFConstantStringType() const {
+ return getTypedefType(getCFConstantStringDecl());
}
QualType ASTContext::getObjCSuperType() const {
@@ -4873,9 +4932,13 @@
}
void ASTContext::setCFConstantStringType(QualType T) {
- const RecordType *Rec = T->getAs<RecordType>();
- assert(Rec && "Invalid CFConstantStringType");
- CFConstantStringTypeDecl = Rec->getDecl();
+ const TypedefType *TD = T->getAs<TypedefType>();
+ assert(TD && "Invalid CFConstantStringType");
+ CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
+ auto TagType =
+ CFConstantStringTypeDecl->getUnderlyingType()->getAs<RecordType>();
+ assert(TagType && "Invalid CFConstantStringType");
+ CFConstantStringTagDecl = TagType->getDecl();
}
QualType ASTContext::getBlockDescriptorType() const {
@@ -5850,6 +5913,7 @@
case Type::Auto:
return;
+ case Type::Pipe:
#define ABSTRACT_TYPE(KIND, BASE)
#define TYPE(KIND, BASE)
#define DEPENDENT_TYPE(KIND, BASE) \
@@ -5871,7 +5935,7 @@
QualType *NotEncodedT) const {
assert(RDecl && "Expected non-null RecordDecl");
assert(!RDecl->isUnion() && "Should not be called for unions");
- if (!RDecl->getDefinition())
+ if (!RDecl->getDefinition() || RDecl->getDefinition()->isInvalidDecl())
return;
CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl);
@@ -7785,6 +7849,24 @@
return QualType();
}
+ case Type::Pipe:
+ {
+ // Merge two pointer types, while trying to preserve typedef info
+ QualType LHSValue = LHS->getAs<PipeType>()->getElementType();
+ QualType RHSValue = RHS->getAs<PipeType>()->getElementType();
+ if (Unqualified) {
+ LHSValue = LHSValue.getUnqualifiedType();
+ RHSValue = RHSValue.getUnqualifiedType();
+ }
+ QualType ResultType = mergeTypes(LHSValue, RHSValue, false,
+ Unqualified);
+ if (ResultType.isNull()) return QualType();
+ if (getCanonicalType(LHSValue) == getCanonicalType(ResultType))
+ return LHS;
+ if (getCanonicalType(RHSValue) == getCanonicalType(ResultType))
+ return RHS;
+ return getPipeType(ResultType);
+ }
}
llvm_unreachable("Invalid Type::Class!");
@@ -7808,6 +7890,10 @@
return true;
}
+void ASTContext::ResetObjCLayout(const ObjCContainerDecl *CD) {
+ ObjCLayouts[CD] = nullptr;
+}
+
/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and
/// 'RHS' attributes and returns the merged version; including for function
/// return types.
@@ -8729,7 +8815,6 @@
///
/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
-
public:
/// \brief Builds and returns the translation unit's parent map.
///
@@ -8756,15 +8841,11 @@
bool shouldVisitImplicitCode() const {
return true;
}
- // Disables data recursion. We intercept Traverse* methods in the RAV, which
- // are not triggered during data recursion.
- bool shouldUseDataRecursionFor(clang::Stmt *S) const {
- return false;
- }
- template <typename T, typename MapNodeTy, typename MapTy>
+ template <typename T, typename MapNodeTy, typename BaseTraverseFn,
+ typename MapTy>
bool TraverseNode(T Node, MapNodeTy MapNode,
- bool (VisitorBase::*traverse)(T), MapTy *Parents) {
+ BaseTraverseFn BaseTraverse, MapTy *Parents) {
if (!Node)
return true;
if (ParentStack.size() > 0) {
@@ -8812,31 +8893,37 @@
}
}
ParentStack.push_back(createDynTypedNode(Node));
- bool Result = (this ->* traverse) (Node);
+ bool Result = BaseTraverse();
ParentStack.pop_back();
return Result;
}
bool TraverseDecl(Decl *DeclNode) {
- return TraverseNode(DeclNode, DeclNode, &VisitorBase::TraverseDecl,
+ return TraverseNode(DeclNode, DeclNode,
+ [&] { return VisitorBase::TraverseDecl(DeclNode); },
Parents);
}
bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(StmtNode, StmtNode, &VisitorBase::TraverseStmt,
+ return TraverseNode(StmtNode, StmtNode,
+ [&] { return VisitorBase::TraverseStmt(StmtNode); },
Parents);
}
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
- return TraverseNode(TypeLocNode,
- ast_type_traits::DynTypedNode::create(TypeLocNode),
- &VisitorBase::TraverseTypeLoc, OtherParents);
+ return TraverseNode(
+ TypeLocNode, ast_type_traits::DynTypedNode::create(TypeLocNode),
+ [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
+ OtherParents);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
return TraverseNode(
NNSLocNode, ast_type_traits::DynTypedNode::create(NNSLocNode),
- &VisitorBase::TraverseNestedNameSpecifierLoc, OtherParents);
+ [&] {
+ return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode);
+ },
+ OtherParents);
}
ASTContext::ParentMapPointers *Parents;
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 0ab1fa7..2ab5a32 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -473,14 +473,14 @@
/// ShowColor - Diagnostics support color, so bolding will be used.
bool ShowColor;
- /// FromType - When single type printing is selected, this is the type to be
- /// be printed. When tree printing is selected, this type will show up first
- /// in the tree.
- QualType FromType;
+ /// FromTemplateType - When single type printing is selected, this is the
+ /// type to be be printed. When tree printing is selected, this type will
+ /// show up first in the tree.
+ QualType FromTemplateType;
- /// ToType - The type that FromType is compared to. Only in tree printing
- /// will this type be outputed.
- QualType ToType;
+ /// ToTemplateType - The type that FromType is compared to. Only in tree
+ /// printing will this type be outputed.
+ QualType ToTemplateType;
/// OS - The stream used to construct the output strings.
raw_ostream &OS;
@@ -491,82 +491,70 @@
/// DiffTree - A tree representation the differences between two types.
class DiffTree {
public:
- /// DiffKind - The difference in a DiffNode and which fields are used.
+ /// DiffKind - The difference in a DiffNode. Fields of
+ /// TemplateArgumentInfo needed by each difference can be found in the
+ /// Set* and Get* functions.
enum DiffKind {
/// Incomplete or invalid node.
Invalid,
- /// Another level of templates, uses TemplateDecl and Qualifiers
+ /// Another level of templates, requires that
Template,
- /// Type difference, uses QualType
+ /// Type difference, all type differences except those falling under
+ /// the Template difference.
Type,
- /// Expression difference, uses Expr
+ /// Expression difference, this is only when both arguments are
+ /// expressions. If one argument is an expression and the other is
+ /// Integer or Declaration, then use that diff type instead.
Expression,
- /// Template argument difference, uses TemplateDecl
+ /// Template argument difference
TemplateTemplate,
- /// Integer difference, uses APSInt and Expr
+ /// Integer difference
Integer,
- /// Declaration difference, uses ValueDecl
- Declaration
+ /// Declaration difference, nullptr arguments are included here
+ Declaration,
+ /// One argument being integer and the other being declaration
+ FromIntegerAndToDeclaration,
+ FromDeclarationAndToInteger
};
+
private:
+ /// TemplateArgumentInfo - All the information needed to pretty print
+ /// a template argument. See the Set* and Get* functions to see which
+ /// fields are used for each DiffKind.
+ struct TemplateArgumentInfo {
+ QualType ArgType;
+ Qualifiers Qual;
+ llvm::APSInt Val;
+ bool IsValidInt = false;
+ Expr *ArgExpr = nullptr;
+ TemplateDecl *TD = nullptr;
+ ValueDecl *VD = nullptr;
+ bool NeedAddressOf = false;
+ bool IsNullPtr = false;
+ bool IsDefault = false;
+ };
+
/// DiffNode - The root node stores the original type. Each child node
/// stores template arguments of their parents. For templated types, the
/// template decl is also stored.
struct DiffNode {
- DiffKind Kind;
+ DiffKind Kind = Invalid;
/// NextNode - The index of the next sibling node or 0.
- unsigned NextNode;
+ unsigned NextNode = 0;
/// ChildNode - The index of the first child node or 0.
- unsigned ChildNode;
+ unsigned ChildNode = 0;
/// ParentNode - The index of the parent node.
- unsigned ParentNode;
+ unsigned ParentNode = 0;
- /// FromType, ToType - The type arguments.
- QualType FromType, ToType;
-
- /// FromExpr, ToExpr - The expression arguments.
- Expr *FromExpr, *ToExpr;
-
- /// FromNullPtr, ToNullPtr - If the template argument is a nullptr
- bool FromNullPtr, ToNullPtr;
-
- /// FromTD, ToTD - The template decl for template template
- /// arguments or the type arguments that are templates.
- TemplateDecl *FromTD, *ToTD;
-
- /// FromQual, ToQual - Qualifiers for template types.
- Qualifiers FromQual, ToQual;
-
- /// FromInt, ToInt - APSInt's for integral arguments.
- llvm::APSInt FromInt, ToInt;
-
- /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
- bool IsValidFromInt, IsValidToInt;
-
- /// FromValueDecl, ToValueDecl - Whether the argument is a decl.
- ValueDecl *FromValueDecl, *ToValueDecl;
-
- /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of
- /// operator before it.
- bool FromAddressOf, ToAddressOf;
-
- /// FromDefault, ToDefault - Whether the argument is a default argument.
- bool FromDefault, ToDefault;
+ TemplateArgumentInfo FromArgInfo, ToArgInfo;
/// Same - Whether the two arguments evaluate to the same value.
- bool Same;
+ bool Same = false;
- DiffNode(unsigned ParentNode = 0)
- : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
- FromType(), ToType(), FromExpr(nullptr), ToExpr(nullptr),
- FromNullPtr(false), ToNullPtr(false),
- FromTD(nullptr), ToTD(nullptr), IsValidFromInt(false),
- IsValidToInt(false), FromValueDecl(nullptr), ToValueDecl(nullptr),
- FromAddressOf(false), ToAddressOf(false), FromDefault(false),
- ToDefault(false), Same(false) {}
+ DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {}
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -581,54 +569,127 @@
/// ReadNode - The index of the current node being read.
unsigned ReadNode;
-
+
public:
DiffTree() :
CurrentNode(0), NextFreeNode(1) {
FlatTree.push_back(DiffNode());
}
- // Node writing functions.
- /// SetNode - Sets FromTD and ToTD of the current node.
- void SetNode(TemplateDecl *FromTD, TemplateDecl *ToTD) {
- FlatTree[CurrentNode].FromTD = FromTD;
- FlatTree[CurrentNode].ToTD = ToTD;
+ // Node writing functions, one for each valid DiffKind element.
+ void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
+ Qualifiers FromQual, Qualifiers ToQual,
+ bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Template;
+ FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
+ FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
+ FlatTree[CurrentNode].FromArgInfo.Qual = FromQual;
+ FlatTree[CurrentNode].ToArgInfo.Qual = ToQual;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Sets FromType and ToType of the current node.
- void SetNode(QualType FromType, QualType ToType) {
- FlatTree[CurrentNode].FromType = FromType;
- FlatTree[CurrentNode].ToType = ToType;
+ void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Type;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromType;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToType;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Set FromExpr and ToExpr of the current node.
- void SetNode(Expr *FromExpr, Expr *ToExpr) {
- FlatTree[CurrentNode].FromExpr = FromExpr;
- FlatTree[CurrentNode].ToExpr = ToExpr;
+ void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Expression;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Set FromInt and ToInt of the current node.
- void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt) {
- FlatTree[CurrentNode].FromInt = FromInt;
- FlatTree[CurrentNode].ToInt = ToInt;
- FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt;
- FlatTree[CurrentNode].IsValidToInt = IsValidToInt;
+ void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
+ bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = TemplateTemplate;
+ FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
+ FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Set FromQual and ToQual of the current node.
- void SetNode(Qualifiers FromQual, Qualifiers ToQual) {
- FlatTree[CurrentNode].FromQual = FromQual;
- FlatTree[CurrentNode].ToQual = ToQual;
+ void SetIntegerDiff(llvm::APSInt FromInt, llvm::APSInt ToInt,
+ bool IsValidFromInt, bool IsValidToInt,
+ QualType FromIntType, QualType ToIntType,
+ Expr *FromExpr, Expr *ToExpr, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Integer;
+ FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
+ FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
+ FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
+ FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Set FromValueDecl and ToValueDecl of the current node.
- void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromAddressOf, bool ToAddressOf) {
- FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
- FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
- FlatTree[CurrentNode].FromAddressOf = FromAddressOf;
- FlatTree[CurrentNode].ToAddressOf = ToAddressOf;
+ void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromAddressOf, bool ToAddressOf,
+ bool FromNullPtr, bool ToNullPtr, Expr *FromExpr,
+ Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Declaration;
+ FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
+ FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
+ FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
+ FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
+ FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetFromDeclarationAndToIntegerDiff(
+ ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr,
+ Expr *FromExpr, llvm::APSInt ToInt, bool IsValidToInt,
+ QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger;
+ FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
+ FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
+ FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetFromIntegerAndToDeclarationDiff(
+ llvm::APSInt FromInt, bool IsValidFromInt, QualType FromIntType,
+ Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf,
+ bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration;
+ FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
+ FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
+ FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
+ FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ /// SetDefault - Sets FromDefault and ToDefault flags of the current node.
+ void SetDefault(bool FromDefault, bool ToDefault) {
+ assert((!FromDefault || !ToDefault) && "Both arguments cannot be default.");
+ FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault;
+ FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault;
}
/// SetSame - Sets the same flag of the current node.
@@ -636,18 +697,6 @@
FlatTree[CurrentNode].Same = Same;
}
- /// SetNullPtr - Sets the NullPtr flags of the current node.
- void SetNullPtr(bool FromNullPtr, bool ToNullPtr) {
- FlatTree[CurrentNode].FromNullPtr = FromNullPtr;
- FlatTree[CurrentNode].ToNullPtr = ToNullPtr;
- }
-
- /// SetDefault - Sets FromDefault and ToDefault flags of the current node.
- void SetDefault(bool FromDefault, bool ToDefault) {
- FlatTree[CurrentNode].FromDefault = FromDefault;
- FlatTree[CurrentNode].ToDefault = ToDefault;
- }
-
/// SetKind - Sets the current node's type.
void SetKind(DiffKind Kind) {
FlatTree[CurrentNode].Kind = Kind;
@@ -655,12 +704,16 @@
/// Up - Changes the node to the parent of the current node.
void Up() {
+ assert(FlatTree[CurrentNode].Kind != Invalid &&
+ "Cannot exit node before setting node information.");
CurrentNode = FlatTree[CurrentNode].ParentNode;
}
/// AddNode - Adds a child node to the current node, then sets that node
/// node as the current node.
void AddNode() {
+ assert(FlatTree[CurrentNode].Kind == Template &&
+ "Only Template nodes can have children nodes.");
FlatTree.push_back(DiffNode(CurrentNode));
DiffNode &Node = FlatTree[CurrentNode];
if (Node.ChildNode == 0) {
@@ -692,46 +745,103 @@
ReadNode = FlatTree[ReadNode].ParentNode;
}
- /// GetNode - Gets the FromType and ToType.
- void GetNode(QualType &FromType, QualType &ToType) {
- FromType = FlatTree[ReadNode].FromType;
- ToType = FlatTree[ReadNode].ToType;
+ void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD,
+ Qualifiers &FromQual, Qualifiers &ToQual) {
+ assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind.");
+ FromTD = FlatTree[ReadNode].FromArgInfo.TD;
+ ToTD = FlatTree[ReadNode].ToArgInfo.TD;
+ FromQual = FlatTree[ReadNode].FromArgInfo.Qual;
+ ToQual = FlatTree[ReadNode].ToArgInfo.Qual;
}
- /// GetNode - Gets the FromExpr and ToExpr.
- void GetNode(Expr *&FromExpr, Expr *&ToExpr) {
- FromExpr = FlatTree[ReadNode].FromExpr;
- ToExpr = FlatTree[ReadNode].ToExpr;
+ void GetTypeDiff(QualType &FromType, QualType &ToType) {
+ assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind");
+ FromType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ ToType = FlatTree[ReadNode].ToArgInfo.ArgType;
}
- /// GetNode - Gets the FromTD and ToTD.
- void GetNode(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
- FromTD = FlatTree[ReadNode].FromTD;
- ToTD = FlatTree[ReadNode].ToTD;
+ void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind");
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
- /// GetNode - Gets the FromInt and ToInt.
- void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
- bool &IsValidFromInt, bool &IsValidToInt) {
- FromInt = FlatTree[ReadNode].FromInt;
- ToInt = FlatTree[ReadNode].ToInt;
- IsValidFromInt = FlatTree[ReadNode].IsValidFromInt;
- IsValidToInt = FlatTree[ReadNode].IsValidToInt;
+ void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
+ assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind.");
+ FromTD = FlatTree[ReadNode].FromArgInfo.TD;
+ ToTD = FlatTree[ReadNode].ToArgInfo.TD;
}
- /// GetNode - Gets the FromQual and ToQual.
- void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) {
- FromQual = FlatTree[ReadNode].FromQual;
- ToQual = FlatTree[ReadNode].ToQual;
+ void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
+ bool &IsValidFromInt, bool &IsValidToInt,
+ QualType &FromIntType, QualType &ToIntType,
+ Expr *&FromExpr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind.");
+ FromInt = FlatTree[ReadNode].FromArgInfo.Val;
+ ToInt = FlatTree[ReadNode].ToArgInfo.Val;
+ IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
+ IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
+ FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
- /// GetNode - Gets the FromValueDecl and ToValueDecl.
- void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
- bool &FromAddressOf, bool &ToAddressOf) {
- FromValueDecl = FlatTree[ReadNode].FromValueDecl;
- ToValueDecl = FlatTree[ReadNode].ToValueDecl;
- FromAddressOf = FlatTree[ReadNode].FromAddressOf;
- ToAddressOf = FlatTree[ReadNode].ToAddressOf;
+ void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
+ bool &FromAddressOf, bool &ToAddressOf,
+ bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr,
+ Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind.");
+ FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
+ ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
+ FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
+ ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
+ FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
+ ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetFromDeclarationAndToIntegerDiff(
+ ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr,
+ Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt,
+ QualType &ToIntType, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger &&
+ "Unexpected kind.");
+ FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
+ FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
+ FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToInt = FlatTree[ReadNode].ToArgInfo.Val;
+ IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
+ ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetFromIntegerAndToDeclarationDiff(
+ llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType,
+ Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf,
+ bool &ToNullPtr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration &&
+ "Unexpected kind.");
+ FromInt = FlatTree[ReadNode].FromArgInfo.Val;
+ IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
+ FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
+ ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
+ ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ /// FromDefault - Return true if the from argument is the default.
+ bool FromDefault() {
+ return FlatTree[ReadNode].FromArgInfo.IsDefault;
+ }
+
+ /// ToDefault - Return true if the to argument is the default.
+ bool ToDefault() {
+ return FlatTree[ReadNode].ToArgInfo.IsDefault;
}
/// NodeIsSame - Returns true the arguments are the same.
@@ -764,26 +874,6 @@
return FlatTree[ReadNode].NextNode != 0;
}
- /// FromNullPtr - Returns true if the from argument is null.
- bool FromNullPtr() {
- return FlatTree[ReadNode].FromNullPtr;
- }
-
- /// ToNullPtr - Returns true if the to argument is null.
- bool ToNullPtr() {
- return FlatTree[ReadNode].ToNullPtr;
- }
-
- /// FromDefault - Return true if the from argument is the default.
- bool FromDefault() {
- return FlatTree[ReadNode].FromDefault;
- }
-
- /// ToDefault - Return true if the to argument is the default.
- bool ToDefault() {
- return FlatTree[ReadNode].ToDefault;
- }
-
/// Empty - Returns true if the tree has no information.
bool Empty() {
return GetKind() == Invalid;
@@ -797,102 +887,128 @@
DiffTree Tree;
- /// TSTiterator - an iterator that is used to enter a
- /// TemplateSpecializationType and read TemplateArguments inside template
- /// parameter packs in order with the rest of the TemplateArguments.
- struct TSTiterator {
+ /// TSTiterator - a pair of iterators that walks the
+ /// TemplateSpecializationType and the desugared TemplateSpecializationType.
+ /// The deseguared TemplateArgument should provide the canonical argument
+ /// for comparisons.
+ class TSTiterator {
typedef const TemplateArgument& reference;
typedef const TemplateArgument* pointer;
- /// TST - the template specialization whose arguments this iterator
- /// traverse over.
- const TemplateSpecializationType *TST;
+ /// InternalIterator - an iterator that is used to enter a
+ /// TemplateSpecializationType and read TemplateArguments inside template
+ /// parameter packs in order with the rest of the TemplateArguments.
+ struct InternalIterator {
+ /// TST - the template specialization whose arguments this iterator
+ /// traverse over.
+ const TemplateSpecializationType *TST;
- /// DesugarTST - desugared template specialization used to extract
- /// default argument information
- const TemplateSpecializationType *DesugarTST;
+ /// Index - the index of the template argument in TST.
+ unsigned Index;
- /// Index - the index of the template argument in TST.
- unsigned Index;
+ /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA
+ /// points to a TemplateArgument within a parameter pack.
+ TemplateArgument::pack_iterator CurrentTA;
- /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA
- /// points to a TemplateArgument within a parameter pack.
- TemplateArgument::pack_iterator CurrentTA;
+ /// EndTA - the end iterator of a parameter pack
+ TemplateArgument::pack_iterator EndTA;
- /// EndTA - the end iterator of a parameter pack
- TemplateArgument::pack_iterator EndTA;
+ /// InternalIterator - Constructs an iterator and sets it to the first
+ /// template argument.
+ InternalIterator(const TemplateSpecializationType *TST)
+ : TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) {
+ if (isEnd()) return;
- /// TSTiterator - Constructs an iterator and sets it to the first template
- /// argument.
- TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
- : TST(TST),
- DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
- Index(0), CurrentTA(nullptr), EndTA(nullptr) {
- if (isEnd()) return;
+ // Set to first template argument. If not a parameter pack, done.
+ TemplateArgument TA = TST->getArg(0);
+ if (TA.getKind() != TemplateArgument::Pack) return;
- // Set to first template argument. If not a parameter pack, done.
- TemplateArgument TA = TST->getArg(0);
- if (TA.getKind() != TemplateArgument::Pack) return;
-
- // Start looking into the parameter pack.
- CurrentTA = TA.pack_begin();
- EndTA = TA.pack_end();
-
- // Found a valid template argument.
- if (CurrentTA != EndTA) return;
-
- // Parameter pack is empty, use the increment to get to a valid
- // template argument.
- ++(*this);
- }
-
- /// isEnd - Returns true if the iterator is one past the end.
- bool isEnd() const {
- return Index >= TST->getNumArgs();
- }
-
- /// &operator++ - Increment the iterator to the next template argument.
- TSTiterator &operator++() {
- // After the end, Index should be the default argument position in
- // DesugarTST, if it exists.
- if (isEnd()) {
- ++Index;
- return *this;
- }
-
- // If in a parameter pack, advance in the parameter pack.
- if (CurrentTA != EndTA) {
- ++CurrentTA;
- if (CurrentTA != EndTA)
- return *this;
- }
-
- // Loop until a template argument is found, or the end is reached.
- while (true) {
- // Advance to the next template argument. Break if reached the end.
- if (++Index == TST->getNumArgs()) break;
-
- // If the TemplateArgument is not a parameter pack, done.
- TemplateArgument TA = TST->getArg(Index);
- if (TA.getKind() != TemplateArgument::Pack) break;
-
- // Handle parameter packs.
+ // Start looking into the parameter pack.
CurrentTA = TA.pack_begin();
EndTA = TA.pack_end();
- // If the parameter pack is empty, try to advance again.
- if (CurrentTA != EndTA) break;
+ // Found a valid template argument.
+ if (CurrentTA != EndTA) return;
+
+ // Parameter pack is empty, use the increment to get to a valid
+ // template argument.
+ ++(*this);
}
+
+ /// isEnd - Returns true if the iterator is one past the end.
+ bool isEnd() const {
+ return Index >= TST->getNumArgs();
+ }
+
+ /// &operator++ - Increment the iterator to the next template argument.
+ InternalIterator &operator++() {
+ if (isEnd()) {
+ return *this;
+ }
+
+ // If in a parameter pack, advance in the parameter pack.
+ if (CurrentTA != EndTA) {
+ ++CurrentTA;
+ if (CurrentTA != EndTA)
+ return *this;
+ }
+
+ // Loop until a template argument is found, or the end is reached.
+ while (true) {
+ // Advance to the next template argument. Break if reached the end.
+ if (++Index == TST->getNumArgs())
+ break;
+
+ // If the TemplateArgument is not a parameter pack, done.
+ TemplateArgument TA = TST->getArg(Index);
+ if (TA.getKind() != TemplateArgument::Pack)
+ break;
+
+ // Handle parameter packs.
+ CurrentTA = TA.pack_begin();
+ EndTA = TA.pack_end();
+
+ // If the parameter pack is empty, try to advance again.
+ if (CurrentTA != EndTA)
+ break;
+ }
+ return *this;
+ }
+
+ /// operator* - Returns the appropriate TemplateArgument.
+ reference operator*() const {
+ assert(!isEnd() && "Index exceeds number of arguments.");
+ if (CurrentTA == EndTA)
+ return TST->getArg(Index);
+ else
+ return *CurrentTA;
+ }
+
+ /// operator-> - Allow access to the underlying TemplateArgument.
+ pointer operator->() const {
+ return &operator*();
+ }
+ };
+
+ InternalIterator SugaredIterator;
+ InternalIterator DesugaredIterator;
+
+ public:
+ TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
+ : SugaredIterator(TST),
+ DesugaredIterator(
+ GetTemplateSpecializationType(Context, TST->desugar())) {}
+
+ /// &operator++ - Increment the iterator to the next template argument.
+ TSTiterator &operator++() {
+ ++SugaredIterator;
+ ++DesugaredIterator;
return *this;
}
/// operator* - Returns the appropriate TemplateArgument.
reference operator*() const {
- assert(!isEnd() && "Index exceeds number of arguments.");
- if (CurrentTA == EndTA)
- return TST->getArg(Index);
- else
- return *CurrentTA;
+ return *SugaredIterator;
}
/// operator-> - Allow access to the underlying TemplateArgument.
@@ -900,16 +1016,27 @@
return &operator*();
}
- /// getDesugar - Returns the deduced template argument from DesguarTST
- reference getDesugar() const {
- return DesugarTST->getArg(Index);
+ /// isEnd - Returns true if no more TemplateArguments are available.
+ bool isEnd() const {
+ return SugaredIterator.isEnd();
+ }
+
+ /// hasDesugaredTA - Returns true if there is another TemplateArgument
+ /// available.
+ bool hasDesugaredTA() const {
+ return !DesugaredIterator.isEnd();
+ }
+
+ /// getDesugaredTA - Returns the desugared TemplateArgument.
+ reference getDesugaredTA() const {
+ return *DesugaredIterator;
}
};
// These functions build up the template diff tree, including functions to
- // retrieve and compare template arguments.
+ // retrieve and compare template arguments.
- static const TemplateSpecializationType * GetTemplateSpecializationType(
+ static const TemplateSpecializationType *GetTemplateSpecializationType(
ASTContext &Context, QualType Ty) {
if (const TemplateSpecializationType *TST =
Ty->getAs<TemplateSpecializationType>())
@@ -935,108 +1062,136 @@
return Ty->getAs<TemplateSpecializationType>();
}
- /// DiffTypes - Fills a DiffNode with information about a type difference.
- void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter,
- TemplateTypeParmDecl *FromDefaultTypeDecl,
- TemplateTypeParmDecl *ToDefaultTypeDecl) {
- QualType FromType = GetType(FromIter, FromDefaultTypeDecl);
- QualType ToType = GetType(ToIter, ToDefaultTypeDecl);
-
- Tree.SetNode(FromType, ToType);
- Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
- ToIter.isEnd() && !ToType.isNull());
- Tree.SetKind(DiffTree::Type);
+ /// Returns true if the DiffType is Type and false for Template.
+ static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType,
+ QualType ToType,
+ const TemplateSpecializationType *&FromArgTST,
+ const TemplateSpecializationType *&ToArgTST) {
if (FromType.isNull() || ToType.isNull())
- return;
+ return true;
- if (Context.hasSameType(FromType, ToType)) {
- Tree.SetSame(true);
- return;
- }
+ if (Context.hasSameType(FromType, ToType))
+ return true;
- const TemplateSpecializationType *FromArgTST =
- GetTemplateSpecializationType(Context, FromType);
- if (!FromArgTST)
- return;
+ FromArgTST = GetTemplateSpecializationType(Context, FromType);
+ ToArgTST = GetTemplateSpecializationType(Context, ToType);
- const TemplateSpecializationType *ToArgTST =
- GetTemplateSpecializationType(Context, ToType);
- if (!ToArgTST)
- return;
+ if (!FromArgTST || !ToArgTST)
+ return true;
if (!hasSameTemplate(FromArgTST, ToArgTST))
- return;
+ return true;
- Qualifiers FromQual = FromType.getQualifiers(),
- ToQual = ToType.getQualifiers();
- FromQual -= QualType(FromArgTST, 0).getQualifiers();
- ToQual -= QualType(ToArgTST, 0).getQualifiers();
- Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
- ToArgTST->getTemplateName().getAsTemplateDecl());
- Tree.SetNode(FromQual, ToQual);
- Tree.SetKind(DiffTree::Template);
- DiffTemplate(FromArgTST, ToArgTST);
+ return false;
+ }
+
+ /// DiffTypes - Fills a DiffNode with information about a type difference.
+ void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) {
+ QualType FromType = GetType(FromIter);
+ QualType ToType = GetType(ToIter);
+
+ bool FromDefault = FromIter.isEnd() && !FromType.isNull();
+ bool ToDefault = ToIter.isEnd() && !ToType.isNull();
+
+ const TemplateSpecializationType *FromArgTST = nullptr;
+ const TemplateSpecializationType *ToArgTST = nullptr;
+ if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) {
+ Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault);
+ Tree.SetSame(!FromType.isNull() && !ToType.isNull() &&
+ Context.hasSameType(FromType, ToType));
+ } else {
+ assert(FromArgTST && ToArgTST &&
+ "Both template specializations need to be valid.");
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
+ FromQual -= QualType(FromArgTST, 0).getQualifiers();
+ ToQual -= QualType(ToArgTST, 0).getQualifiers();
+ Tree.SetTemplateDiff(FromArgTST->getTemplateName().getAsTemplateDecl(),
+ ToArgTST->getTemplateName().getAsTemplateDecl(),
+ FromQual, ToQual, FromDefault, ToDefault);
+ DiffTemplate(FromArgTST, ToArgTST);
+ }
}
/// DiffTemplateTemplates - Fills a DiffNode with information about a
/// template template difference.
void DiffTemplateTemplates(const TSTiterator &FromIter,
- const TSTiterator &ToIter,
- TemplateTemplateParmDecl *FromDefaultTemplateDecl,
- TemplateTemplateParmDecl *ToDefaultTemplateDecl) {
- TemplateDecl *FromDecl = GetTemplateDecl(FromIter, FromDefaultTemplateDecl);
- TemplateDecl *ToDecl = GetTemplateDecl(ToIter, ToDefaultTemplateDecl);
- Tree.SetNode(FromDecl, ToDecl);
+ const TSTiterator &ToIter) {
+ TemplateDecl *FromDecl = GetTemplateDecl(FromIter);
+ TemplateDecl *ToDecl = GetTemplateDecl(ToIter);
+ Tree.SetTemplateTemplateDiff(FromDecl, ToDecl, FromIter.isEnd() && FromDecl,
+ ToIter.isEnd() && ToDecl);
Tree.SetSame(FromDecl && ToDecl &&
FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl);
- Tree.SetKind(DiffTree::TemplateTemplate);
}
/// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes
- static void InitializeNonTypeDiffVariables(
- ASTContext &Context, const TSTiterator &Iter,
- NonTypeTemplateParmDecl *Default, bool &HasInt, bool &HasValueDecl,
- bool &IsNullPtr, Expr *&E, llvm::APSInt &Value, ValueDecl *&VD) {
- HasInt = !Iter.isEnd() && Iter->getKind() == TemplateArgument::Integral;
-
- HasValueDecl =
- !Iter.isEnd() && Iter->getKind() == TemplateArgument::Declaration;
-
- IsNullPtr = !Iter.isEnd() && Iter->getKind() == TemplateArgument::NullPtr;
-
- if (HasInt)
- Value = Iter->getAsIntegral();
- else if (HasValueDecl)
- VD = Iter->getAsDecl();
- else if (!IsNullPtr)
- E = GetExpr(Iter, Default);
-
- if (E && Default->getType()->isPointerType())
- IsNullPtr = CheckForNullPtr(Context, E);
- }
-
- /// NeedsAddressOf - Helper function for DiffNonTypes. Returns true if the
- /// ValueDecl needs a '&' when printed.
- static bool NeedsAddressOf(ValueDecl *VD, Expr *E,
- NonTypeTemplateParmDecl *Default) {
- if (!VD)
- return false;
-
- if (E) {
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
- if (UO->getOpcode() == UO_AddrOf) {
- return true;
+ static void InitializeNonTypeDiffVariables(ASTContext &Context,
+ const TSTiterator &Iter,
+ NonTypeTemplateParmDecl *Default,
+ llvm::APSInt &Value, bool &HasInt,
+ QualType &IntType, bool &IsNullPtr,
+ Expr *&E, ValueDecl *&VD,
+ bool &NeedAddressOf) {
+ if (!Iter.isEnd()) {
+ switch (Iter->getKind()) {
+ default:
+ llvm_unreachable("unknown ArgumentKind");
+ case TemplateArgument::Integral:
+ Value = Iter->getAsIntegral();
+ HasInt = true;
+ IntType = Iter->getIntegralType();
+ return;
+ case TemplateArgument::Declaration: {
+ VD = Iter->getAsDecl();
+ QualType ArgType = Iter->getParamTypeForDecl();
+ QualType VDType = VD->getType();
+ if (ArgType->isPointerType() &&
+ Context.hasSameType(ArgType->getPointeeType(), VDType))
+ NeedAddressOf = true;
+ return;
}
+ case TemplateArgument::NullPtr:
+ IsNullPtr = true;
+ return;
+ case TemplateArgument::Expression:
+ E = Iter->getAsExpr();
}
- return false;
+ } else if (!Default->isParameterPack()) {
+ E = Default->getDefaultArgument();
}
- if (!Default->getType()->isReferenceType()) {
- return true;
- }
+ if (!Iter.hasDesugaredTA()) return;
- return false;
+ const TemplateArgument& TA = Iter.getDesugaredTA();
+ switch (TA.getKind()) {
+ default:
+ llvm_unreachable("unknown ArgumentKind");
+ case TemplateArgument::Integral:
+ Value = TA.getAsIntegral();
+ HasInt = true;
+ IntType = TA.getIntegralType();
+ return;
+ case TemplateArgument::Declaration: {
+ VD = TA.getAsDecl();
+ QualType ArgType = TA.getParamTypeForDecl();
+ QualType VDType = VD->getType();
+ if (ArgType->isPointerType() &&
+ Context.hasSameType(ArgType->getPointeeType(), VDType))
+ NeedAddressOf = true;
+ return;
+ }
+ case TemplateArgument::NullPtr:
+ IsNullPtr = true;
+ return;
+ case TemplateArgument::Expression:
+ // TODO: Sometimes, the desugared template argument Expr differs from
+ // the sugared template argument Expr. It may be useful in the future
+ // but for now, it is just discarded.
+ if (!E)
+ E = TA.getAsExpr();
+ return;
+ }
}
/// DiffNonTypes - Handles any template parameters not handled by DiffTypes
@@ -1046,85 +1201,68 @@
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) {
Expr *FromExpr = nullptr, *ToExpr = nullptr;
llvm::APSInt FromInt, ToInt;
+ QualType FromIntType, ToIntType;
ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
- bool HasFromInt = false, HasToInt = false, HasFromValueDecl = false,
- HasToValueDecl = false, FromNullPtr = false, ToNullPtr = false;
- InitializeNonTypeDiffVariables(Context, FromIter, FromDefaultNonTypeDecl,
- HasFromInt, HasFromValueDecl, FromNullPtr,
- FromExpr, FromInt, FromValueDecl);
- InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl,
- HasToInt, HasToValueDecl, ToNullPtr,
- ToExpr, ToInt, ToValueDecl);
+ bool HasFromInt = false, HasToInt = false, FromNullPtr = false,
+ ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false;
+ InitializeNonTypeDiffVariables(
+ Context, FromIter, FromDefaultNonTypeDecl, FromInt, HasFromInt,
+ FromIntType, FromNullPtr, FromExpr, FromValueDecl, NeedFromAddressOf);
+ InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl, ToInt,
+ HasToInt, ToIntType, ToNullPtr, ToExpr,
+ ToValueDecl, NeedToAddressOf);
- assert(((!HasFromInt && !HasToInt) ||
- (!HasFromValueDecl && !HasToValueDecl)) &&
- "Template argument cannot be both integer and declaration");
+ bool FromDefault = FromIter.isEnd() &&
+ (FromExpr || FromValueDecl || HasFromInt || FromNullPtr);
+ bool ToDefault = ToIter.isEnd() &&
+ (ToExpr || ToValueDecl || HasToInt || ToNullPtr);
- if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
- Tree.SetNode(FromExpr, ToExpr);
- Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr);
- if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType()) {
- if (FromExpr)
- HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt,
- FromDefaultNonTypeDecl->getType());
- if (ToExpr)
- HasToInt = GetInt(Context, ToIter, ToExpr, ToInt,
- ToDefaultNonTypeDecl->getType());
- }
- if (HasFromInt && HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(FromInt == ToInt);
- Tree.SetKind(DiffTree::Integer);
- } else if (HasFromInt || HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(false);
- Tree.SetKind(DiffTree::Integer);
- } else {
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr) ||
- (FromNullPtr && ToNullPtr));
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetKind(DiffTree::Expression);
- }
+ bool FromDeclaration = FromValueDecl || FromNullPtr;
+ bool ToDeclaration = ToValueDecl || ToNullPtr;
+
+ if (FromDeclaration && HasToInt) {
+ Tree.SetFromDeclarationAndToIntegerDiff(
+ FromValueDecl, NeedFromAddressOf, FromNullPtr, FromExpr, ToInt,
+ HasToInt, ToIntType, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(false);
+ return;
+
+ }
+
+ if (HasFromInt && ToDeclaration) {
+ Tree.SetFromIntegerAndToDeclarationDiff(
+ FromInt, HasFromInt, FromIntType, FromExpr, ToValueDecl,
+ NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(false);
return;
}
if (HasFromInt || HasToInt) {
- if (!HasFromInt && FromExpr)
- HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt,
- FromDefaultNonTypeDecl->getType());
- if (!HasToInt && ToExpr)
- HasToInt = GetInt(Context, ToIter, ToExpr, ToInt,
- ToDefaultNonTypeDecl->getType());
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetIntegerDiff(FromInt, ToInt, HasFromInt, HasToInt, FromIntType,
+ ToIntType, FromExpr, ToExpr, FromDefault, ToDefault);
if (HasFromInt && HasToInt) {
- Tree.SetSame(FromInt == ToInt);
- } else {
- Tree.SetSame(false);
+ Tree.SetSame(Context.hasSameType(FromIntType, ToIntType) &&
+ FromInt == ToInt);
}
- Tree.SetDefault(FromIter.isEnd() && HasFromInt,
- ToIter.isEnd() && HasToInt);
- Tree.SetKind(DiffTree::Integer);
return;
}
- if (!HasFromValueDecl && FromExpr)
- FromValueDecl = GetValueDecl(FromIter, FromExpr);
- if (!HasToValueDecl && ToExpr)
- ToValueDecl = GetValueDecl(ToIter, ToExpr);
+ if (FromDeclaration || ToDeclaration) {
+ Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, NeedFromAddressOf,
+ NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
+ ToExpr, FromDefault, ToDefault);
+ bool BothNull = FromNullPtr && ToNullPtr;
+ bool SameValueDecl =
+ FromValueDecl && ToValueDecl &&
+ NeedFromAddressOf == NeedToAddressOf &&
+ FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl();
+ Tree.SetSame(BothNull || SameValueDecl);
+ return;
+ }
- bool FromAddressOf =
- NeedsAddressOf(FromValueDecl, FromExpr, FromDefaultNonTypeDecl);
- bool ToAddressOf =
- NeedsAddressOf(ToValueDecl, ToExpr, ToDefaultNonTypeDecl);
-
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
- Tree.SetSame(FromValueDecl && ToValueDecl &&
- FromValueDecl->getCanonicalDecl() ==
- ToValueDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
- ToIter.isEnd() && ToValueDecl);
- Tree.SetKind(DiffTree::Declaration);
+ assert((FromExpr || ToExpr) && "Both template arguments cannot be empty.");
+ Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
}
/// DiffTemplate - recursively visits template arguments and stores the
@@ -1149,28 +1287,23 @@
NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex);
NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex);
- TemplateTypeParmDecl *FromDefaultTypeDecl =
- dyn_cast<TemplateTypeParmDecl>(FromParamND);
- TemplateTypeParmDecl *ToDefaultTypeDecl =
- dyn_cast<TemplateTypeParmDecl>(ToParamND);
- if (FromDefaultTypeDecl && ToDefaultTypeDecl)
- DiffTypes(FromIter, ToIter, FromDefaultTypeDecl, ToDefaultTypeDecl);
+ assert(FromParamND->getKind() == ToParamND->getKind() &&
+ "Parameter Decl are not the same kind.");
- TemplateTemplateParmDecl *FromDefaultTemplateDecl =
- dyn_cast<TemplateTemplateParmDecl>(FromParamND);
- TemplateTemplateParmDecl *ToDefaultTemplateDecl =
- dyn_cast<TemplateTemplateParmDecl>(ToParamND);
- if (FromDefaultTemplateDecl && ToDefaultTemplateDecl)
- DiffTemplateTemplates(FromIter, ToIter, FromDefaultTemplateDecl,
- ToDefaultTemplateDecl);
-
- NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
- dyn_cast<NonTypeTemplateParmDecl>(FromParamND);
- NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
- dyn_cast<NonTypeTemplateParmDecl>(ToParamND);
- if (FromDefaultNonTypeDecl && ToDefaultNonTypeDecl)
+ if (isa<TemplateTypeParmDecl>(FromParamND)) {
+ DiffTypes(FromIter, ToIter);
+ } else if (isa<TemplateTemplateParmDecl>(FromParamND)) {
+ DiffTemplateTemplates(FromIter, ToIter);
+ } else if (isa<NonTypeTemplateParmDecl>(FromParamND)) {
+ NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
+ cast<NonTypeTemplateParmDecl>(FromParamND);
+ NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
+ cast<NonTypeTemplateParmDecl>(ToParamND);
DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl,
ToDefaultNonTypeDecl);
+ } else {
+ llvm_unreachable("Unexpected Decl type.");
+ }
++FromIter;
++ToIter;
@@ -1239,140 +1372,27 @@
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- static QualType GetType(const TSTiterator &Iter,
- TemplateTypeParmDecl *DefaultTTPD) {
- bool isVariadic = DefaultTTPD->isParameterPack();
-
+ static QualType GetType(const TSTiterator &Iter) {
if (!Iter.isEnd())
return Iter->getAsType();
- if (isVariadic)
- return QualType();
-
- QualType ArgType = DefaultTTPD->getDefaultArgument();
- if (ArgType->isDependentType())
- return Iter.getDesugar().getAsType();
-
- return ArgType;
- }
-
- /// GetExpr - Retrieves the template expression argument, including default
- /// arguments.
- static Expr *GetExpr(const TSTiterator &Iter,
- NonTypeTemplateParmDecl *DefaultNTTPD) {
- Expr *ArgExpr = nullptr;
- bool isVariadic = DefaultNTTPD->isParameterPack();
-
- if (!Iter.isEnd())
- ArgExpr = Iter->getAsExpr();
- else if (!isVariadic)
- ArgExpr = DefaultNTTPD->getDefaultArgument();
-
- if (ArgExpr)
- while (SubstNonTypeTemplateParmExpr *SNTTPE =
- dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))
- ArgExpr = SNTTPE->getReplacement();
-
- return ArgExpr;
- }
-
- /// GetInt - Retrieves the template integer argument, including evaluating
- /// default arguments. If the value comes from an expression, extend the
- /// APSInt to size of IntegerType to match the behavior in
- /// Sema::CheckTemplateArgument
- static bool GetInt(ASTContext &Context, const TSTiterator &Iter,
- Expr *ArgExpr, llvm::APSInt &Int, QualType IntegerType) {
- // Default, value-depenedent expressions require fetching
- // from the desugared TemplateArgument, otherwise expression needs to
- // be evaluatable.
- if (Iter.isEnd() && ArgExpr->isValueDependent()) {
- switch (Iter.getDesugar().getKind()) {
- case TemplateArgument::Integral:
- Int = Iter.getDesugar().getAsIntegral();
- return true;
- case TemplateArgument::Expression:
- ArgExpr = Iter.getDesugar().getAsExpr();
- Int = ArgExpr->EvaluateKnownConstInt(Context);
- Int = Int.extOrTrunc(Context.getTypeSize(IntegerType));
- return true;
- default:
- llvm_unreachable("Unexpected template argument kind");
- }
- } else if (ArgExpr->isEvaluatable(Context)) {
- Int = ArgExpr->EvaluateKnownConstInt(Context);
- Int = Int.extOrTrunc(Context.getTypeSize(IntegerType));
- return true;
- }
-
- return false;
- }
-
- /// GetValueDecl - Retrieves the template Decl argument, including
- /// default expression argument.
- static ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
- // Default, value-depenedent expressions require fetching
- // from the desugared TemplateArgument
- if (Iter.isEnd() && ArgExpr->isValueDependent())
- switch (Iter.getDesugar().getKind()) {
- case TemplateArgument::Declaration:
- return Iter.getDesugar().getAsDecl();
- case TemplateArgument::Expression:
- ArgExpr = Iter.getDesugar().getAsExpr();
- return cast<DeclRefExpr>(ArgExpr)->getDecl();
- default:
- llvm_unreachable("Unexpected template argument kind");
- }
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
- if (!DRE) {
- UnaryOperator *UO = dyn_cast<UnaryOperator>(ArgExpr->IgnoreParens());
- if (!UO)
- return nullptr;
- DRE = cast<DeclRefExpr>(UO->getSubExpr());
- }
-
- return DRE->getDecl();
- }
-
- /// CheckForNullPtr - returns true if the expression can be evaluated as
- /// a null pointer
- static bool CheckForNullPtr(ASTContext &Context, Expr *E) {
- assert(E && "Expected expression");
-
- E = E->IgnoreParenCasts();
- if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
- return true;
-
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
- if (!DRE)
- return false;
-
- VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
- if (!VD || !VD->hasInit())
- return false;
-
- return VD->getInit()->IgnoreParenCasts()->isNullPointerConstant(
- Context, Expr::NPC_ValueDependentIsNull);
+ if (Iter.hasDesugaredTA())
+ return Iter.getDesugaredTA().getAsType();
+ return QualType();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
- TemplateTemplateParmDecl *DefaultTTPD) {
- bool isVariadic = DefaultTTPD->isParameterPack();
-
- TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
- TemplateDecl *DefaultTD = nullptr;
- if (TA.getKind() != TemplateArgument::Null)
- DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
-
+ static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) {
if (!Iter.isEnd())
return Iter->getAsTemplate().getAsTemplateDecl();
- if (!isVariadic)
- return DefaultTD;
-
+ if (Iter.hasDesugaredTA())
+ return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl();
return nullptr;
}
- /// IsEqualExpr - Returns true if the expressions evaluate to the same value.
+ /// IsEqualExpr - Returns true if the expressions are the same in regards to
+ /// template arguments. These expressions are dependent, so profile them
+ /// instead of trying to evaluate them.
static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
if (FromExpr == ToExpr)
return true;
@@ -1380,47 +1400,10 @@
if (!FromExpr || !ToExpr)
return false;
- DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr->IgnoreParens()),
- *ToDRE = dyn_cast<DeclRefExpr>(ToExpr->IgnoreParens());
-
- if (FromDRE || ToDRE) {
- if (!FromDRE || !ToDRE)
- return false;
- return FromDRE->getDecl() == ToDRE->getDecl();
- }
-
- Expr::EvalResult FromResult, ToResult;
- if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
- !ToExpr->EvaluateAsRValue(ToResult, Context)) {
- llvm::FoldingSetNodeID FromID, ToID;
- FromExpr->Profile(FromID, Context, true);
- ToExpr->Profile(ToID, Context, true);
- return FromID == ToID;
- }
-
- APValue &FromVal = FromResult.Val;
- APValue &ToVal = ToResult.Val;
-
- if (FromVal.getKind() != ToVal.getKind()) return false;
-
- switch (FromVal.getKind()) {
- case APValue::Int:
- return FromVal.getInt() == ToVal.getInt();
- case APValue::LValue: {
- APValue::LValueBase FromBase = FromVal.getLValueBase();
- APValue::LValueBase ToBase = ToVal.getLValueBase();
- if (FromBase.isNull() && ToBase.isNull())
- return true;
- if (FromBase.isNull() || ToBase.isNull())
- return false;
- return FromBase.get<const ValueDecl*>() ==
- ToBase.get<const ValueDecl*>();
- }
- case APValue::MemberPointer:
- return FromVal.getMemberPointerDecl() == ToVal.getMemberPointerDecl();
- default:
- llvm_unreachable("Unknown template argument expression.");
- }
+ llvm::FoldingSetNodeID FromID, ToID;
+ FromExpr->Profile(FromID, Context, true);
+ ToExpr->Profile(ToID, Context, true);
+ return FromID == ToID;
}
// These functions converts the tree representation of the template
@@ -1442,21 +1425,21 @@
llvm_unreachable("Template diffing failed with bad DiffNode");
case DiffTree::Type: {
QualType FromType, ToType;
- Tree.GetNode(FromType, ToType);
+ Tree.GetTypeDiff(FromType, ToType);
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
- Tree.GetNode(FromExpr, ToExpr);
- PrintExpr(FromExpr, ToExpr, Tree.FromNullPtr(), Tree.ToNullPtr(),
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ Tree.GetExpressionDiff(FromExpr, ToExpr);
+ PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
+ Tree.NodeIsSame());
return;
}
case DiffTree::TemplateTemplate: {
TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
+ Tree.GetTemplateTemplateDiff(FromTD, ToTD);
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
Tree.ToDefault(), Tree.NodeIsSame());
return;
@@ -1465,26 +1448,70 @@
llvm::APSInt FromInt, ToInt;
Expr *FromExpr, *ToExpr;
bool IsValidFromInt, IsValidToInt;
- Tree.GetNode(FromExpr, ToExpr);
- Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
- PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
- FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
- Tree.NodeIsSame());
+ QualType FromIntType, ToIntType;
+ Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt,
+ FromIntType, ToIntType, FromExpr, ToExpr);
+ PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType,
+ ToIntType, FromExpr, ToExpr, Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Declaration: {
ValueDecl *FromValueDecl, *ToValueDecl;
bool FromAddressOf, ToAddressOf;
- Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ bool FromNullPtr, ToNullPtr;
+ Expr *FromExpr, *ToExpr;
+ Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf,
+ ToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
+ ToExpr);
PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
- Tree.FromNullPtr(), Tree.ToNullPtr(), Tree.FromDefault(),
- Tree.ToDefault(), Tree.NodeIsSame());
+ FromNullPtr, ToNullPtr, FromExpr, ToExpr,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
+ case DiffTree::FromDeclarationAndToInteger: {
+ ValueDecl *FromValueDecl;
+ bool FromAddressOf;
+ bool FromNullPtr;
+ Expr *FromExpr;
+ llvm::APSInt ToInt;
+ bool IsValidToInt;
+ QualType ToIntType;
+ Expr *ToExpr;
+ Tree.GetFromDeclarationAndToIntegerDiff(
+ FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt,
+ IsValidToInt, ToIntType, ToExpr);
+ assert((FromValueDecl || FromNullPtr) && IsValidToInt);
+ PrintValueDeclAndInteger(FromValueDecl, FromAddressOf, FromNullPtr,
+ FromExpr, Tree.FromDefault(), ToInt, ToIntType,
+ ToExpr, Tree.ToDefault());
+ return;
+ }
+ case DiffTree::FromIntegerAndToDeclaration: {
+ llvm::APSInt FromInt;
+ bool IsValidFromInt;
+ QualType FromIntType;
+ Expr *FromExpr;
+ ValueDecl *ToValueDecl;
+ bool ToAddressOf;
+ bool ToNullPtr;
+ Expr *ToExpr;
+ Tree.GetFromIntegerAndToDeclarationDiff(
+ FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl,
+ ToAddressOf, ToNullPtr, ToExpr);
+ assert(IsValidFromInt && (ToValueDecl || ToNullPtr));
+ PrintIntegerAndValueDecl(FromInt, FromIntType, FromExpr,
+ Tree.FromDefault(), ToValueDecl, ToAddressOf,
+ ToNullPtr, ToExpr, Tree.ToDefault());
return;
}
case DiffTree::Template: {
// Node is root of template. Recurse on children.
TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
+ Qualifiers FromQual, ToQual;
+ Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual);
+
+ PrintQualifiers(FromQual, ToQual);
if (!Tree.HasChildren()) {
// If we're dealing with a template specialization with zero
@@ -1493,11 +1520,7 @@
return;
}
- Qualifiers FromQual, ToQual;
- Tree.GetNode(FromQual, ToQual);
- PrintQualifiers(FromQual, ToQual);
-
- OS << FromTD->getNameAsString() << '<';
+ OS << FromTD->getNameAsString() << '<';
Tree.MoveToChild();
unsigned NumElideArgs = 0;
do {
@@ -1604,40 +1627,36 @@
/// PrintExpr - Prints out the expr template arguments, highlighting argument
/// differences.
- void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromNullPtr,
- bool ToNullPtr, bool FromDefault, bool ToDefault, bool Same) {
+ void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault,
+ bool ToDefault, bool Same) {
assert((FromExpr || ToExpr) &&
"Only one template argument may be missing.");
if (Same) {
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- PrintExpr(ToExpr, ToNullPtr);
+ PrintExpr(ToExpr);
Unbold();
OS << ']';
}
}
/// PrintExpr - Actual formatting and printing of expressions.
- void PrintExpr(const Expr *E, bool NullPtr = false) {
+ void PrintExpr(const Expr *E) {
if (E) {
E->printPretty(OS, nullptr, Policy);
return;
}
- if (NullPtr) {
- OS << "nullptr";
- return;
- }
OS << "(no argument)";
}
@@ -1677,28 +1696,40 @@
/// PrintAPSInt - Handles printing of integral arguments, highlighting
/// argument differences.
void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr,
- Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) {
+ bool IsValidFromInt, bool IsValidToInt, QualType FromIntType,
+ QualType ToIntType, Expr *FromExpr, Expr *ToExpr,
+ bool FromDefault, bool ToDefault, bool Same) {
assert((IsValidFromInt || IsValidToInt) &&
"Only one integral argument may be missing.");
if (Same) {
- OS << FromInt.toString(10);
- } else if (!PrintTree) {
+ if (FromIntType->isBooleanType()) {
+ OS << ((FromInt == 0) ? "false" : "true");
+ } else {
+ OS << FromInt.toString(10);
+ }
+ return;
+ }
+
+ bool PrintType = IsValidFromInt && IsValidToInt &&
+ !Context.hasSameType(FromIntType, ToIntType);
+
+ if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
- PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
} else {
OS << (FromDefault ? "[(default) " : "[");
- PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
OS << " != " << (ToDefault ? "(default) " : "");
- PrintAPSInt(ToInt, ToExpr, IsValidToInt);
+ PrintAPSInt(ToInt, ToExpr, IsValidToInt, ToIntType, PrintType);
OS << ']';
}
}
/// PrintAPSInt - If valid, print the APSInt. If the expression is
/// gives more information, print it too.
- void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) {
+ void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid, QualType IntType,
+ bool PrintType) {
Bold();
if (Valid) {
if (HasExtraInfo(E)) {
@@ -1707,7 +1738,20 @@
OS << " aka ";
Bold();
}
- OS << Val.toString(10);
+ if (PrintType) {
+ Unbold();
+ OS << "(";
+ Bold();
+ IntType.print(OS, Context.getPrintingPolicy());
+ Unbold();
+ OS << ") ";
+ Bold();
+ }
+ if (IntType->isBooleanType()) {
+ OS << ((Val == 0) ? "false" : "true");
+ } else {
+ OS << Val.toString(10);
+ }
} else if (E) {
PrintExpr(E);
} else {
@@ -1716,8 +1760,8 @@
Unbold();
}
- /// HasExtraInfo - Returns true if E is not an integer literal or the
- /// negation of an integer literal
+ /// HasExtraInfo - Returns true if E is not an integer literal, the
+ /// negation of an integer literal, or a boolean literal.
bool HasExtraInfo(Expr *E) {
if (!E) return false;
@@ -1730,10 +1774,13 @@
if (isa<IntegerLiteral>(UO->getSubExpr()))
return false;
+ if (isa<CXXBoolLiteralExpr>(E))
+ return false;
+
return true;
}
- void PrintValueDecl(ValueDecl *VD, bool AddressOf, bool NullPtr) {
+ void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) {
if (VD) {
if (AddressOf)
OS << "&";
@@ -1742,6 +1789,17 @@
}
if (NullPtr) {
+ if (E && !isa<CXXNullPtrLiteralExpr>(E)) {
+ PrintExpr(E);
+ if (IsBold) {
+ Unbold();
+ OS << " aka ";
+ Bold();
+ } else {
+ OS << " aka ";
+ }
+ }
+
OS << "nullptr";
return;
}
@@ -1753,32 +1811,74 @@
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
bool FromAddressOf, bool ToAddressOf, bool FromNullPtr,
- bool ToNullPtr, bool FromDefault, bool ToDefault,
- bool Same) {
+ bool ToNullPtr, Expr *FromExpr, Expr *ToExpr,
+ bool FromDefault, bool ToDefault, bool Same) {
assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) &&
"Only one Decl argument may be NULL");
if (Same) {
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- PrintValueDecl(ToValueDecl, ToAddressOf, ToNullPtr);
+ PrintValueDecl(ToValueDecl, ToAddressOf, ToExpr, ToNullPtr);
Unbold();
OS << ']';
}
}
+ /// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and
+ /// APSInt to print a mixed difference.
+ void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf,
+ bool IsNullPtr, Expr *VDExpr, bool DefaultDecl,
+ llvm::APSInt Val, QualType IntType,
+ Expr *IntExpr, bool DefaultInt) {
+ if (!PrintTree) {
+ OS << (DefaultDecl ? "(default) " : "");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
+ Unbold();
+ } else {
+ OS << (DefaultDecl ? "[(default) " : "[");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
+ Unbold();
+ OS << " != " << (DefaultInt ? "(default) " : "");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
+ OS << ']';
+ }
+ }
+
+ /// PrintIntegerAndValueDecl - Uses the print functions for APSInt and
+ /// ValueDecl to print a mixed difference.
+ void PrintIntegerAndValueDecl(llvm::APSInt Val, QualType IntType,
+ Expr *IntExpr, bool DefaultInt, ValueDecl *VD,
+ bool NeedAddressOf, bool IsNullPtr,
+ Expr *VDExpr, bool DefaultDecl) {
+ if (!PrintTree) {
+ OS << (DefaultInt ? "(default) " : "");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
+ } else {
+ OS << (DefaultInt ? "[(default) " : "[");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
+ OS << " != " << (DefaultDecl ? "(default) " : "");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
+ Unbold();
+ OS << ']';
+ }
+ }
+
// Prints the appropriate placeholder for elided template arguments.
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {
if (PrintTree) {
@@ -1866,21 +1966,21 @@
PrintTree(PrintTree),
ShowColor(ShowColor),
// When printing a single type, the FromType is the one printed.
- FromType(PrintFromType ? FromType : ToType),
- ToType(PrintFromType ? ToType : FromType),
+ FromTemplateType(PrintFromType ? FromType : ToType),
+ ToTemplateType(PrintFromType ? ToType : FromType),
OS(OS),
IsBold(false) {
}
/// DiffTemplate - Start the template type diffing.
void DiffTemplate() {
- Qualifiers FromQual = FromType.getQualifiers(),
- ToQual = ToType.getQualifiers();
+ Qualifiers FromQual = FromTemplateType.getQualifiers(),
+ ToQual = ToTemplateType.getQualifiers();
const TemplateSpecializationType *FromOrigTST =
- GetTemplateSpecializationType(Context, FromType);
+ GetTemplateSpecializationType(Context, FromTemplateType);
const TemplateSpecializationType *ToOrigTST =
- GetTemplateSpecializationType(Context, ToType);
+ GetTemplateSpecializationType(Context, ToTemplateType);
// Only checking templates.
if (!FromOrigTST || !ToOrigTST)
@@ -1893,13 +1993,12 @@
FromQual -= QualType(FromOrigTST, 0).getQualifiers();
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
- Tree.SetNode(FromType, ToType);
- Tree.SetNode(FromQual, ToQual);
- Tree.SetKind(DiffTree::Template);
// Same base template, but different arguments.
- Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
- ToOrigTST->getTemplateName().getAsTemplateDecl());
+ Tree.SetTemplateDiff(FromOrigTST->getTemplateName().getAsTemplateDecl(),
+ ToOrigTST->getTemplateName().getAsTemplateDecl(),
+ FromQual, ToQual, false /*FromDefault*/,
+ false /*ToDefault*/);
DiffTemplate(FromOrigTST, ToOrigTST);
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index d5e5372..9b79442 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/LocInfoType.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::comments;
@@ -655,6 +656,15 @@
OS << "<<<NULL>>>";
return;
}
+ if (const LocInfoType *LIT = llvm::dyn_cast<LocInfoType>(T)) {
+ {
+ ColorScope Color(*this, TypeColor);
+ OS << "LocInfo Type";
+ }
+ dumpPointer(T);
+ dumpTypeAsChild(LIT->getTypeSourceInfo()->getType());
+ return;
+ }
{
ColorScope Color(*this, TypeColor);
@@ -1045,6 +1055,7 @@
dumpType(D->getUnderlyingType());
if (D->isModulePrivate())
OS << " __module_private__";
+ dumpTypeAsChild(D->getUnderlyingType());
}
void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
@@ -1216,6 +1227,7 @@
void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
dumpName(D);
dumpType(D->getUnderlyingType());
+ dumpTypeAsChild(D->getUnderlyingType());
}
void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
@@ -1385,20 +1397,23 @@
void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
OS << ' ';
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
}
void ASTDumper::VisitUnresolvedUsingTypenameDecl(
const UnresolvedUsingTypenameDecl *D) {
OS << ' ';
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
}
void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
OS << ' ';
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ if (D->getQualifier())
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
dumpType(D->getType());
}
@@ -1406,6 +1421,8 @@
void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
OS << ' ';
dumpBareDeclRef(D->getTargetDecl());
+ if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
+ dumpTypeAsChild(TD->getTypeForDecl());
}
void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
@@ -1580,6 +1597,8 @@
OS << " strong";
if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
OS << " unsafe_unretained";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
+ OS << " class";
if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
dumpDeclRef(D->getGetterMethodDecl(), "getter");
if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index ccc6931..018faff 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -878,6 +878,14 @@
break;
}
+ case Type::Pipe: {
+ if (!IsStructurallyEquivalent(Context,
+ cast<PipeType>(T1)->getElementType(),
+ cast<PipeType>(T2)->getElementType()))
+ return false;
+ break;
+ }
+
} // end switch
return true;
@@ -1746,7 +1754,7 @@
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ return Importer.getToContext().getAutoType(ToDeduced, T->getKeyword(),
/*IsDependent*/false);
}
@@ -2144,7 +2152,7 @@
return TemplateParameterList::Create(Importer.getToContext(),
Importer.Import(Params->getTemplateLoc()),
Importer.Import(Params->getLAngleLoc()),
- ToParams.data(), ToParams.size(),
+ ToParams,
Importer.Import(Params->getRAngleLoc()));
}
@@ -4053,7 +4061,8 @@
}
ObjCPropertyImplDecl *ToImpl
- = InImpl->FindPropertyImplDecl(Property->getIdentifier());
+ = InImpl->FindPropertyImplDecl(Property->getIdentifier(),
+ Property->getQueryKind());
if (!ToImpl) {
ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getLocStart()),
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f760079..427ca5e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -635,6 +635,8 @@
if (D->isInAnonymousNamespace()) {
const auto *Var = dyn_cast<VarDecl>(D);
const auto *Func = dyn_cast<FunctionDecl>(D);
+ // FIXME: In C++11 onwards, anonymous namespaces should give decls
+ // within them internal linkage, not unique external linkage.
if ((!Var || !isFirstInExternCContext(Var)) &&
(!Func || !isFirstInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
@@ -821,10 +823,14 @@
} else if (isa<ObjCInterfaceDecl>(D)) {
// fallout
+ } else if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
+ // A typedef declaration has linkage if it gives a type a name for
+ // linkage purposes.
+ if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/true))
+ return LinkageInfo::none();
+
// Everything not covered here has no linkage.
} else {
- // FIXME: A typedef declaration has linkage if it gives a type a name for
- // linkage purposes.
return LinkageInfo::none();
}
@@ -1178,7 +1184,7 @@
return LinkageInfo::none();
const Decl *OuterD = getOutermostFuncOrBlockContext(D);
- if (!OuterD)
+ if (!OuterD || OuterD->isInvalidDecl())
return LinkageInfo::none();
LinkageInfo LV;
@@ -1217,13 +1223,45 @@
static LinkageInfo computeLVForDecl(const NamedDecl *D,
LVComputationKind computation) {
+ // Internal_linkage attribute overrides other considerations.
+ if (D->hasAttr<InternalLinkageAttr>())
+ return LinkageInfo::internal();
+
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
default:
break;
+
+ // Per C++ [basic.link]p2, only the names of objects, references,
+ // functions, types, templates, namespaces, and values ever have linkage.
+ //
+ // Note that the name of a typedef, namespace alias, using declaration,
+ // and so on are not the name of the corresponding type, namespace, or
+ // declaration, so they do *not* have linkage.
+ case Decl::ImplicitParam:
+ case Decl::Label:
+ case Decl::NamespaceAlias:
case Decl::ParmVar:
+ case Decl::Using:
+ case Decl::UsingShadow:
+ case Decl::UsingDirective:
return LinkageInfo::none();
+
+ case Decl::EnumConstant:
+ // C++ [basic.link]p4: an enumerator has the linkage of its enumeration.
+ return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation);
+
+ case Decl::Typedef:
+ case Decl::TypeAlias:
+ // A typedef declaration has linkage if it gives a type a name for
+ // linkage purposes.
+ if (!D->getASTContext().getLangOpts().CPlusPlus ||
+ !cast<TypedefNameDecl>(D)
+ ->getAnonDeclWithTypedefName(/*AnyRedecl*/true))
+ return LinkageInfo::none();
+ break;
+
case Decl::TemplateTemplateParm: // count these as external
case Decl::NonTypeTemplateParm:
case Decl::ObjCAtDefsField:
@@ -1307,6 +1345,10 @@
public:
static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation) {
+ // Internal_linkage attribute overrides other considerations.
+ if (D->hasAttr<InternalLinkageAttr>())
+ return LinkageInfo::internal();
+
if (computation == LVForLinkageOnly && D->hasCachedLinkage())
return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
@@ -1392,8 +1434,10 @@
if (P.SuppressUnwrittenScope &&
(ND->isAnonymousNamespace() || ND->isInline()))
continue;
- if (ND->isAnonymousNamespace())
- OS << "(anonymous namespace)";
+ if (ND->isAnonymousNamespace()) {
+ OS << (P.MSVCFormatting ? "`anonymous namespace\'"
+ : "(anonymous namespace)");
+ }
else
OS << *ND;
} else if (const auto *RD = dyn_cast<RecordDecl>(*I)) {
@@ -1563,6 +1607,9 @@
if (auto *AD = dyn_cast<ObjCCompatibleAliasDecl>(ND))
return AD->getClassInterface();
+ if (auto *AD = dyn_cast<NamespaceAliasDecl>(ND))
+ return AD->getNamespace();
+
return ND;
}
@@ -1984,6 +2031,31 @@
return nullptr;
}
+bool VarDecl::hasInit() const {
+ if (auto *P = dyn_cast<ParmVarDecl>(this))
+ if (P->hasUnparsedDefaultArg() || P->hasUninstantiatedDefaultArg())
+ return false;
+
+ return !Init.isNull();
+}
+
+Expr *VarDecl::getInit() {
+ if (!hasInit())
+ return nullptr;
+
+ if (auto *S = Init.dyn_cast<Stmt *>())
+ return cast<Expr>(S);
+
+ return cast_or_null<Expr>(Init.get<EvaluatedStmt *>()->Value);
+}
+
+Stmt **VarDecl::getInitAddress() {
+ if (auto *ES = Init.dyn_cast<EvaluatedStmt *>())
+ return &ES->Value;
+
+ return Init.getAddrOfPtr1();
+}
+
bool VarDecl::isOutOfLine() const {
if (Decl::isOutOfLine())
return true;
@@ -2054,13 +2126,12 @@
EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
auto *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
- auto *S = Init.get<Stmt *>();
// Note: EvaluatedStmt contains an APValue, which usually holds
// resources not allocated from the ASTContext. We need to do some
// work to avoid leaking those, but we do so in VarDecl::evaluateValue
// where we can detect whether there's anything to clean up or not.
Eval = new (getASTContext()) EvaluatedStmt;
- Eval->Value = S;
+ Eval->Value = Init.get<Stmt *>();
Init = Eval;
}
return Eval;
@@ -2124,6 +2195,27 @@
return Result ? &Eval->Evaluated : nullptr;
}
+APValue *VarDecl::getEvaluatedValue() const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ if (Eval->WasEvaluated)
+ return &Eval->Evaluated;
+
+ return nullptr;
+}
+
+bool VarDecl::isInitKnownICE() const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ return Eval->CheckedICE;
+
+ return false;
+}
+
+bool VarDecl::isInitICE() const {
+ assert(isInitKnownICE() &&
+ "Check whether we already know that the initializer is an ICE");
+ return Init.get<EvaluatedStmt *>()->IsICE;
+}
+
bool VarDecl::checkInitIsICE() const {
// Initializers of weak variables are never ICEs.
if (isWeak())
@@ -2289,14 +2381,48 @@
return Arg;
}
-SourceRange ParmVarDecl::getDefaultArgRange() const {
- if (const Expr *E = getInit())
- return E->getSourceRange();
+void ParmVarDecl::setDefaultArg(Expr *defarg) {
+ ParmVarDeclBits.DefaultArgKind = DAK_Normal;
+ Init = defarg;
+}
- if (hasUninstantiatedDefaultArg())
+SourceRange ParmVarDecl::getDefaultArgRange() const {
+ switch (ParmVarDeclBits.DefaultArgKind) {
+ case DAK_None:
+ case DAK_Unparsed:
+ // Nothing we can do here.
+ return SourceRange();
+
+ case DAK_Uninstantiated:
return getUninstantiatedDefaultArg()->getSourceRange();
- return SourceRange();
+ case DAK_Normal:
+ if (const Expr *E = getInit())
+ return E->getSourceRange();
+
+ // Missing an actual expression, may be invalid.
+ return SourceRange();
+ }
+ llvm_unreachable("Invalid default argument kind.");
+}
+
+void ParmVarDecl::setUninstantiatedDefaultArg(Expr *arg) {
+ ParmVarDeclBits.DefaultArgKind = DAK_Uninstantiated;
+ Init = arg;
+}
+
+Expr *ParmVarDecl::getUninstantiatedDefaultArg() {
+ assert(hasUninstantiatedDefaultArg() &&
+ "Wrong kind of initialization expression!");
+ return cast_or_null<Expr>(Init.get<Stmt *>());
+}
+
+bool ParmVarDecl::hasDefaultArg() const {
+ // FIXME: We should just return false for DAK_None here once callers are
+ // prepared for the case that we encountered an invalid default argument and
+ // were unable to even build an invalid expression.
+ return hasUnparsedDefaultArg() || hasUninstantiatedDefaultArg() ||
+ !Init.isNull();
}
bool ParmVarDecl::isParameterPack() const {
@@ -2919,6 +3045,10 @@
return nullptr;
}
+MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
+ return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>();
+}
+
void
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
FunctionDecl *FD,
@@ -2930,6 +3060,14 @@
TemplateOrSpecialization = Info;
}
+FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const {
+ return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl *>();
+}
+
+void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
+ TemplateOrSpecialization = Template;
+}
+
bool FunctionDecl::isImplicitlyInstantiable() const {
// If the function is invalid, it can't be implicitly instantiated.
if (isInvalidDecl())
@@ -3036,6 +3174,12 @@
return getASTContext().getClassScopeSpecializationPattern(this);
}
+FunctionTemplateSpecializationInfo *
+FunctionDecl::getTemplateSpecializationInfo() const {
+ return TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo *>();
+}
+
const TemplateArgumentList *
FunctionDecl::getTemplateSpecializationArgs() const {
if (FunctionTemplateSpecializationInfo *Info
@@ -3089,6 +3233,12 @@
}
DependentFunctionTemplateSpecializationInfo *
+FunctionDecl::getDependentSpecializationInfo() const {
+ return TemplateOrSpecialization
+ .dyn_cast<DependentFunctionTemplateSpecializationInfo *>();
+}
+
+DependentFunctionTemplateSpecializationInfo *
DependentFunctionTemplateSpecializationInfo::Create(
ASTContext &Context, const UnresolvedSetImpl &Ts,
const TemplateArgumentListInfo &TArgs) {
@@ -3837,6 +3987,10 @@
return new (C, ID) BlockDecl(nullptr, SourceLocation());
}
+CapturedDecl::CapturedDecl(DeclContext *DC, unsigned NumParams)
+ : Decl(Captured, DC, SourceLocation()), DeclContext(Captured),
+ NumParams(NumParams), ContextParam(0), BodyAndNothrow(nullptr, false) {}
+
CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC,
unsigned NumParams) {
return new (C, DC, additionalSizeToAlloc<ImplicitParamDecl *>(NumParams))
@@ -3849,6 +4003,12 @@
CapturedDecl(nullptr, NumParams);
}
+Stmt *CapturedDecl::getBody() const { return BodyAndNothrow.getPointer(); }
+void CapturedDecl::setBody(Stmt *B) { BodyAndNothrow.setPointer(B); }
+
+bool CapturedDecl::isNothrow() const { return BodyAndNothrow.getInt(); }
+void CapturedDecl::setNothrow(bool Nothrow) { BodyAndNothrow.setInt(Nothrow); }
+
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
SourceLocation L,
IdentifierInfo *Id, QualType T,
@@ -3864,16 +4024,26 @@
void IndirectFieldDecl::anchor() { }
+IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName N,
+ QualType T, NamedDecl **CH, unsigned CHS)
+ : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {
+ // In C++, indirect field declarations conflict with tag declarations in the
+ // same scope, so add them to IDNS_Tag so that tag redeclaration finds them.
+ if (C.getLangOpts().CPlusPlus)
+ IdentifierNamespace |= IDNS_Tag;
+}
+
IndirectFieldDecl *
IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, NamedDecl **CH,
unsigned CHS) {
- return new (C, DC) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
+ return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH, CHS);
}
IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) IndirectFieldDecl(nullptr, SourceLocation(),
+ return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(),
DeclarationName(), QualType(), nullptr,
0);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 3da2546..6a70730 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -573,7 +573,6 @@
case Var:
case ImplicitParam:
case ParmVar:
- case NonTypeTemplateParm:
case ObjCMethod:
case ObjCProperty:
case MSProperty:
@@ -583,6 +582,12 @@
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
+ case NonTypeTemplateParm:
+ // Non-type template parameters are not found by lookups that ignore
+ // non-types, but they are found by redeclaration lookups for tag types,
+ // so we include them in the tag namespace.
+ return IDNS_Ordinary | IDNS_Tag;
+
case ObjCCompatibleAlias:
case ObjCInterface:
return IDNS_Ordinary | IDNS_Type;
@@ -1214,13 +1219,16 @@
// Remove only decls that have a name
if (!ND->getDeclName()) return;
- StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
- if (!Map) return;
-
- StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
- assert(Pos != Map->end() && "no lookup entry for decl");
- if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND)
- Pos->second.remove(ND);
+ auto *DC = this;
+ do {
+ StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr;
+ if (Map) {
+ StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
+ assert(Pos != Map->end() && "no lookup entry for decl");
+ if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND)
+ Pos->second.remove(ND);
+ }
+ } while (DC->isTransparentContext() && (DC = DC->getParent()));
}
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 32e64b6..4f24fdc 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1218,6 +1218,10 @@
return nullptr;
}
+MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
+ return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
+}
+
void
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
@@ -1228,6 +1232,14 @@
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
+ClassTemplateDecl *CXXRecordDecl::getDescribedClassTemplate() const {
+ return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl *>();
+}
+
+void CXXRecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) {
+ TemplateOrInstantiation = Template;
+}
+
TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(this))
@@ -1675,8 +1687,8 @@
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
{
- VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
- memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
+ std::uninitialized_copy(Indices, Indices + NumIndices,
+ getTrailingObjects<VarDecl *>());
}
CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context,
@@ -1686,8 +1698,7 @@
SourceLocation R,
VarDecl **Indices,
unsigned NumIndices) {
- void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) +
- sizeof(VarDecl *) * NumIndices,
+ void *Mem = Context.Allocate(totalSizeToAlloc<VarDecl *>(NumIndices),
llvm::alignOf<CXXCtorInitializer>());
return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R,
Indices, NumIndices);
@@ -2017,6 +2028,22 @@
SourceLocation(), nullptr, nullptr);
}
+NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
+ if (isFirstDecl())
+ return this;
+
+ return AnonOrFirstNamespaceAndInline.getPointer();
+}
+
+const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
+ if (isFirstDecl())
+ return this;
+
+ return AnonOrFirstNamespaceAndInline.getPointer();
+}
+
+bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }
+
NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() {
return getNextRedeclaration();
}
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index a996cab..121403b 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -46,7 +46,9 @@
}
#endif
- std::size_t Extra = FriendTypeTPLists.size() * sizeof(TemplateParameterList*);
+ std::size_t Extra =
+ FriendDecl::additionalSizeToAlloc<TemplateParameterList *>(
+ FriendTypeTPLists.size());
FriendDecl *FD = new (C, DC, Extra) FriendDecl(DC, L, Friend, FriendL,
FriendTypeTPLists);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
@@ -55,7 +57,8 @@
FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned FriendTypeNumTPLists) {
- std::size_t Extra = FriendTypeNumTPLists * sizeof(TemplateParameterList*);
+ std::size_t Extra =
+ additionalSizeToAlloc<TemplateParameterList *>(FriendTypeNumTPLists);
return new (C, ID, Extra) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 512837f..f162e6d 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -18,10 +18,8 @@
using namespace clang;
DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
- static_assert(sizeof(DeclGroup) % llvm::AlignOf<void *>::Alignment == 0,
- "Trailing data is unaligned!");
assert(NumDecls > 1 && "Invalid DeclGroup");
- unsigned Size = sizeof(DeclGroup) + sizeof(Decl*) * NumDecls;
+ unsigned Size = totalSizeToAlloc<Decl *>(NumDecls);
void* Mem = C.Allocate(Size, llvm::AlignOf<DeclGroup>::Alignment);
new (Mem) DeclGroup(NumDecls, Decls);
return static_cast<DeclGroup*>(Mem);
@@ -30,5 +28,6 @@
DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) {
assert(numdecls > 0);
assert(decls);
- memcpy(this+1, decls, numdecls * sizeof(*decls));
+ std::uninitialized_copy(decls, decls + numdecls,
+ getTrailingObjects<Decl *>());
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index b5dc9e1..1480a55 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -152,7 +152,8 @@
ObjCPropertyDecl *
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
- const IdentifierInfo *propertyID) {
+ const IdentifierInfo *propertyID,
+ ObjCPropertyQueryKind queryKind) {
// If this context is a hidden protocol definition, don't find any
// property.
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
@@ -166,15 +167,33 @@
if (auto *IDecl = dyn_cast<ObjCInterfaceDecl>(DC)) {
for (const auto *Ext : IDecl->known_extensions())
if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(Ext,
- propertyID))
+ propertyID,
+ queryKind))
return PD;
}
DeclContext::lookup_result R = DC->lookup(propertyID);
+ ObjCPropertyDecl *classProp = nullptr;
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
++I)
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
- return PD;
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) {
+ // If queryKind is unknown, we return the instance property if one
+ // exists; otherwise we return the class property.
+ if ((queryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown &&
+ !PD->isClassProperty()) ||
+ (queryKind == ObjCPropertyQueryKind::OBJC_PR_query_class &&
+ PD->isClassProperty()) ||
+ (queryKind == ObjCPropertyQueryKind::OBJC_PR_query_instance &&
+ !PD->isClassProperty()))
+ return PD;
+
+ if (PD->isClassProperty())
+ classProp = PD;
+ }
+
+ if (queryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown)
+ // We can't find the instance property, return the class property.
+ return classProp;
return nullptr;
}
@@ -192,7 +211,8 @@
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
- const IdentifierInfo *PropertyId) const {
+ const IdentifierInfo *PropertyId,
+ ObjCPropertyQueryKind QueryKind) const {
// Don't find properties within hidden protocol definitions.
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
@@ -204,13 +224,14 @@
// the class itself.
if (const auto *ClassDecl = dyn_cast<ObjCInterfaceDecl>(this)) {
for (const auto *Ext : ClassDecl->visible_extensions()) {
- if (auto *P = Ext->FindPropertyDeclaration(PropertyId))
+ if (auto *P = Ext->FindPropertyDeclaration(PropertyId, QueryKind))
return P;
}
}
if (ObjCPropertyDecl *PD =
- ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId,
+ QueryKind))
return PD;
switch (getKind()) {
@@ -219,7 +240,8 @@
case Decl::ObjCProtocol: {
const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this);
for (const auto *I : PID->protocols())
- if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
+ QueryKind))
return P;
break;
}
@@ -228,18 +250,20 @@
// Look through categories (but not extensions; they were handled above).
for (const auto *Cat : OID->visible_categories()) {
if (!Cat->IsClassExtension())
- if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(
+ PropertyId, QueryKind))
return P;
}
// Look through protocols.
for (const auto *I : OID->all_referenced_protocols())
- if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
+ QueryKind))
return P;
// Finally, check the super class.
if (const ObjCInterfaceDecl *superClass = OID->getSuperClass())
- return superClass->FindPropertyDeclaration(PropertyId);
+ return superClass->FindPropertyDeclaration(PropertyId, QueryKind);
break;
}
case Decl::ObjCCategory: {
@@ -247,7 +271,8 @@
// Look through protocols.
if (!OCD->IsClassExtension())
for (const auto *I : OCD->protocols())
- if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
+ QueryKind))
return P;
break;
}
@@ -319,7 +344,8 @@
///
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
- IdentifierInfo *PropertyId) const {
+ IdentifierInfo *PropertyId,
+ ObjCPropertyQueryKind QueryKind) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return nullptr;
@@ -328,12 +354,14 @@
LoadExternalDefinition();
if (ObjCPropertyDecl *PD =
- ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId,
+ QueryKind))
return PD;
// Look through protocols.
for (const auto *I : all_referenced_protocols())
- if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
+ QueryKind))
return P;
return nullptr;
@@ -342,13 +370,13 @@
void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const {
for (auto *Prop : properties()) {
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
PO.push_back(Prop);
}
for (const auto *Ext : known_extensions()) {
const ObjCCategoryDecl *ClassExt = Ext;
for (auto *Prop : ClassExt->properties()) {
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
PO.push_back(Prop);
}
}
@@ -772,6 +800,10 @@
if (Params.empty() && SelLocs.empty())
return;
+ static_assert(llvm::AlignOf<ParmVarDecl *>::Alignment >=
+ llvm::AlignOf<SourceLocation>::Alignment,
+ "Alignment not sufficient for SourceLocation");
+
unsigned Size = sizeof(ParmVarDecl *) * NumParams +
sizeof(SourceLocation) * SelLocs.size();
ParamsAndSelLocs = C.Allocate(Size);
@@ -1214,7 +1246,7 @@
auto findMatchingProperty =
[&](const ObjCContainerDecl *Container) -> const ObjCPropertyDecl * {
- for (const auto *I : Container->properties()) {
+ for (const auto *I : Container->instance_properties()) {
Selector NextSel = IsGetter ? I->getGetterName()
: I->getSetterName();
if (NextSel == Sel)
@@ -1326,13 +1358,9 @@
SourceLocation lAngleLoc,
ArrayRef<ObjCTypeParamDecl *> typeParams,
SourceLocation rAngleLoc) {
- unsigned size = sizeof(ObjCTypeParamList)
- + sizeof(ObjCTypeParamDecl *) * typeParams.size();
- static_assert(llvm::AlignOf<ObjCTypeParamList>::Alignment >=
- llvm::AlignOf<ObjCTypeParamDecl *>::Alignment,
- "type parameter list needs greater alignment");
- unsigned align = llvm::alignOf<ObjCTypeParamList>();
- void *mem = ctx.Allocate(size, align);
+ void *mem =
+ ctx.Allocate(totalSizeToAlloc<ObjCTypeParamDecl *>(typeParams.size()),
+ llvm::alignOf<ObjCTypeParamList>());
return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
}
@@ -1822,7 +1850,9 @@
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
for (auto *Prop : PDecl->properties()) {
// Insert into PM if not there already.
- PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+ PM.insert(std::make_pair(
+ std::make_pair(Prop->getIdentifier(), Prop->isClassProperty()),
+ Prop));
PO.push_back(Prop);
}
// Scan through protocol's protocols.
@@ -2011,10 +2041,29 @@
/// category \@implementation block.
///
ObjCPropertyImplDecl *ObjCImplDecl::
-FindPropertyImplDecl(IdentifierInfo *Id) const {
+FindPropertyImplDecl(IdentifierInfo *Id,
+ ObjCPropertyQueryKind QueryKind) const {
+ ObjCPropertyImplDecl *ClassPropImpl = nullptr;
for (auto *PID : property_impls())
- if (PID->getPropertyDecl()->getIdentifier() == Id)
- return PID;
+ // If queryKind is unknown, we return the instance property if one
+ // exists; otherwise we return the class property.
+ if (PID->getPropertyDecl()->getIdentifier() == Id) {
+ if ((QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown &&
+ !PID->getPropertyDecl()->isClassProperty()) ||
+ (QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_class &&
+ PID->getPropertyDecl()->isClassProperty()) ||
+ (QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_instance &&
+ !PID->getPropertyDecl()->isClassProperty()))
+ return PID;
+
+ if (PID->getPropertyDecl()->isClassProperty())
+ ClassPropImpl = PID;
+ }
+
+ if (QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown)
+ // We can't find the instance property, return the class property.
+ return ClassPropImpl;
+
return nullptr;
}
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index 5f8b42b..493e2cd 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -29,8 +29,9 @@
DeclContext *DC,
SourceLocation L,
ArrayRef<Expr *> VL) {
- OMPThreadPrivateDecl *D = new (C, DC, VL.size() * sizeof(Expr *))
- OMPThreadPrivateDecl(OMPThreadPrivate, DC, L);
+ OMPThreadPrivateDecl *D =
+ new (C, DC, additionalSizeToAlloc<Expr *>(VL.size()))
+ OMPThreadPrivateDecl(OMPThreadPrivate, DC, L);
D->NumVars = VL.size();
D->setVars(VL);
return D;
@@ -39,7 +40,7 @@
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- OMPThreadPrivateDecl *D = new (C, ID, N * sizeof(Expr *))
+ OMPThreadPrivateDecl *D = new (C, ID, additionalSizeToAlloc<Expr *>(N))
OMPThreadPrivateDecl(OMPThreadPrivate, nullptr, SourceLocation());
D->NumVars = N;
return D;
@@ -48,7 +49,6 @@
void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- Expr **Vars = reinterpret_cast<Expr **>(this + 1);
- std::copy(VL.begin(), VL.end(), Vars);
+ std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>());
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 5c6002d..e20c7d8 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1298,6 +1298,11 @@
}
}
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_class) {
+ Out << (first ? ' ' : ',') << "class";
+ first = false;
+ }
+
(void) first; // Silence dead store warning due to idiomatic code.
Out << " )";
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 18a30b2..de3ebd2 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -30,10 +30,10 @@
TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- NamedDecl **Params, unsigned NumParams,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
- NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
+ NumParams(Params.size()), ContainsUnexpandedParameterPack(false) {
assert(this->NumParams == NumParams && "Too many template parameters");
for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
NamedDecl *P = Params[Idx];
@@ -54,14 +54,13 @@
}
}
-TemplateParameterList *
-TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc, NamedDecl **Params,
- unsigned NumParams, SourceLocation RAngleLoc) {
- void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *>(NumParams),
+TemplateParameterList *TemplateParameterList::Create(
+ const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *>(Params.size()),
llvm::alignOf<TemplateParameterList>());
return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
- NumParams, RAngleLoc);
+ RAngleLoc);
}
unsigned TemplateParameterList::getMinRequiredArguments() const {
@@ -1212,7 +1211,7 @@
// <typename T, T ...Ints>
NamedDecl *P[2] = {T, N};
auto *TPL = TemplateParameterList::Create(
- C, SourceLocation(), SourceLocation(), P, 2, SourceLocation());
+ C, SourceLocation(), SourceLocation(), P, SourceLocation());
// template <typename T, ...Ints> class IntSeq
auto *TemplateTemplateParm = TemplateTemplateParmDecl::Create(
@@ -1237,7 +1236,7 @@
// template <template <typename T, T ...Ints> class IntSeq, typename T, T N>
return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
- Params, 3, SourceLocation());
+ Params, SourceLocation());
}
static TemplateParameterList *createBuiltinTemplateParameterList(
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index dbc890d..62b7999 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -331,7 +331,8 @@
D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
if (QualifierLoc) {
- getInternalQualifierLoc() = QualifierLoc;
+ new (getTrailingObjects<NestedNameSpecifierLoc>())
+ NestedNameSpecifierLoc(QualifierLoc);
auto *NNS = QualifierLoc.getNestedNameSpecifier();
if (NNS->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
@@ -340,7 +341,7 @@
}
DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
if (FoundD)
- getInternalFoundDecl() = FoundD;
+ *getTrailingObjects<NamedDecl *>() = FoundD;
DeclRefExprBits.HasTemplateKWAndArgsInfo
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
@@ -349,15 +350,15 @@
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
- Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
+ Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
assert(!Dependent && "built a DeclRefExpr with dependent template args");
ExprBits.InstantiationDependent |= InstantiationDependent;
ExprBits.ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
} else if (TemplateKWLoc.isValid()) {
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc);
}
DeclRefExprBits.HadMultipleCandidates = 0;
@@ -394,20 +395,13 @@
if (D == FoundD)
FoundD = nullptr;
- std::size_t Size = sizeof(DeclRefExpr);
- if (QualifierLoc)
- Size += sizeof(NestedNameSpecifierLoc);
- if (FoundD)
- Size += sizeof(NamedDecl *);
- if (TemplateArgs) {
- Size = llvm::RoundUpToAlignment(Size,
- llvm::alignOf<ASTTemplateKWAndArgsInfo>());
- Size += ASTTemplateKWAndArgsInfo::sizeFor(TemplateArgs->size());
- } else if (TemplateKWLoc.isValid()) {
- Size = llvm::RoundUpToAlignment(Size,
- llvm::alignOf<ASTTemplateKWAndArgsInfo>());
- Size += ASTTemplateKWAndArgsInfo::sizeFor(0);
- }
+ bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
+ std::size_t Size =
+ totalSizeToAlloc<NestedNameSpecifierLoc, NamedDecl *,
+ ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ QualifierLoc ? 1 : 0, FoundD ? 1 : 0,
+ HasTemplateKWAndArgsInfo ? 1 : 0,
+ TemplateArgs ? TemplateArgs->size() : 0);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
@@ -420,17 +414,12 @@
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- std::size_t Size = sizeof(DeclRefExpr);
- if (HasQualifier)
- Size += sizeof(NestedNameSpecifierLoc);
- if (HasFoundDecl)
- Size += sizeof(NamedDecl *);
- if (HasTemplateKWAndArgsInfo) {
- Size = llvm::RoundUpToAlignment(Size,
- llvm::alignOf<ASTTemplateKWAndArgsInfo>());
- Size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
- }
-
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+ std::size_t Size =
+ totalSizeToAlloc<NestedNameSpecifierLoc, NamedDecl *,
+ ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasQualifier ? 1 : 0, HasFoundDecl ? 1 : 0, HasTemplateKWAndArgsInfo,
+ NumTemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
}
@@ -1007,15 +996,33 @@
/// can have escape sequences in them in addition to the usual trigraph and
/// escaped newline business. This routine handles this complexity.
///
-SourceLocation StringLiteral::
-getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
- const LangOptions &Features, const TargetInfo &Target) const {
+/// The *StartToken sets the first token to be searched in this function and
+/// the *StartTokenByteOffset is the byte offset of the first token. Before
+/// returning, it updates the *StartToken to the TokNo of the token being found
+/// and sets *StartTokenByteOffset to the byte offset of the token in the
+/// string.
+/// Using these two parameters can reduce the time complexity from O(n^2) to
+/// O(n) if one wants to get the location of byte for all the tokens in a
+/// string.
+///
+SourceLocation
+StringLiteral::getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
+ const LangOptions &Features,
+ const TargetInfo &Target, unsigned *StartToken,
+ unsigned *StartTokenByteOffset) const {
assert((Kind == StringLiteral::Ascii || Kind == StringLiteral::UTF8) &&
"Only narrow string literals are currently supported");
// Loop over all of the tokens in this string until we find the one that
// contains the byte we're looking for.
unsigned TokNo = 0;
+ unsigned StringOffset = 0;
+ if (StartToken)
+ TokNo = *StartToken;
+ if (StartTokenByteOffset) {
+ StringOffset = *StartTokenByteOffset;
+ ByteNo -= StringOffset;
+ }
while (1) {
assert(TokNo < getNumConcatenated() && "Invalid byte number!");
SourceLocation StrTokLoc = getStrTokenLoc(TokNo);
@@ -1024,14 +1031,20 @@
// the string literal, not the identifier for the macro it is potentially
// expanded through.
SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc);
-
+
// Re-lex the token to get its length and original spelling.
- std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc);
+ std::pair<FileID, unsigned> LocInfo =
+ SM.getDecomposedLoc(StrTokSpellingLoc);
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
- if (Invalid)
+ if (Invalid) {
+ if (StartTokenByteOffset != nullptr)
+ *StartTokenByteOffset = StringOffset;
+ if (StartToken != nullptr)
+ *StartToken = TokNo;
return StrTokSpellingLoc;
-
+ }
+
const char *StrData = Buffer.data()+LocInfo.second;
// Create a lexer starting at the beginning of this token.
@@ -1047,14 +1060,19 @@
// If the byte is in this token, return the location of the byte.
if (ByteNo < TokNumBytes ||
(ByteNo == TokNumBytes && TokNo == getNumConcatenated() - 1)) {
- unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo);
-
+ unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo);
+
// Now that we know the offset of the token in the spelling, use the
// preprocessor to get the offset in the original source.
+ if (StartTokenByteOffset != nullptr)
+ *StartTokenByteOffset = StringOffset;
+ if (StartToken != nullptr)
+ *StartToken = TokNo;
return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features);
}
-
+
// Move to the next string token.
+ StringOffset += TokNumBytes;
++TokNo;
ByteNo -= TokNumBytes;
}
@@ -1120,28 +1138,23 @@
// Postfix Operators.
//===----------------------------------------------------------------------===//
-CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
- unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t,
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
+ ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc)
- : Expr(SC, t, VK, OK_Ordinary,
- fn->isTypeDependent(),
- fn->isValueDependent(),
- fn->isInstantiationDependent(),
- fn->containsUnexpandedParameterPack()),
- NumArgs(args.size()) {
+ : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(),
+ fn->isValueDependent(), fn->isInstantiationDependent(),
+ fn->containsUnexpandedParameterPack()),
+ NumArgs(args.size()) {
- SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs];
+ unsigned NumPreArgs = preargs.size();
+ SubExprs = new (C) Stmt *[args.size()+PREARGS_START+NumPreArgs];
SubExprs[FN] = fn;
+ for (unsigned i = 0; i != NumPreArgs; ++i) {
+ updateDependenciesFromArg(preargs[i]);
+ SubExprs[i+PREARGS_START] = preargs[i];
+ }
for (unsigned i = 0; i != args.size(); ++i) {
- if (args[i]->isTypeDependent())
- ExprBits.TypeDependent = true;
- if (args[i]->isValueDependent())
- ExprBits.ValueDependent = true;
- if (args[i]->isInstantiationDependent())
- ExprBits.InstantiationDependent = true;
- if (args[i]->containsUnexpandedParameterPack())
- ExprBits.ContainsUnexpandedParameterPack = true;
-
+ updateDependenciesFromArg(args[i]);
SubExprs[i+PREARGS_START+NumPreArgs] = args[i];
}
@@ -1149,9 +1162,14 @@
RParenLoc = rparenloc;
}
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
+ ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
+ SourceLocation rparenloc)
+ : CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {}
+
CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
- : CallExpr(C, CallExprClass, fn, /*NumPreArgs=*/0, args, t, VK, rparenloc) {
+ : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {
}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
@@ -1161,10 +1179,21 @@
EmptyShell Empty)
: Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) {
// FIXME: Why do we allocate this?
- SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs];
+ SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs]();
CallExprBits.NumPreArgs = NumPreArgs;
}
+void CallExpr::updateDependenciesFromArg(Expr *Arg) {
+ if (Arg->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (Arg->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (Arg->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (Arg->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+}
+
Decl *CallExpr::getCalleeDecl() {
Expr *CEE = getCallee()->IgnoreParenImpCasts();
@@ -1296,9 +1325,8 @@
ArrayRef<OffsetOfNode> comps,
ArrayRef<Expr*> exprs,
SourceLocation RParenLoc) {
- void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
- sizeof(OffsetOfNode) * comps.size() +
- sizeof(Expr*) * exprs.size());
+ void *Mem = C.Allocate(
+ totalSizeToAlloc<OffsetOfNode, Expr *>(comps.size(), exprs.size()));
return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs,
RParenLoc);
@@ -1306,9 +1334,8 @@
OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C,
unsigned numComps, unsigned numExprs) {
- void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
- sizeof(OffsetOfNode) * numComps +
- sizeof(Expr*) * numExprs);
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<OffsetOfNode, Expr *>(numComps, numExprs));
return new (Mem) OffsetOfExpr(numComps, numExprs);
}
@@ -1338,7 +1365,7 @@
}
}
-IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
+IdentifierInfo *OffsetOfNode::getFieldName() const {
assert(getKind() == Field || getKind() == Identifier);
if (getKind() == Field)
return getField()->getIdentifier();
@@ -1390,18 +1417,17 @@
ValueDecl *memberdecl, DeclAccessPair founddecl,
DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs,
QualType ty, ExprValueKind vk, ExprObjectKind ok) {
- std::size_t Size = sizeof(MemberExpr);
bool hasQualOrFound = (QualifierLoc ||
founddecl.getDecl() != memberdecl ||
founddecl.getAccess() != memberdecl->getAccess());
- if (hasQualOrFound)
- Size += sizeof(MemberNameQualifier);
- if (targs)
- Size += ASTTemplateKWAndArgsInfo::sizeFor(targs->size());
- else if (TemplateKWLoc.isValid())
- Size += ASTTemplateKWAndArgsInfo::sizeFor(0);
+ bool HasTemplateKWAndArgsInfo = targs || TemplateKWLoc.isValid();
+ std::size_t Size =
+ totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc>(hasQualOrFound ? 1 : 0,
+ HasTemplateKWAndArgsInfo ? 1 : 0,
+ targs ? targs->size() : 0);
void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>());
MemberExpr *E = new (Mem)
@@ -1420,7 +1446,8 @@
E->HasQualifierOrFoundDecl = true;
- MemberNameQualifier *NQ = E->getMemberQualifier();
+ MemberExprNameQualifier *NQ =
+ E->getTrailingObjects<MemberExprNameQualifier>();
NQ->QualifierLoc = QualifierLoc;
NQ->FoundDecl = founddecl;
}
@@ -1431,14 +1458,14 @@
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- E->getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *targs,
- Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc, *targs, E->getTrailingObjects<TemplateArgumentLoc>(),
+ Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
if (InstantiationDependent)
E->setInstantiationDependent(true);
} else if (TemplateKWLoc.isValid()) {
- E->getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
+ E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc);
}
return E;
@@ -1537,6 +1564,7 @@
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
case CK_FloatingCast:
@@ -1630,6 +1658,8 @@
return "VectorSplat";
case CK_IntegralCast:
return "IntegralCast";
+ case CK_BooleanToSignedIntegral:
+ return "BooleanToSignedIntegral";
case CK_IntegralToBoolean:
return "IntegralToBoolean";
case CK_IntegralToFloating:
@@ -1714,8 +1744,13 @@
// subexpression describing the call; strip it off.
if (E->getCastKind() == CK_ConstructorConversion)
SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
- else if (E->getCastKind() == CK_UserDefinedConversion)
- SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
+ else if (E->getCastKind() == CK_UserDefinedConversion) {
+ assert((isa<CXXMemberCallExpr>(SubExpr) ||
+ isa<BlockExpr>(SubExpr)) &&
+ "Unexpected SubExpr for CK_UserDefinedConversion.");
+ if (isa<CXXMemberCallExpr>(SubExpr))
+ SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
+ }
// If the subexpression we're left with is an implicit cast, look
// through that, too.
@@ -1727,9 +1762,9 @@
CXXBaseSpecifier **CastExpr::path_buffer() {
switch (getStmtClass()) {
#define ABSTRACT_STMT(x)
-#define CASTEXPR(Type, Base) \
- case Stmt::Type##Class: \
- return reinterpret_cast<CXXBaseSpecifier**>(static_cast<Type*>(this)+1);
+#define CASTEXPR(Type, Base) \
+ case Stmt::Type##Class: \
+ return static_cast<Type *>(this)->getTrailingObjects<CXXBaseSpecifier *>();
#define STMT(Type, Base)
#include "clang/AST/StmtNodes.inc"
default:
@@ -1737,28 +1772,23 @@
}
}
-void CastExpr::setCastPath(const CXXCastPath &Path) {
- assert(Path.size() == path_size());
- memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*));
-}
-
ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
ExprValueKind VK) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer =
- C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
ImplicitCastExpr *E =
new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
- void *Buffer =
- C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) ImplicitCastExpr(EmptyShell(), PathSize);
}
@@ -1769,18 +1799,18 @@
TypeSourceInfo *WrittenTy,
SourceLocation L, SourceLocation R) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer =
- C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
CStyleCastExpr *E =
new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
- void *Buffer =
- C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize);
}
@@ -2891,7 +2921,10 @@
return cast<CXXDefaultInitExpr>(this)->getExpr()
->isConstantInitializer(Ctx, false, Culprit);
}
- if (isEvaluatable(Ctx))
+ // Allow certain forms of UB in constant initializers: signed integer
+ // overflow and floating-point division by zero. We'll give a warning on
+ // these, but they're common enough that we have to accept them.
+ if (isEvaluatable(Ctx, SE_AllowUndefinedBehavior))
return true;
if (Culprit)
*Culprit = this;
@@ -3004,6 +3037,7 @@
return true;
case MSPropertyRefExprClass:
+ case MSPropertySubscriptExprClass:
case CompoundAssignOperatorClass:
case VAArgExprClass:
case AtomicExprClass:
@@ -3260,9 +3294,20 @@
// Check that it is a cast to void*.
if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
QualType Pointee = PT->getPointeeType();
- if (!Pointee.hasQualifiers() &&
- Pointee->isVoidType() && // to void*
- CE->getSubExpr()->getType()->isIntegerType()) // from int.
+ Qualifiers Q = Pointee.getQualifiers();
+ // In OpenCL v2.0 generic address space acts as a placeholder
+ // and should be ignored.
+ bool IsASValid = true;
+ if (Ctx.getLangOpts().OpenCLVersion >= 200) {
+ if (Pointee.getAddressSpace() == LangAS::opencl_generic)
+ Q.removeAddressSpace();
+ else
+ IsASValid = false;
+ }
+
+ if (IsASValid && !Q.hasQualifiers() &&
+ Pointee->isVoidType() && // to void*
+ CE->getSubExpr()->getType()->isIntegerType()) // from int.
return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
}
}
@@ -3685,8 +3730,7 @@
ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
bool UsesColonSyntax, Expr *Init) {
- void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
- sizeof(Stmt *) * (IndexExprs.size() + 1),
+ void *Mem = C.Allocate(totalSizeToAlloc<Stmt *>(IndexExprs.size() + 1),
llvm::alignOf<DesignatedInitExpr>());
return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
@@ -3695,8 +3739,8 @@
DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C,
unsigned NumIndexExprs) {
- void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
- sizeof(Stmt *) * (NumIndexExprs + 1), 8);
+ void *Mem = C.Allocate(totalSizeToAlloc<Stmt *>(NumIndexExprs + 1),
+ llvm::alignOf<DesignatedInitExpr>());
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
@@ -3738,22 +3782,19 @@
Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
- Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
- return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+ return getSubExpr(D.ArrayOrRange.Index + 1);
}
Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
- return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+ return getSubExpr(D.ArrayOrRange.Index + 1);
}
Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
- return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
+ return getSubExpr(D.ArrayOrRange.Index + 2);
}
/// \brief Replaces the designator at index @p Idx with the series
@@ -3837,9 +3878,9 @@
PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context,
EmptyShell sh,
unsigned numSemanticExprs) {
- void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
- (1 + numSemanticExprs) * sizeof(Expr*),
- llvm::alignOf<PseudoObjectExpr>());
+ void *buffer =
+ Context.Allocate(totalSizeToAlloc<Expr *>(1 + numSemanticExprs),
+ llvm::alignOf<PseudoObjectExpr>());
return new(buffer) PseudoObjectExpr(sh, numSemanticExprs);
}
@@ -3866,8 +3907,7 @@
assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary);
}
- void *buffer = C.Allocate(sizeof(PseudoObjectExpr) +
- (1 + semantics.size()) * sizeof(Expr*),
+ void *buffer = C.Allocate(totalSizeToAlloc<Expr *>(semantics.size() + 1),
llvm::alignOf<PseudoObjectExpr>());
return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics,
resultIndex);
@@ -4011,4 +4051,3 @@
}
return OriginalTy;
}
-
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b7f266c..ea98334 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -295,8 +295,11 @@
{
assert(Args || TemplateKWLoc.isValid());
unsigned num_args = Args ? Args->size() : 0;
- void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
- ASTTemplateKWAndArgsInfo::sizeFor(num_args));
+
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(1,
+ num_args);
+ void *Mem = C.Allocate(Size, llvm::alignOf<UnresolvedLookupExpr>());
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo,
ADL, /*Overload*/ true, Args,
@@ -307,11 +310,11 @@
UnresolvedLookupExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- std::size_t size = sizeof(UnresolvedLookupExpr);
- if (HasTemplateKWAndArgsInfo)
- size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
-
- void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>());
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs);
+ void *Mem = C.Allocate(Size, llvm::alignOf<UnresolvedLookupExpr>());
UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell());
E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
@@ -367,10 +370,9 @@
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
- Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
+ TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(),
+ Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
if (Dependent) {
ExprBits.TypeDependent = true;
@@ -381,7 +383,7 @@
if (ContainsUnexpandedParameterPack)
ExprBits.ContainsUnexpandedParameterPack = true;
} else if (TemplateKWLoc.isValid()) {
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
+ getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
if (isTypeDependent())
@@ -432,13 +434,13 @@
bool InstantiationDependent = true;
bool ContainsUnexpandedParameterPack
= ExprBits.ContainsUnexpandedParameterPack;
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *Args,
- Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>(),
+ Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
} else if (TemplateKWLoc.isValid()) {
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc);
}
}
@@ -449,12 +451,11 @@
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
assert(QualifierLoc && "should be created for dependent qualifiers");
- std::size_t size = sizeof(DependentScopeDeclRefExpr);
- if (Args)
- size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size());
- else if (TemplateKWLoc.isValid())
- size += ASTTemplateKWAndArgsInfo::sizeFor(0);
- void *Mem = C.Allocate(size);
+ bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid();
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, Args ? Args->size() : 0);
+ void *Mem = C.Allocate(Size);
return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc,
TemplateKWLoc, NameInfo, Args);
}
@@ -463,10 +464,11 @@
DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- std::size_t size = sizeof(DependentScopeDeclRefExpr);
- if (HasTemplateKWAndArgsInfo)
- size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
- void *Mem = C.Allocate(size);
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs);
+ void *Mem = C.Allocate(Size);
DependentScopeDeclRefExpr *E
= new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(),
SourceLocation(),
@@ -587,19 +589,19 @@
SourceLocation RParenLoc,
SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr)
- + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
CXXStaticCastExpr *E =
new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
RParenLoc, AngleBrackets);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
- void *Buffer =
- C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize);
}
@@ -612,19 +614,19 @@
SourceLocation RParenLoc,
SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr)
- + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
CXXDynamicCastExpr *E =
new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
RParenLoc, AngleBrackets);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
- void *Buffer =
- C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize);
}
@@ -669,19 +671,19 @@
SourceLocation RParenLoc,
SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer =
- C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
CXXReinterpretCastExpr *E =
new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
RParenLoc, AngleBrackets);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
CXXReinterpretCastExpr *
CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
- void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr)
- + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize);
}
@@ -704,18 +706,18 @@
const CXXCastPath *BasePath,
SourceLocation L, SourceLocation R) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
- void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
- + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
CXXFunctionalCastExpr *E =
new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R);
- if (PathSize) E->setCastPath(*BasePath);
+ if (PathSize)
+ std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
+ E->getTrailingObjects<CXXBaseSpecifier *>());
return E;
}
CXXFunctionalCastExpr *
CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
- void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
- + PathSize * sizeof(CXXBaseSpecifier*));
+ void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
@@ -761,14 +763,6 @@
return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
}
-CXXDefaultArgExpr *
-CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc,
- ParmVarDecl *Param, Expr *SubExpr) {
- void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *));
- return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
- SubExpr);
-}
-
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field, QualType T)
: Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
@@ -922,29 +916,22 @@
return CapByCopy ? LCK_ByCopy : LCK_ByRef;
}
-LambdaExpr::LambdaExpr(QualType T,
- SourceRange IntroducerRange,
+LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc,
- ArrayRef<Capture> Captures,
- bool ExplicitParams,
- bool ExplicitResultType,
- ArrayRef<Expr *> CaptureInits,
+ ArrayRef<LambdaCapture> Captures, bool ExplicitParams,
+ bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
bool ContainsUnexpandedParameterPack)
- : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
- T->isDependentType(), T->isDependentType(), T->isDependentType(),
- ContainsUnexpandedParameterPack),
- IntroducerRange(IntroducerRange),
- CaptureDefaultLoc(CaptureDefaultLoc),
- NumCaptures(Captures.size()),
- CaptureDefault(CaptureDefault),
- ExplicitParams(ExplicitParams),
- ExplicitResultType(ExplicitResultType),
- ClosingBrace(ClosingBrace)
-{
+ : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(),
+ T->isDependentType(), T->isDependentType(),
+ ContainsUnexpandedParameterPack),
+ IntroducerRange(IntroducerRange), CaptureDefaultLoc(CaptureDefaultLoc),
+ NumCaptures(Captures.size()), CaptureDefault(CaptureDefault),
+ ExplicitParams(ExplicitParams), ExplicitResultType(ExplicitResultType),
+ ClosingBrace(ClosingBrace) {
assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
CXXRecordDecl *Class = getLambdaClass();
CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData();
@@ -955,8 +942,9 @@
const ASTContext &Context = Class->getASTContext();
Data.NumCaptures = NumCaptures;
Data.NumExplicitCaptures = 0;
- Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
- Capture *ToCapture = Data.Captures;
+ Data.Captures =
+ (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) * NumCaptures);
+ LambdaCapture *ToCapture = Data.Captures;
for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
if (Captures[I].isExplicit())
++Data.NumExplicitCaptures;
@@ -984,30 +972,20 @@
}
}
-LambdaExpr *LambdaExpr::Create(const ASTContext &Context,
- CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- LambdaCaptureDefault CaptureDefault,
- SourceLocation CaptureDefaultLoc,
- ArrayRef<Capture> Captures,
- bool ExplicitParams,
- bool ExplicitResultType,
- ArrayRef<Expr *> CaptureInits,
- ArrayRef<VarDecl *> ArrayIndexVars,
- ArrayRef<unsigned> ArrayIndexStarts,
- SourceLocation ClosingBrace,
- bool ContainsUnexpandedParameterPack) {
+LambdaExpr *LambdaExpr::Create(
+ const ASTContext &Context, CXXRecordDecl *Class,
+ SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault,
+ SourceLocation CaptureDefaultLoc, ArrayRef<LambdaCapture> Captures,
+ bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts,
+ SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
QualType T = Context.getTypeDeclType(Class);
- unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1);
- if (!ArrayIndexVars.empty()) {
- Size += sizeof(unsigned) * (Captures.size() + 1);
- // Realign for following VarDecl array.
- Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<VarDecl*>());
- Size += sizeof(VarDecl *) * ArrayIndexVars.size();
- }
+ unsigned Size = totalSizeToAlloc<Stmt *, unsigned, VarDecl *>(
+ Captures.size() + 1, ArrayIndexVars.empty() ? 0 : Captures.size() + 1,
+ ArrayIndexVars.size());
void *Mem = Context.Allocate(Size);
return new (Mem) LambdaExpr(T, IntroducerRange,
CaptureDefault, CaptureDefaultLoc, Captures,
@@ -1019,10 +997,9 @@
LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C,
unsigned NumCaptures,
unsigned NumArrayIndexVars) {
- unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1);
- if (NumArrayIndexVars)
- Size += sizeof(VarDecl) * NumArrayIndexVars
- + sizeof(unsigned) * (NumCaptures + 1);
+ unsigned Size = totalSizeToAlloc<Stmt *, unsigned, VarDecl *>(
+ NumCaptures + 1, NumArrayIndexVars ? NumCaptures + 1 : 0,
+ NumArrayIndexVars);
void *Mem = C.Allocate(Size);
return new (Mem) LambdaExpr(EmptyShell(), NumCaptures, NumArrayIndexVars > 0);
}
@@ -1106,7 +1083,7 @@
*const_cast<clang::Stmt **>(&getStoredStmts()[NumCaptures]) =
getCallOperator()->getBody();
- return reinterpret_cast<CompoundStmt *>(getStoredStmts()[NumCaptures]);
+ return static_cast<CompoundStmt *>(getStoredStmts()[NumCaptures]);
}
bool LambdaExpr::isMutable() const {
@@ -1123,14 +1100,13 @@
SubExpr(subexpr) {
ExprWithCleanupsBits.NumObjects = objects.size();
for (unsigned i = 0, e = objects.size(); i != e; ++i)
- getObjectsBuffer()[i] = objects[i];
+ getTrailingObjects<CleanupObject>()[i] = objects[i];
}
ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
ArrayRef<CleanupObject> objects) {
- size_t size = sizeof(ExprWithCleanups)
- + objects.size() * sizeof(CleanupObject);
- void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+ void *buffer = C.Allocate(totalSizeToAlloc<CleanupObject>(objects.size()),
+ llvm::alignOf<ExprWithCleanups>());
return new (buffer) ExprWithCleanups(subexpr, objects);
}
@@ -1142,8 +1118,8 @@
ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C,
EmptyShell empty,
unsigned numObjects) {
- size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
- void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+ void *buffer = C.Allocate(totalSizeToAlloc<CleanupObject>(numObjects),
+ llvm::alignOf<ExprWithCleanups>());
return new (buffer) ExprWithCleanups(empty, numObjects);
}
@@ -1163,7 +1139,7 @@
LParenLoc(LParenLoc),
RParenLoc(RParenLoc),
NumArgs(Args.size()) {
- Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1);
+ Expr **StoredArgs = getTrailingObjects<Expr *>();
for (unsigned I = 0; I != Args.size(); ++I) {
if (Args[I]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
@@ -1178,16 +1154,14 @@
SourceLocation LParenLoc,
ArrayRef<Expr*> Args,
SourceLocation RParenLoc) {
- void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
- sizeof(Expr *) * Args.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Args.size()));
return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, RParenLoc);
}
CXXUnresolvedConstructExpr *
CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) {
Stmt::EmptyShell Empty;
- void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
- sizeof(Expr *) * NumArgs);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumArgs));
return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs);
}
@@ -1195,63 +1169,40 @@
return Type->getTypeLoc().getBeginLoc();
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
- Expr *Base, QualType BaseType,
- bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- NamedDecl *FirstQualifierFoundInScope,
- DeclarationNameInfo MemberNameInfo,
- const TemplateArgumentListInfo *TemplateArgs)
- : Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
- VK_LValue, OK_Ordinary, true, true, true,
- ((Base && Base->containsUnexpandedParameterPack()) ||
- (QualifierLoc &&
- QualifierLoc.getNestedNameSpecifier()
- ->containsUnexpandedParameterPack()) ||
- MemberNameInfo.containsUnexpandedParameterPack())),
- Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasTemplateKWAndArgsInfo(TemplateArgs != nullptr ||
- TemplateKWLoc.isValid()),
- OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
- FirstQualifierFoundInScope(FirstQualifierFoundInScope),
- MemberNameInfo(MemberNameInfo) {
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
+ const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow,
+ SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
+ DeclarationNameInfo MemberNameInfo,
+ const TemplateArgumentListInfo *TemplateArgs)
+ : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, VK_LValue,
+ OK_Ordinary, true, true, true,
+ ((Base && Base->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()) ||
+ MemberNameInfo.containsUnexpandedParameterPack())),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasTemplateKWAndArgsInfo(TemplateArgs != nullptr ||
+ TemplateKWLoc.isValid()),
+ OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
+ FirstQualifierFoundInScope(FirstQualifierFoundInScope),
+ MemberNameInfo(MemberNameInfo) {
if (TemplateArgs) {
bool Dependent = true;
bool InstantiationDependent = true;
bool ContainsUnexpandedParameterPack = false;
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
- Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
+ Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
if (ContainsUnexpandedParameterPack)
ExprBits.ContainsUnexpandedParameterPack = true;
} else if (TemplateKWLoc.isValid()) {
- getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
+ getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
+ TemplateKWLoc);
}
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
- Expr *Base, QualType BaseType,
- bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
- NamedDecl *FirstQualifierFoundInScope,
- DeclarationNameInfo MemberNameInfo)
- : Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
- VK_LValue, OK_Ordinary, true, true, true,
- ((Base && Base->containsUnexpandedParameterPack()) ||
- (QualifierLoc &&
- QualifierLoc.getNestedNameSpecifier()->
- containsUnexpandedParameterPack()) ||
- MemberNameInfo.containsUnexpandedParameterPack())),
- Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasTemplateKWAndArgsInfo(false),
- OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
- FirstQualifierFoundInScope(FirstQualifierFoundInScope),
- MemberNameInfo(MemberNameInfo) { }
-
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(const ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
@@ -1261,18 +1212,13 @@
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
- if (!TemplateArgs && !TemplateKWLoc.isValid())
- return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
- IsArrow, OperatorLoc,
- QualifierLoc,
- FirstQualifierFoundInScope,
- MemberNameInfo);
-
+ bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
- std::size_t size = sizeof(CXXDependentScopeMemberExpr)
- + ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
+ void *Mem = C.Allocate(Size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
QualifierLoc,
@@ -1285,22 +1231,18 @@
CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- if (!HasTemplateKWAndArgsInfo)
- return new (C) CXXDependentScopeMemberExpr(C, nullptr, QualType(),
- 0, SourceLocation(),
- NestedNameSpecifierLoc(),
- nullptr, DeclarationNameInfo());
-
- std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
- ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs);
+ void *Mem = C.Allocate(Size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(),
0, SourceLocation(),
NestedNameSpecifierLoc(),
SourceLocation(), nullptr,
DeclarationNameInfo(), nullptr);
- E->HasTemplateKWAndArgsInfo = true;
+ E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
@@ -1365,38 +1307,34 @@
return cast<Expr>(Base)->isImplicitCXXThis();
}
-UnresolvedMemberExpr *
-UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing,
- Expr *Base, QualType BaseType, bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &MemberNameInfo,
- const TemplateArgumentListInfo *TemplateArgs,
- UnresolvedSetIterator Begin,
- UnresolvedSetIterator End) {
- std::size_t size = sizeof(UnresolvedMemberExpr);
- if (TemplateArgs)
- size += ASTTemplateKWAndArgsInfo::sizeFor(TemplateArgs->size());
- else if (TemplateKWLoc.isValid())
- size += ASTTemplateKWAndArgsInfo::sizeFor(0);
+UnresolvedMemberExpr *UnresolvedMemberExpr::Create(
+ const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType,
+ bool IsArrow, SourceLocation OperatorLoc,
+ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
+ const DeclarationNameInfo &MemberNameInfo,
+ const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) {
+ bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, TemplateArgs ? TemplateArgs->size() : 0);
- void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
- return new (Mem) UnresolvedMemberExpr(C,
- HasUnresolvedUsing, Base, BaseType,
- IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
- MemberNameInfo, TemplateArgs, Begin, End);
+ void *Mem = C.Allocate(Size, llvm::alignOf<UnresolvedMemberExpr>());
+ return new (Mem) UnresolvedMemberExpr(
+ C, HasUnresolvedUsing, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc,
+ TemplateKWLoc, MemberNameInfo, TemplateArgs, Begin, End);
}
UnresolvedMemberExpr *
UnresolvedMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- std::size_t size = sizeof(UnresolvedMemberExpr);
- if (HasTemplateKWAndArgsInfo)
- size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+ std::size_t Size =
+ totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
+ void *Mem = C.Allocate(Size, llvm::alignOf<UnresolvedMemberExpr>());
UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell());
E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
@@ -1438,16 +1376,16 @@
SourceLocation RParenLoc,
Optional<unsigned> Length,
ArrayRef<TemplateArgument> PartialArgs) {
- void *Storage = Context.Allocate(
- sizeof(SizeOfPackExpr) + sizeof(TemplateArgument) * PartialArgs.size());
+ void *Storage =
+ Context.Allocate(totalSizeToAlloc<TemplateArgument>(PartialArgs.size()));
return new (Storage) SizeOfPackExpr(Context.getSizeType(), OperatorLoc, Pack,
PackLoc, RParenLoc, Length, PartialArgs);
}
SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
unsigned NumPartialArgs) {
- void *Storage = Context.Allocate(
- sizeof(SizeOfPackExpr) + sizeof(TemplateArgument) * NumPartialArgs);
+ void *Storage =
+ Context.Allocate(totalSizeToAlloc<TemplateArgument>(NumPartialArgs));
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
}
@@ -1474,24 +1412,22 @@
ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
if (Params)
std::uninitialized_copy(Params, Params + NumParams,
- reinterpret_cast<ParmVarDecl **>(this + 1));
+ getTrailingObjects<ParmVarDecl *>());
}
FunctionParmPackExpr *
FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
ArrayRef<ParmVarDecl *> Params) {
- return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
- sizeof(ParmVarDecl*) * Params.size()))
- FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
+ return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(Params.size())))
+ FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
}
FunctionParmPackExpr *
FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
unsigned NumParams) {
- return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
- sizeof(ParmVarDecl*) * NumParams))
- FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
+ return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(NumParams)))
+ FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
}
void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
@@ -1528,8 +1464,8 @@
TypeTraitExprBits.Value = Value;
TypeTraitExprBits.NumArgs = Args.size();
- TypeSourceInfo **ToArgs = getTypeSourceInfos();
-
+ TypeSourceInfo **ToArgs = getTrailingObjects<TypeSourceInfo *>();
+
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (Args[I]->getType()->isDependentType())
setValueDependent(true);
@@ -1548,15 +1484,13 @@
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc,
bool Value) {
- unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * Args.size();
- void *Mem = C.Allocate(Size);
+ void *Mem = C.Allocate(totalSizeToAlloc<TypeSourceInfo *>(Args.size()));
return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
}
TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
unsigned NumArgs) {
- unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs;
- void *Mem = C.Allocate(Size);
+ void *Mem = C.Allocate(totalSizeToAlloc<TypeSourceInfo *>(NumArgs));
return new (Mem) TypeTraitExpr(EmptyShell());
}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index a5a4435..a47b03c 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -136,6 +136,7 @@
case Expr::ObjCIvarRefExprClass:
case Expr::FunctionParmPackExprClass:
case Expr::MSPropertyRefExprClass:
+ case Expr::MSPropertySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
return Cl::CL_LValue;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index eb1c498..eaa61ea 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -473,6 +473,10 @@
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
+ /// \brief Have we emitted a diagnostic explaining why we couldn't constant
+ /// fold (not just why it's not strictly a constant expression)?
+ bool HasFoldFailureDiagnostic;
+
enum EvaluationMode {
/// Evaluate as a constant expression. Stop if we find that the expression
/// is not a constant expression.
@@ -537,7 +541,7 @@
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
@@ -597,7 +601,7 @@
/// Diagnose that the evaluation cannot be folded.
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
+ unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
if (EvalStatus.Diag) {
// If we have a prior diagnostic, it will be noting that the expression
// isn't a constant expression. This diagnostic is more important,
@@ -610,10 +614,9 @@
case EM_ConstantFold:
case EM_IgnoreSideEffects:
case EM_EvaluateForOverflow:
- if (!EvalStatus.HasSideEffects)
+ if (!HasFoldFailureDiagnostic)
break;
- // We've had side-effects; we want the diagnostic from them, not
- // some later problem.
+ // We've already failed to fold something. Keep that diagnostic.
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
case EM_ConstantExpressionUnevaluated:
@@ -632,6 +635,7 @@
CallStackNotes = 0;
HasActiveDiagnostic = true;
+ HasFoldFailureDiagnostic = !IsCCEDiag;
EvalStatus.Diag->clear();
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
addDiag(Loc, DiagId);
@@ -645,9 +649,9 @@
OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
+ unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
if (EvalStatus.Diag)
- return Diag(E->getExprLoc(), DiagId, ExtraNotes);
+ return Diag(E->getExprLoc(), DiagId, ExtraNotes, IsCCEDiag);
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
@@ -667,7 +671,7 @@
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
- return Diag(Loc, DiagId, ExtraNotes);
+ return Diag(Loc, DiagId, ExtraNotes, true);
}
/// Add a note to a prior diagnostic.
@@ -711,6 +715,32 @@
return keepEvaluatingAfterSideEffect();
}
+ /// Should we continue evaluation after encountering undefined behavior?
+ bool keepEvaluatingAfterUndefinedBehavior() {
+ switch (EvalMode) {
+ case EM_EvaluateForOverflow:
+ case EM_IgnoreSideEffects:
+ case EM_ConstantFold:
+ case EM_DesignatorFold:
+ return true;
+
+ case EM_PotentialConstantExpression:
+ case EM_PotentialConstantExpressionUnevaluated:
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Note that we hit something that was technically undefined behavior, but
+ /// that we can evaluate past it (such as signed overflow or floating-point
+ /// division by zero.)
+ bool noteUndefinedBehavior() {
+ EvalStatus.HasUndefinedBehavior = true;
+ return keepEvaluatingAfterUndefinedBehavior();
+ }
+
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be reduced to a value?
bool keepEvaluatingAfterFailure() {
@@ -1150,12 +1180,13 @@
static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
EvalInfo &Info);
static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
-static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
+static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
//===----------------------------------------------------------------------===//
// Misc utilities
@@ -1540,10 +1571,11 @@
}
template<typename T>
-static void HandleOverflow(EvalInfo &Info, const Expr *E,
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
const T &SrcValue, QualType DestType) {
Info.CCEDiag(E, diag::note_constexpr_overflow)
<< SrcValue << DestType;
+ return Info.noteUndefinedBehavior();
}
static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
@@ -1557,7 +1589,7 @@
bool ignored;
if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
& APFloat::opInvalidOp)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -1569,13 +1601,13 @@
if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
APFloat::rmNearestTiesToEven, &ignored)
& APFloat::opOverflow)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
QualType DestType, QualType SrcType,
- APSInt &Value) {
+ const APSInt &Value) {
unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
APSInt Result = Value;
// Figure out if this is a truncate, extend or noop cast.
@@ -1592,7 +1624,7 @@
if (Result.convertFromAPInt(Value, Value.isSigned(),
APFloat::rmNearestTiesToEven)
& APFloat::opOverflow)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -1668,23 +1700,26 @@
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
template<typename Operation>
-static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &LHS, const APSInt &RHS,
- unsigned BitWidth, Operation Op) {
- if (LHS.isUnsigned())
- return Op(LHS, RHS);
+static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op,
+ APSInt &Result) {
+ if (LHS.isUnsigned()) {
+ Result = Op(LHS, RHS);
+ return true;
+ }
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
- APSInt Result = Value.trunc(LHS.getBitWidth());
+ Result = Value.trunc(LHS.getBitWidth());
if (Result.extend(BitWidth) != Value) {
if (Info.checkingForOverflow())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_integer_constant_overflow)
+ diag::warn_integer_constant_overflow)
<< Result.toString(10) << E->getType();
else
- HandleOverflow(Info, E, Value, E->getType());
+ return HandleOverflow(Info, E, Value, E->getType());
}
- return Result;
+ return true;
}
/// Perform the given binary integer operation.
@@ -1696,17 +1731,14 @@
Info.Diag(E);
return false;
case BO_Mul:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
- std::multiplies<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>(), Result);
case BO_Add:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
- std::plus<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::plus<APSInt>(), Result);
case BO_Sub:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
- std::minus<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::minus<APSInt>(), Result);
case BO_And: Result = LHS & RHS; return true;
case BO_Xor: Result = LHS ^ RHS; return true;
case BO_Or: Result = LHS | RHS; return true;
@@ -1716,11 +1748,13 @@
Info.Diag(E, diag::note_expr_divide_by_zero);
return false;
}
- // Check for overflow case: INT_MIN / -1 or INT_MIN % -1.
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports
+ // this operation and gives the two's complement result.
if (RHS.isNegative() && RHS.isAllOnesValue() &&
LHS.isSigned() && LHS.isMinSignedValue())
- HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
- Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1),
+ E->getType());
return true;
case BO_Shl: {
if (Info.getLangOpts().OpenCL)
@@ -1808,8 +1842,10 @@
break;
}
- if (LHS.isInfinity() || LHS.isNaN())
+ if (LHS.isInfinity() || LHS.isNaN()) {
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+ return Info.noteUndefinedBehavior();
+ }
return true;
}
@@ -3008,7 +3044,7 @@
if (!WasNegative && Value.isNegative() &&
isOverflowingIntegerType(Info.Ctx, SubobjType)) {
APSInt ActualValue(Value, /*IsUnsigned*/true);
- HandleOverflow(Info, E, ActualValue, SubobjType);
+ return HandleOverflow(Info, E, ActualValue, SubobjType);
}
} else {
--Value;
@@ -3018,7 +3054,7 @@
unsigned BitWidth = Value.getBitWidth();
APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
ActualValue.setBit(BitWidth);
- HandleOverflow(Info, E, ActualValue, SubobjType);
+ return HandleOverflow(Info, E, ActualValue, SubobjType);
}
}
return true;
@@ -5099,7 +5135,7 @@
}
// The offset must also have the correct alignment.
- if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) {
+ if (OffsetResult.Offset.alignTo(Align) != OffsetResult.Offset) {
Result.Designator.setInvalid();
APSInt Offset(64, false);
Offset = OffsetResult.Offset.getQuantity();
@@ -5619,7 +5655,7 @@
return VectorExprEvaluator(Info, Result).Visit(E);
}
-bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
+bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
const VectorType *VTy = E->getType()->castAs<VectorType>();
unsigned NElts = VTy->getNumElements();
@@ -5632,13 +5668,13 @@
if (SETy->isIntegerType()) {
APSInt IntResult;
if (!EvaluateInteger(SE, IntResult, Info))
- return false;
- Val = APValue(IntResult);
+ return false;
+ Val = APValue(std::move(IntResult));
} else if (SETy->isRealFloatingType()) {
- APFloat F(0.0);
- if (!EvaluateFloat(SE, F, Info))
- return false;
- Val = APValue(F);
+ APFloat FloatResult(0.0);
+ if (!EvaluateFloat(SE, FloatResult, Info))
+ return false;
+ Val = APValue(std::move(FloatResult));
} else {
return Error(E);
}
@@ -6239,8 +6275,8 @@
APValue &V = Result.Val;
if (V.getKind() == APValue::Int)
return true;
-
- return EvaluateBuiltinConstantPForLValue(V);
+ if (V.getKind() == APValue::LValue)
+ return EvaluateBuiltinConstantPForLValue(V);
} else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
return Arg->isEvaluatable(Ctx);
} else if (ArgType->isPointerType() || Arg->isGLValue()) {
@@ -6377,8 +6413,28 @@
return false;
}
-bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
- unsigned Type) {
+/// Tries to evaluate the __builtin_object_size for @p E. If successful, returns
+/// true and stores the result in @p Size.
+///
+/// If @p WasError is non-null, this will report whether the failure to evaluate
+/// is to be treated as an Error in IntExprEvaluator.
+static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
+ EvalInfo &Info, uint64_t &Size,
+ bool *WasError = nullptr) {
+ if (WasError != nullptr)
+ *WasError = false;
+
+ auto Error = [&](const Expr *E) {
+ if (WasError != nullptr)
+ *WasError = true;
+ return false;
+ };
+
+ auto Success = [&](uint64_t S, const Expr *E) {
+ Size = S;
+ return true;
+ };
+
// Determine the denoted object.
LValue Base;
{
@@ -6387,8 +6443,15 @@
// ignore the side-effects.
SpeculativeEvaluationRAII SpeculativeEval(Info);
FoldOffsetRAII Fold(Info, Type & 1);
- const Expr *Ptr = ignorePointerCastsAndParens(E->getArg(0));
- if (!EvaluatePointer(Ptr, Base, Info))
+
+ if (E->isGLValue()) {
+ // It's possible for us to be given GLValues if we're called via
+ // Expr::tryEvaluateObjectSize.
+ APValue RVal;
+ if (!EvaluateAsRValue(Info, E, RVal))
+ return false;
+ Base.setFrom(Info.Ctx, RVal);
+ } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), Base, Info))
return false;
}
@@ -6447,7 +6510,7 @@
End.Designator.Entries.size() == End.Designator.MostDerivedPathLength) {
// We got a pointer to an array. Step to its end.
AmountToAdd = End.Designator.MostDerivedArraySize -
- End.Designator.Entries.back().ArrayIndex;
+ End.Designator.Entries.back().ArrayIndex;
} else if (End.Designator.isOnePastTheEnd()) {
// We're already pointing at the end of the object.
AmountToAdd = 0;
@@ -6484,7 +6547,18 @@
if (BaseOffset > EndOffset)
return Success(0, E);
- return Success(EndOffset - BaseOffset, E);
+ return Success((EndOffset - BaseOffset).getQuantity(), E);
+}
+
+bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
+ unsigned Type) {
+ uint64_t Size;
+ bool WasError;
+ if (::tryEvaluateBuiltinObjectSize(E->getArg(0), Type, Info, Size, &WasError))
+ return Success(Size, E);
+ if (WasError)
+ return Error(E);
+ return false;
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
@@ -6501,12 +6575,7 @@
if (TryEvaluateBuiltinObjectSize(E, Type))
return true;
- // If evaluating the argument has side-effects, we can't determine the size
- // of the object, and so we lower it to unknown now. CodeGen relies on us to
- // handle all cases where the expression has side-effects.
- // Likewise, if Type is 3, we must handle this because CodeGen cannot give a
- // conservatively correct answer in that case.
- if (E->getArg(0)->HasSideEffects(Info.Ctx) || Type == 3)
+ if (E->getArg(0)->HasSideEffects(Info.Ctx))
return Success((Type & 2) ? 0 : -1, E);
// Expression had no side effects, but we couldn't statically determine the
@@ -7224,7 +7293,7 @@
LValue LHSValue, RHSValue;
bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info);
- if (!LHSOK && Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
@@ -7236,21 +7305,20 @@
if (E->getOpcode() == BO_Sub) {
// Handle &&A - &&B.
if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero())
- return false;
+ return Error(E);
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>();
if (!LHSExpr || !RHSExpr)
- return false;
+ return Error(E);
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr);
if (!LHSAddrExpr || !RHSAddrExpr)
- return false;
+ return Error(E);
// Make sure both labels come from the same function.
if (LHSAddrExpr->getLabel()->getDeclContext() !=
RHSAddrExpr->getLabel()->getDeclContext())
- return false;
- Result = APValue(LHSAddrExpr, RHSAddrExpr);
- return true;
+ return Error(E);
+ return Success(APValue(LHSAddrExpr, RHSAddrExpr), E);
}
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
@@ -7341,8 +7409,9 @@
APSInt TrueResult = (LHS - RHS) / ElemSize;
APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType()));
- if (Result.extend(65) != TrueResult)
- HandleOverflow(Info, E, TrueResult, E->getType());
+ if (Result.extend(65) != TrueResult &&
+ !HandleOverflow(Info, E, TrueResult, E->getType()))
+ return false;
return Success(Result, E);
}
@@ -7548,9 +7617,9 @@
return Error(OOE);
QualType CurrentType = OOE->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
- OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
+ OffsetOfNode ON = OOE->getComponent(i);
switch (ON.getKind()) {
- case OffsetOfExpr::OffsetOfNode::Array: {
+ case OffsetOfNode::Array: {
const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
APSInt IdxResult;
if (!EvaluateInteger(Idx, IdxResult, Info))
@@ -7564,7 +7633,7 @@
break;
}
- case OffsetOfExpr::OffsetOfNode::Field: {
+ case OffsetOfNode::Field: {
FieldDecl *MemberDecl = ON.getField();
const RecordType *RT = CurrentType->getAs<RecordType>();
if (!RT)
@@ -7579,10 +7648,10 @@
break;
}
- case OffsetOfExpr::OffsetOfNode::Identifier:
+ case OffsetOfNode::Identifier:
llvm_unreachable("dependent __builtin_offsetof");
- case OffsetOfExpr::OffsetOfNode::Base: {
+ case OffsetOfNode::Base: {
CXXBaseSpecifier *BaseSpec = ON.getBase();
if (BaseSpec->isVirtual())
return Error(OOE);
@@ -7628,9 +7697,10 @@
return false;
if (!Result.isInt()) return Error(E);
const APSInt &Value = Result.getInt();
- if (Value.isSigned() && Value.isMinSignedValue())
- HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
- E->getType());
+ if (Value.isSigned() && Value.isMinSignedValue() &&
+ !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+ E->getType()))
+ return false;
return Success(-Value, E);
}
case UO_Not: {
@@ -7711,12 +7781,16 @@
case CK_PointerToBoolean:
case CK_IntegralToBoolean:
case CK_FloatingToBoolean:
+ case CK_BooleanToSignedIntegral:
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean: {
bool BoolResult;
if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
return false;
- return Success(BoolResult, E);
+ uint64_t IntResult = BoolResult;
+ if (BoolResult && E->getCastKind() == CK_BooleanToSignedIntegral)
+ IntResult = (uint64_t)-1;
+ return Success(IntResult, E);
}
case CK_IntegralCast: {
@@ -8153,6 +8227,7 @@
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
@@ -8790,6 +8865,12 @@
HandleConversionToBool(Scratch.Val, Result);
}
+static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result,
+ Expr::SideEffectsKind SEK) {
+ return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) ||
+ (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior);
+}
+
bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
SideEffectsKind AllowSideEffects) const {
if (!getType()->isIntegralOrEnumerationType())
@@ -8797,7 +8878,7 @@
EvalResult ExprResult;
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
- (!AllowSideEffects && ExprResult.HasSideEffects))
+ hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
return false;
Result = ExprResult.Val.getInt();
@@ -8829,7 +8910,9 @@
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold);
+ EvalInfo InitInfo(Ctx, EStatus, VD->isConstexpr()
+ ? EvalInfo::EM_ConstantExpression
+ : EvalInfo::EM_ConstantFold);
InitInfo.setEvaluatingDecl(VD, Value);
LValue LVal;
@@ -8858,9 +8941,10 @@
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded, but discard the result.
-bool Expr::isEvaluatable(const ASTContext &Ctx) const {
+bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
EvalResult Result;
- return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
+ return EvaluateAsRValue(Result, Ctx) &&
+ !hasUnacceptableSideEffect(Result, SEK);
}
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
@@ -8974,6 +9058,7 @@
case Expr::CXXTypeidExprClass:
case Expr::CXXUuidofExprClass:
case Expr::MSPropertyRefExprClass:
+ case Expr::MSPropertySubscriptExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::UserDefinedLiteralClass:
case Expr::CXXThisExprClass:
@@ -9360,7 +9445,11 @@
if (!isIntegerConstantExpr(Ctx, Loc))
return false;
- if (!EvaluateAsInt(Value, Ctx))
+ // The only possible side-effects here are due to UB discovered in the
+ // evaluation (for instance, INT_MAX + 1). In such a case, we are still
+ // required to treat the expression as an ICE, so we produce the folded
+ // value.
+ if (!EvaluateAsInt(Value, Ctx, SE_AllowSideEffects))
llvm_unreachable("ICE cannot be evaluated!");
return true;
}
@@ -9482,3 +9571,13 @@
Evaluate(ResultScratch, Info, E);
return Diags.empty();
}
+
+bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx,
+ unsigned Type) const {
+ if (!getType()->isPointerType())
+ return false;
+
+ Expr::EvalStatus Status;
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
+ return ::tryEvaluateBuiltinObjectSize(this, Type, Info, Result);
+}
diff --git a/lib/AST/ExprObjC.cpp b/lib/AST/ExprObjC.cpp
index 46298c7..0936a81 100644
--- a/lib/AST/ExprObjC.cpp
+++ b/lib/AST/ExprObjC.cpp
@@ -39,16 +39,14 @@
ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl *Method,
SourceRange SR) {
- void *Mem =
- C.Allocate(sizeof(ObjCArrayLiteral) + Elements.size() * sizeof(Expr *));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Elements.size()));
return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR);
}
ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C,
unsigned NumElements) {
- void *Mem =
- C.Allocate(sizeof(ObjCArrayLiteral) + NumElements * sizeof(Expr *));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumElements));
return new (Mem) ObjCArrayLiteral(EmptyShell(), NumElements);
}
@@ -60,8 +58,9 @@
false, false),
NumElements(VK.size()), HasPackExpansions(HasPackExpansions), Range(SR),
DictWithObjectsMethod(method) {
- KeyValuePair *KeyValues = getKeyValues();
- ExpansionData *Expansions = getExpansionData();
+ KeyValuePair *KeyValues = getTrailingObjects<KeyValuePair>();
+ ExpansionData *Expansions =
+ HasPackExpansions ? getTrailingObjects<ExpansionData>() : nullptr;
for (unsigned I = 0; I < NumElements; I++) {
if (VK[I].Key->isTypeDependent() || VK[I].Key->isValueDependent() ||
VK[I].Value->isTypeDependent() || VK[I].Value->isValueDependent())
@@ -91,23 +90,16 @@
ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions, QualType T,
ObjCMethodDecl *method, SourceRange SR) {
- unsigned ExpansionsSize = 0;
- if (HasPackExpansions)
- ExpansionsSize = sizeof(ExpansionData) * VK.size();
-
- void *Mem = C.Allocate(sizeof(ObjCDictionaryLiteral) +
- sizeof(KeyValuePair) * VK.size() + ExpansionsSize);
+ void *Mem = C.Allocate(totalSizeToAlloc<KeyValuePair, ExpansionData>(
+ VK.size(), HasPackExpansions ? VK.size() : 0));
return new (Mem) ObjCDictionaryLiteral(VK, HasPackExpansions, T, method, SR);
}
ObjCDictionaryLiteral *
ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements,
bool HasPackExpansions) {
- unsigned ExpansionsSize = 0;
- if (HasPackExpansions)
- ExpansionsSize = sizeof(ExpansionData) * NumElements;
- void *Mem = C.Allocate(sizeof(ObjCDictionaryLiteral) +
- sizeof(KeyValuePair) * NumElements + ExpansionsSize);
+ void *Mem = C.Allocate(totalSizeToAlloc<KeyValuePair, ExpansionData>(
+ NumElements, HasPackExpansions ? NumElements : 0));
return new (Mem)
ObjCDictionaryLiteral(EmptyShell(), NumElements, HasPackExpansions);
}
@@ -122,15 +114,6 @@
return getBase()->getType();
}
-ObjCSubscriptRefExpr *
-ObjCSubscriptRefExpr::Create(const ASTContext &C, Expr *base, Expr *key,
- QualType T, ObjCMethodDecl *getMethod,
- ObjCMethodDecl *setMethod, SourceLocation RB) {
- void *Mem = C.Allocate(sizeof(ObjCSubscriptRefExpr));
- return new (Mem) ObjCSubscriptRefExpr(
- base, key, T, VK_LValue, OK_ObjCSubscript, getMethod, setMethod, RB);
-}
-
ObjCMessageExpr::ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc, bool IsInstanceSuper,
@@ -293,11 +276,9 @@
ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, unsigned NumArgs,
unsigned NumStoredSelLocs) {
- unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
- NumArgs * sizeof(Expr *) +
- NumStoredSelLocs * sizeof(SourceLocation);
return (ObjCMessageExpr *)C.Allocate(
- Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ totalSizeToAlloc<void *, SourceLocation>(NumArgs + 1, NumStoredSelLocs),
+ llvm::AlignOf<ObjCMessageExpr>::Alignment);
}
void ObjCMessageExpr::getSelectorLocs(
@@ -358,7 +339,7 @@
Stmt::child_range ObjCMessageExpr::children() {
Stmt **begin;
if (getReceiverKind() == Instance)
- begin = reinterpret_cast<Stmt **>(this + 1);
+ begin = reinterpret_cast<Stmt **>(getTrailingObjects<void *>());
else
begin = reinterpret_cast<Stmt **>(getArgs());
return child_range(begin,
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index c343283..3f6b682 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -377,8 +377,8 @@
void mangleType(const TagType*);
void mangleType(TemplateName);
- void mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType);
+ void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType,
+ const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
void mangleAArch64NeonVectorType(const VectorType *T);
@@ -395,7 +395,8 @@
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
- void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
+ void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
+ unsigned NumTemplateArgs);
void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
void mangleTemplateArgs(const TemplateArgumentList &AL);
@@ -523,7 +524,7 @@
}
mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
- MangleReturnType);
+ MangleReturnType, FD);
}
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
@@ -1017,7 +1018,7 @@
unsigned UnnamedMangle = getASTContext().getManglingNumber(TD);
Out << "Ut";
if (UnnamedMangle > 1)
- Out << llvm::utostr(UnnamedMangle - 2);
+ Out << UnnamedMangle - 2;
Out << '_';
break;
}
@@ -1282,7 +1283,8 @@
Out << "Ul";
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
getAs<FunctionProtoType>();
- mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
+ Lambda->getLambdaStaticInvoker());
Out << "E";
// The number is omitted for the first closure type with a given
@@ -1507,6 +1509,7 @@
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::Atomic:
+ case Type::Pipe:
llvm_unreachable("type is illegal as a nested name specifier");
case Type::SubstTemplateTypeParmPack:
@@ -2171,7 +2174,8 @@
}
void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType) {
+ bool MangleReturnType,
+ const FunctionDecl *FD) {
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
@@ -2194,8 +2198,19 @@
return;
}
- for (const auto &Arg : Proto->param_types())
- mangleType(Context.getASTContext().getSignatureParameterType(Arg));
+ assert(!FD || FD->getNumParams() == Proto->getNumParams());
+ for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
+ const auto &ParamTy = Proto->getParamType(I);
+ mangleType(Context.getASTContext().getSignatureParameterType(ParamTy));
+
+ if (FD) {
+ if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
+ // Attr can only take 1 character, so we can hardcode the length below.
+ assert(Attr->getType() <= 9 && Attr->getType() >= 0);
+ Out << "U17pass_object_size" << Attr->getType();
+ }
+ }
+ }
FunctionTypeDepth.pop(saved);
@@ -2436,7 +2451,7 @@
EltName = mangleAArch64VectorBase(cast<BuiltinType>(EltType));
std::string TypeName =
- ("__" + EltName + "x" + llvm::utostr(T->getNumElements()) + "_t").str();
+ ("__" + EltName + "x" + Twine(T->getNumElements()) + "_t").str();
Out << TypeName.length() << TypeName;
}
@@ -2653,9 +2668,11 @@
void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
// <builtin-type> ::= Da # dependent auto
- if (D.isNull())
+ if (D.isNull()) {
+ assert(T->getKeyword() != AutoTypeKeyword::GNUAutoType &&
+ "shouldn't need to mangle __auto_type!");
Out << (T->isDecltypeAuto() ? "Dc" : "Da");
- else
+ } else
mangleType(D);
}
@@ -2666,6 +2683,13 @@
mangleType(T->getValueType());
}
+void CXXNameMangler::mangleType(const PipeType *T) {
+ // Pipe type mangling rules are described in SPIR 2.0 specification
+ // A.1 Data types and A.3 Summary of changes
+ // <type> ::= 8ocl_pipe
+ Out << "8ocl_pipe";
+}
+
void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
@@ -2809,6 +2833,7 @@
case Expr::ParenListExprClass:
case Expr::LambdaExprClass:
case Expr::MSPropertyRefExprClass:
+ case Expr::MSPropertySubscriptExprClass:
case Expr::TypoExprClass: // This should no longer exist in the AST by now.
case Expr::OMPArraySectionExprClass:
llvm_unreachable("unexpected statement kind");
@@ -3019,7 +3044,7 @@
ME->isArrow(), ME->getQualifier(), nullptr,
ME->getMemberName(), Arity);
if (ME->hasExplicitTemplateArgs())
- mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ mangleTemplateArgs(ME->getTemplateArgs(), ME->getNumTemplateArgs());
break;
}
@@ -3031,7 +3056,7 @@
ME->getFirstQualifierFoundInScope(),
ME->getMember(), Arity);
if (ME->hasExplicitTemplateArgs())
- mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ mangleTemplateArgs(ME->getTemplateArgs(), ME->getNumTemplateArgs());
break;
}
@@ -3043,7 +3068,7 @@
// base-unresolved-name, where <template-args> are just tacked
// onto the end.
if (ULE->hasExplicitTemplateArgs())
- mangleTemplateArgs(ULE->getExplicitTemplateArgs());
+ mangleTemplateArgs(ULE->getTemplateArgs(), ULE->getNumTemplateArgs());
break;
}
@@ -3365,7 +3390,7 @@
// base-unresolved-name, where <template-args> are just tacked
// onto the end.
if (DRE->hasExplicitTemplateArgs())
- mangleTemplateArgs(DRE->getExplicitTemplateArgs());
+ mangleTemplateArgs(DRE->getTemplateArgs(), DRE->getNumTemplateArgs());
break;
}
@@ -3633,12 +3658,12 @@
}
}
-void CXXNameMangler::mangleTemplateArgs(
- const ASTTemplateArgumentListInfo &TemplateArgs) {
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
+ unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
- for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
- mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument());
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(TemplateArgs[i].getArgument());
Out << 'E';
}
@@ -4225,4 +4250,3 @@
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
}
-
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 014338f..b1193ca 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -177,9 +177,9 @@
++ArgWords;
for (const auto &AT : Proto->param_types())
// Size should be aligned to pointer size.
- ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT),
- TI.getPointerWidth(0)) /
- TI.getPointerWidth(0);
+ ArgWords +=
+ llvm::alignTo(ASTContext.getTypeSize(AT), TI.getPointerWidth(0)) /
+ TI.getPointerWidth(0);
Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 6ba31cc..3ae0453 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -262,7 +262,7 @@
Align = Target.getIntAlign();
if (Target.getTriple().isArch64Bit())
- Width = llvm::RoundUpToAlignment(Width, Align);
+ Width = llvm::alignTo(Width, Align);
return std::make_pair(Width, Align);
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5c30ae2..0634319 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -127,8 +127,6 @@
CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) override;
- void mangleCXXCatchHandlerType(QualType T, uint32_t Flags,
- raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -162,14 +160,17 @@
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
- // Lambda closure types are already numbered.
- if (isLambda(ND))
- return false;
-
const DeclContext *DC = getEffectiveDeclContext(ND);
if (!DC->isFunctionOrMethod())
return false;
+ // Lambda closure types are already numbered, give out a phony number so
+ // that they demangle nicely.
+ if (isLambda(ND)) {
+ disc = 1;
+ return true;
+ }
+
// Use the canonical number for externally visible decls.
if (ND->isExternallyVisible()) {
disc = getASTContext().getManglingNumber(ND);
@@ -221,9 +222,12 @@
typedef llvm::SmallVector<std::string, 10> BackRefVec;
BackRefVec NameBackReferences;
- typedef llvm::DenseMap<void *, unsigned> ArgBackRefMap;
+ typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap;
ArgBackRefMap TypeBackReferences;
+ typedef std::set<int> PassObjectSizeArgsSet;
+ PassObjectSizeArgsSet PassObjectSizeArgs;
+
ASTContext &getASTContext() const { return Context.getASTContext(); }
// FIXME: If we add support for __ptr32/64 qualifiers, then we should push
@@ -263,6 +267,9 @@
const CXXMethodDecl *MD,
const MicrosoftVTableContext::MethodVFTableLocation &ML);
void mangleNumber(int64_t Number);
+ void mangleTagTypeKind(TagTypeKind TK);
+ void mangleArtificalTagType(TagTypeKind TK, StringRef UnqualifiedName,
+ ArrayRef<StringRef> NestedNames = None);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
void mangleFunctionType(const FunctionType *T,
@@ -290,6 +297,7 @@
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleArgumentType(QualType T, SourceRange Range);
+ void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA);
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -392,14 +400,8 @@
mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD));
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleVariableEncoding(VD);
- else {
- // TODO: Fields? Can MSVC even mangle them?
- // Issue a diagnostic for now.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "cannot mangle this declaration yet");
- Diags.Report(D->getLocation(), DiagID) << D->getSourceRange();
- }
+ else
+ llvm_unreachable("Tried to mangle unexpected NamedDecl!");
}
void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD,
@@ -422,7 +424,7 @@
// We would like to mangle all extern "C" functions using this additional
// component but this would break compatibility with MSVC's behavior.
// Instead, do this when we know that compatibility isn't important (in
- // other words, when it is an overloaded extern "C" funciton).
+ // other words, when it is an overloaded extern "C" function).
if (FD->isExternC() && FD->hasAttr<OverloadableAttr>())
Out << "$$J0";
@@ -697,8 +699,7 @@
// Function templates aren't considered for name back referencing. This
// makes sense since function templates aren't likely to occur multiple
// times in a symbol.
- // FIXME: Test alias template mangling with MSVC 2013.
- if (!isa<ClassTemplateDecl>(TD)) {
+ if (isa<FunctionTemplateDecl>(TD)) {
mangleTemplateInstantiationName(TD, *TemplateArgs);
Out << '@';
return;
@@ -1087,8 +1088,10 @@
// Templates have their own context for back references.
ArgBackRefMap OuterArgsContext;
BackRefVec OuterTemplateContext;
+ PassObjectSizeArgsSet OuterPassObjectSizeArgs;
NameBackReferences.swap(OuterTemplateContext);
TypeBackReferences.swap(OuterArgsContext);
+ PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(TD, TemplateArgs);
@@ -1096,6 +1099,7 @@
// Restore the previous back reference contexts.
NameBackReferences.swap(OuterTemplateContext);
TypeBackReferences.swap(OuterArgsContext);
+ PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
}
void
@@ -1137,12 +1141,6 @@
UE = dyn_cast<CXXUuidofExpr>(E);
if (UE) {
- // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from
- // const __s_GUID _GUID_{lower case UUID with underscores}
- StringRef Uuid = UE->getUuidAsStringRef(Context.getASTContext());
- std::string Name = "_GUID_" + Uuid.lower();
- std::replace(Name.begin(), Name.end(), '-', '_');
-
// If we had to peek through an address-of operator, treat this like we are
// dealing with a pointer type. Otherwise, treat it like a const reference.
//
@@ -1152,7 +1150,22 @@
Out << "$E?";
else
Out << "$1?";
- Out << Name << "@@3U__s_GUID@@B";
+
+ // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from
+ // const __s_GUID _GUID_{lower case UUID with underscores}
+ StringRef Uuid = UE->getUuidAsStringRef(Context.getASTContext());
+ std::string Name = "_GUID_" + Uuid.lower();
+ std::replace(Name.begin(), Name.end(), '-', '_');
+
+ mangleSourceName(Name);
+ // Terminate the whole name with an '@'.
+ Out << '@';
+ // It's a global variable.
+ Out << '3';
+ // It's a struct called __s_GUID.
+ mangleArtificalTagType(TTK_Struct, "__s_GUID");
+ // It's const.
+ Out << 'B';
return;
}
@@ -1226,12 +1239,13 @@
QualType T = TA.getNullPtrType();
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- if (MPT->isMemberFunctionPointerType() && isa<ClassTemplateDecl>(TD)) {
+ if (MPT->isMemberFunctionPointerType() &&
+ !isa<FunctionTemplateDecl>(TD)) {
mangleMemberFunctionPointer(RD, nullptr);
return;
}
if (MPT->isMemberDataPointer()) {
- if (isa<ClassTemplateDecl>(TD)) {
+ if (!isa<FunctionTemplateDecl>(TD)) {
mangleMemberDataPointer(RD, nullptr);
return;
}
@@ -1471,6 +1485,27 @@
}
}
+void MicrosoftCXXNameMangler::manglePassObjectSizeArg(
+ const PassObjectSizeAttr *POSA) {
+ int Type = POSA->getType();
+
+ auto Iter = PassObjectSizeArgs.insert(Type).first;
+ auto *TypePtr = (const void *)&*Iter;
+ ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
+
+ if (Found == TypeBackReferences.end()) {
+ mangleArtificalTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type),
+ {"__clang"});
+
+ if (TypeBackReferences.size() < 10) {
+ size_t Size = TypeBackReferences.size();
+ TypeBackReferences[TypePtr] = Size;
+ }
+ } else {
+ Out << Found->second;
+ }
+}
+
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM) {
// Don't use the canonical types. MSVC includes things like 'const' on
@@ -1637,68 +1672,89 @@
llvm_unreachable("placeholder types shouldn't get to name mangling");
case BuiltinType::ObjCId:
- Out << "PAUobjc_object@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "objc_object");
break;
case BuiltinType::ObjCClass:
- Out << "PAUobjc_class@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "objc_class");
break;
case BuiltinType::ObjCSel:
- Out << "PAUobjc_selector@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "objc_selector");
break;
case BuiltinType::OCLImage1d:
- Out << "PAUocl_image1d@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image1d");
break;
case BuiltinType::OCLImage1dArray:
- Out << "PAUocl_image1darray@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image1darray");
break;
case BuiltinType::OCLImage1dBuffer:
- Out << "PAUocl_image1dbuffer@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image1dbuffer");
break;
case BuiltinType::OCLImage2d:
- Out << "PAUocl_image2d@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2d");
break;
case BuiltinType::OCLImage2dArray:
- Out << "PAUocl_image2darray@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2darray");
break;
case BuiltinType::OCLImage2dDepth:
- Out << "PAUocl_image2ddepth@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2ddepth");
break;
case BuiltinType::OCLImage2dArrayDepth:
- Out << "PAUocl_image2darraydepth@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2darraydepth");
break;
case BuiltinType::OCLImage2dMSAA:
- Out << "PAUocl_image2dmsaa@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2dmsaa");
break;
case BuiltinType::OCLImage2dArrayMSAA:
- Out << "PAUocl_image2darraymsaa@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2darraymsaa");
break;
case BuiltinType::OCLImage2dMSAADepth:
- Out << "PAUocl_image2dmsaadepth@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2dmsaadepth");
break;
case BuiltinType::OCLImage2dArrayMSAADepth:
- Out << "PAUocl_image2darraymsaadepth@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image2darraymsaadepth");
break;
case BuiltinType::OCLImage3d:
- Out << "PAUocl_image3d@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_image3d");
break;
case BuiltinType::OCLSampler:
- Out << "PAUocl_sampler@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_sampler");
break;
case BuiltinType::OCLEvent:
- Out << "PAUocl_event@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_event");
break;
case BuiltinType::OCLClkEvent:
- Out << "PAUocl_clkevent@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_clkevent");
break;
case BuiltinType::OCLQueue:
- Out << "PAUocl_queue@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_queue");
break;
case BuiltinType::OCLNDRange:
- Out << "PAUocl_ndrange@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_ndrange");
break;
case BuiltinType::OCLReserveID:
- Out << "PAUocl_reserveid@@";
+ Out << "PA";
+ mangleArtificalTagType(TTK_Struct, "ocl_reserveid");
break;
case BuiltinType::NullPtr:
@@ -1746,9 +1802,12 @@
SourceRange Range;
if (D) Range = D->getSourceRange();
+ bool IsInLambda = false;
bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false;
CallingConv CC = T->getCallConv();
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
+ if (MD->getParent()->isLambda())
+ IsInLambda = true;
if (MD->isInstance())
HasThisQuals = true;
if (isa<CXXDestructorDecl>(MD)) {
@@ -1818,8 +1877,12 @@
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
+ assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
+ "shouldn't need to mangle __auto_type!");
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
+ } else if (IsInLambda) {
+ Out << '@';
} else {
if (ResultType->isVoidType())
ResultType = ResultType.getUnqualifiedType();
@@ -1839,8 +1902,20 @@
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
- for (const QualType &Arg : Proto->param_types())
- mangleArgumentType(Arg, Range);
+ for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
+ mangleArgumentType(Proto->getParamType(I), Range);
+ // Mangle each pass_object_size parameter as if it's a paramater of enum
+ // type passed directly after the parameter with the pass_object_size
+ // attribute. The aforementioned enum's name is __pass_object_size, and we
+ // pretend it resides in a top-level namespace called __clang.
+ //
+ // FIXME: Is there a defined extension notation for the MS ABI, or is it
+ // necessary to just cross our fingers and hope this type+namespace
+ // combination doesn't conflict with anything?
+ if (D)
+ if (const auto *P = D->getParamDecl(I)->getAttr<PassObjectSizeAttr>())
+ manglePassObjectSizeArg(P);
+ }
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
@@ -1969,16 +2044,8 @@
// <struct-type> ::= U <name>
// <class-type> ::= V <name>
// <enum-type> ::= W4 <name>
-void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers,
- SourceRange) {
- mangleType(cast<TagType>(T)->getDecl());
-}
-void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers,
- SourceRange) {
- mangleType(cast<TagType>(T)->getDecl());
-}
-void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
- switch (TD->getTagKind()) {
+void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) {
+ switch (TTK) {
case TTK_Union:
Out << 'T';
break;
@@ -1993,8 +2060,33 @@
Out << "W4";
break;
}
+}
+void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers,
+ SourceRange) {
+ mangleType(cast<TagType>(T)->getDecl());
+}
+void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers,
+ SourceRange) {
+ mangleType(cast<TagType>(T)->getDecl());
+}
+void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
+ mangleTagTypeKind(TD->getTagKind());
mangleName(TD);
}
+void MicrosoftCXXNameMangler::mangleArtificalTagType(
+ TagTypeKind TK, StringRef UnqualifiedName, ArrayRef<StringRef> NestedNames) {
+ // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
+ mangleTagTypeKind(TK);
+
+ // Always start with the unqualified name.
+ mangleSourceName(UnqualifiedName);
+
+ for (auto I = NestedNames.rbegin(), E = NestedNames.rend(); I != E; ++I)
+ mangleSourceName(*I);
+
+ // Terminate the whole name with an '@'.
+ Out << '@';
+}
// <type> ::= <array-type>
// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
@@ -2129,7 +2221,8 @@
void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
- Out << (Quals.hasVolatile() ? 'B' : 'A');
+ assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
+ Out << 'A';
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
@@ -2140,18 +2233,24 @@
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
- Out << (Quals.hasVolatile() ? "$$R" : "$$Q");
+ assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
+ Out << "$$Q";
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers,
SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this complex number type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+ QualType ElementType = T->getElementType();
+
+ llvm::SmallString<64> TemplateMangling;
+ llvm::raw_svector_ostream Stream(TemplateMangling);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Stream << "?$";
+ Extra.mangleSourceName("_Complex");
+ Extra.mangleType(ElementType, Range, QMM_Escape);
+
+ mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__clang"});
}
void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
@@ -2161,37 +2260,39 @@
uint64_t Width = getASTContext().getTypeSize(T);
// Pattern match exactly the typedefs in our intrinsic headers. Anything that
// doesn't match the Intel types uses a custom mangling below.
- bool IsBuiltin = true;
+ size_t OutSizeBefore = Out.tell();
llvm::Triple::ArchType AT =
getASTContext().getTargetInfo().getTriple().getArch();
if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
- Out << "T__m64";
+ mangleArtificalTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
if (ET->getKind() == BuiltinType::Float)
- Out << "T__m" << Width;
+ mangleArtificalTagType(TTK_Union, "__m" + llvm::utostr(Width));
else if (ET->getKind() == BuiltinType::LongLong)
- Out << "T__m" << Width << 'i';
+ mangleArtificalTagType(TTK_Union, "__m" + llvm::utostr(Width) + 'i');
else if (ET->getKind() == BuiltinType::Double)
- Out << "U__m" << Width << 'd';
- else
- IsBuiltin = false;
- } else {
- IsBuiltin = false;
+ mangleArtificalTagType(TTK_Struct, "__m" + llvm::utostr(Width) + 'd');
}
- } else {
- IsBuiltin = false;
}
+ bool IsBuiltin = Out.tell() != OutSizeBefore;
if (!IsBuiltin) {
// The MS ABI doesn't have a special mangling for vector types, so we define
// our own mangling to handle uses of __vector_size__ on user-specified
// types, and for extensions like __v4sf.
- Out << "T__clang_vec" << T->getNumElements() << '_';
- mangleType(ET, Quals, Range);
- }
- Out << "@@";
+ llvm::SmallString<64> TemplateMangling;
+ llvm::raw_svector_ostream Stream(TemplateMangling);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Stream << "?$";
+ Extra.mangleSourceName("__vector");
+ Extra.mangleType(QualType(ET, 0), Range, QMM_Escape);
+ Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(T->getNumElements()),
+ /*IsBoolean=*/false);
+
+ mangleArtificalTagType(TTK_Union, TemplateMangling, {"__clang"});
+ }
}
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
@@ -2210,7 +2311,7 @@
void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers,
SourceRange) {
// ObjC interfaces have structs underlying them.
- Out << 'U';
+ mangleTagTypeKind(TTK_Struct);
mangleName(T->getDecl());
}
@@ -2323,9 +2424,23 @@
void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers,
SourceRange Range) {
+ QualType ValueType = T->getValueType();
+
+ llvm::SmallString<64> TemplateMangling;
+ llvm::raw_svector_ostream Stream(TemplateMangling);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Stream << "?$";
+ Extra.mangleSourceName("_Atomic");
+ Extra.mangleType(ValueType, Range, QMM_Escape);
+
+ mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__clang"});
+}
+
+void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers,
+ SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this C11 atomic type yet");
+ "cannot mangle this OpenCL pipe type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
@@ -2522,15 +2637,6 @@
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
-void MicrosoftMangleContextImpl::mangleCXXCatchHandlerType(QualType T,
- uint32_t Flags,
- raw_ostream &Out) {
- MicrosoftCXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "llvm.eh.handlertype.";
- Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
- Mangler.getStream() << '.' << Flags;
-}
-
void MicrosoftMangleContextImpl::mangleCXXVirtualDisplacementMap(
const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
@@ -2688,12 +2794,12 @@
mangler.mangle(D);
}
-void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
- unsigned,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this reference temporary yet");
- getDiags().Report(VD->getLocation(), DiagID);
+void MicrosoftMangleContextImpl::mangleReferenceTemporary(
+ const VarDecl *VD, unsigned ManglingNumber, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+
+ Mangler.getStream() << "\01?$RT" << ManglingNumber << '@';
+ Mangler.mangle(VD, "");
}
void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable(
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 97425d0..d2370c8 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -318,7 +318,12 @@
OS << "::";
}
-void NestedNameSpecifier::dump(const LangOptions &LO) {
+void NestedNameSpecifier::dump(const LangOptions &LO) const {
+ print(llvm::errs(), PrintingPolicy(LO));
+}
+
+void NestedNameSpecifier::dump() const {
+ LangOptions LO;
print(llvm::errs(), PrintingPolicy(LO));
}
diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index 8146017..1ef43f7 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -40,9 +40,7 @@
SourceLocation LParenLoc, SourceLocation EndLoc,
ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL) {
// Allocate space for private variables and initializer expressions.
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
- llvm::alignOf<Expr *>()) +
- 2 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size()));
OMPPrivateClause *Clause =
new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -52,9 +50,7 @@
OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
- llvm::alignOf<Expr *>()) +
- 2 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N));
return new (Mem) OMPPrivateClause(N);
}
@@ -75,9 +71,7 @@
SourceLocation LParenLoc, SourceLocation EndLoc,
ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
ArrayRef<Expr *> InitVL) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
- llvm::alignOf<Expr *>()) +
- 3 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(3 * VL.size()));
OMPFirstprivateClause *Clause =
new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -88,9 +82,7 @@
OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
- llvm::alignOf<Expr *>()) +
- 3 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(3 * N));
return new (Mem) OMPFirstprivateClause(N);
}
@@ -126,9 +118,7 @@
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
- llvm::alignOf<Expr *>()) +
- 5 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
OMPLastprivateClause *Clause =
new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -140,9 +130,7 @@
OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
- llvm::alignOf<Expr *>()) +
- 5 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
return new (Mem) OMPLastprivateClause(N);
}
@@ -151,9 +139,7 @@
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
OMPSharedClause *Clause =
new (Mem) OMPSharedClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -161,9 +147,7 @@
}
OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
return new (Mem) OMPSharedClause(N);
}
@@ -198,9 +182,7 @@
ArrayRef<Expr *> PL, ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep) {
// Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
// (Step and CalcStep).
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
- llvm::alignOf<Expr *>()) +
- (5 * VL.size() + 2) * sizeof(Expr *));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2));
OMPLinearClause *Clause = new (Mem) OMPLinearClause(
StartLoc, LParenLoc, Modifier, ModifierLoc, ColonLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -221,9 +203,7 @@
unsigned NumVars) {
// Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
// (Step and CalcStep).
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
- llvm::alignOf<Expr *>()) +
- (5 * NumVars + 2) * sizeof(Expr *));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2));
return new (Mem) OMPLinearClause(NumVars);
}
@@ -231,9 +211,7 @@
OMPAlignedClause::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation ColonLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, Expr *A) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * (VL.size() + 1));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
OMPAlignedClause *Clause = new (Mem)
OMPAlignedClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -243,9 +221,7 @@
OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C,
unsigned NumVars) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * (NumVars + 1));
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumVars + 1));
return new (Mem) OMPAlignedClause(NumVars);
}
@@ -275,9 +251,7 @@
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
- llvm::alignOf<Expr *>()) +
- 4 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * VL.size()));
OMPCopyinClause *Clause =
new (Mem) OMPCopyinClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -288,9 +262,7 @@
}
OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
- llvm::alignOf<Expr *>()) +
- 4 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * N));
return new (Mem) OMPCopyinClause(N);
}
@@ -320,9 +292,7 @@
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
- llvm::alignOf<Expr *>()) +
- 4 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * VL.size()));
OMPCopyprivateClause *Clause =
new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -334,9 +304,7 @@
OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
- llvm::alignOf<Expr *>()) +
- 4 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * N));
return new (Mem) OMPCopyprivateClause(N);
}
@@ -373,9 +341,7 @@
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
- llvm::alignOf<Expr *>()) +
- 5 * sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
OMPReductionClause *Clause = new (Mem) OMPReductionClause(
StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
Clause->setVarRefs(VL);
@@ -388,9 +354,7 @@
OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
- llvm::alignOf<Expr *>()) +
- 5 * sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
return new (Mem) OMPReductionClause(N);
}
@@ -399,9 +363,7 @@
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
OMPFlushClause *Clause =
new (Mem) OMPFlushClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -409,9 +371,7 @@
}
OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
return new (Mem) OMPFlushClause(N);
}
@@ -420,9 +380,7 @@
SourceLocation LParenLoc, SourceLocation EndLoc,
OpenMPDependClauseKind DepKind, SourceLocation DepLoc,
SourceLocation ColonLoc, ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
OMPDependClause *Clause =
new (Mem) OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -433,8 +391,27 @@
}
OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N) {
- void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause),
- llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
return new (Mem) OMPDependClause(N);
}
+
+OMPMapClause *OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ OpenMPMapClauseKind TypeModifier,
+ OpenMPMapClauseKind Type,
+ SourceLocation TypeLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
+ OMPMapClause *Clause = new (Mem) OMPMapClause(
+ TypeModifier, Type, TypeLoc, StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setMapTypeModifier(TypeModifier);
+ Clause->setMapType(Type);
+ Clause->setMapLoc(TypeLoc);
+ return Clause;
+}
+
+OMPMapClause *OMPMapClause::CreateEmpty(const ASTContext &C, unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
+ return new (Mem) OMPMapClause(N);
+}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0c76838..0572ff6 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -973,7 +973,7 @@
}
// Round up the current record size to pointer alignment.
- setSize(getSize().RoundUpToAlignment(BaseAlign));
+ setSize(getSize().alignTo(BaseAlign));
setDataSize(getSize());
// Update the alignment.
@@ -1194,7 +1194,7 @@
if (!HasExternalLayout) {
// Round up the current record size to the base's alignment boundary.
- Offset = getDataSize().RoundUpToAlignment(BaseAlign);
+ Offset = getDataSize().alignTo(BaseAlign);
// Try to place the base.
while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
@@ -1204,7 +1204,7 @@
(void)Allowed;
assert(Allowed && "Base subobject externally placed at overlapping offset");
- if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){
+ if (InferAlignment && Offset < getDataSize().alignTo(BaseAlign)) {
// The externally-supplied base offset is before the base offset we
// computed. Assume that the structure is packed.
Alignment = CharUnits::One();
@@ -1292,8 +1292,7 @@
LayoutFields(RD);
NonVirtualSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.getTargetInfo().getCharAlign()));
+ llvm::alignTo(getSizeInBits(), Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1364,7 +1363,7 @@
roundUpSizeToCharAlignment(uint64_t Size,
const ASTContext &Context) {
uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
- return llvm::RoundUpToAlignment(Size, CharAlignment);
+ return llvm::alignTo(Size, CharAlignment);
}
void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1411,13 +1410,12 @@
} else {
// The bitfield is allocated starting at the next offset aligned
// appropriately for T', with length n bits.
- FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
- Context.toBits(TypeAlign));
+ FieldOffset = llvm::alignTo(getDataSizeInBits(), Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
+ setDataSize(
+ llvm::alignTo(NewSizeInBits, Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
}
@@ -1552,7 +1550,8 @@
FieldAlign = 1;
// But, if there's an 'aligned' attribute on the field, honor that.
- if (unsigned ExplicitFieldAlign = D->getMaxAlignment()) {
+ unsigned ExplicitFieldAlign = D->getMaxAlignment();
+ if (ExplicitFieldAlign) {
FieldAlign = std::max(FieldAlign, ExplicitFieldAlign);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, ExplicitFieldAlign);
}
@@ -1586,9 +1585,9 @@
// start a new storage unit), just do so, regardless of any other
// other consideration. Otherwise, round up to the right alignment.
if (FieldSize == 0 || FieldSize > UnfilledBitsInLastUnit) {
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
- UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
- UnpackedFieldAlign);
+ FieldOffset = llvm::alignTo(FieldOffset, FieldAlign);
+ UnpackedFieldOffset =
+ llvm::alignTo(UnpackedFieldOffset, UnpackedFieldAlign);
UnfilledBitsInLastUnit = 0;
}
@@ -1600,15 +1599,22 @@
if (FieldSize == 0 ||
(AllowPadding &&
(FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) {
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ FieldOffset = llvm::alignTo(FieldOffset, FieldAlign);
+ } else if (ExplicitFieldAlign) {
+ // TODO: figure it out what needs to be done on targets that don't honor
+ // bit-field type alignment like ARM APCS ABI.
+ FieldOffset = llvm::alignTo(FieldOffset, ExplicitFieldAlign);
}
// Repeat the computation for diagnostic purposes.
if (FieldSize == 0 ||
(AllowPadding &&
(UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
- UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
- UnpackedFieldAlign);
+ UnpackedFieldOffset =
+ llvm::alignTo(UnpackedFieldOffset, UnpackedFieldAlign);
+ else if (ExplicitFieldAlign)
+ UnpackedFieldOffset =
+ llvm::alignTo(UnpackedFieldOffset, ExplicitFieldAlign);
}
// If we're using external layout, give the external layout a chance
@@ -1669,7 +1675,7 @@
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, CharAlignment));
+ setDataSize(llvm::alignTo(NewSizeInBits, CharAlignment));
UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
// The only time we can get here for an ms_struct is if this is a
@@ -1759,9 +1765,8 @@
}
// Round up the current record size to the field's alignment boundary.
- FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
- UnpackedFieldOffset =
- UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
+ FieldOffset = FieldOffset.alignTo(FieldAlign);
+ UnpackedFieldOffset = UnpackedFieldOffset.alignTo(UnpackedFieldAlign);
if (UseExternalLayout) {
FieldOffset = Context.toCharUnitsFromBits(
@@ -1832,11 +1837,10 @@
// record itself.
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.toBits(UnpackedAlignment));
+ llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment));
CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
- uint64_t RoundedSize
- = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment));
+ uint64_t RoundedSize =
+ llvm::alignTo(getSizeInBits(), Context.toBits(Alignment));
if (UseExternalLayout) {
// If we're inferring alignment, and the external size is smaller than
@@ -2025,6 +2029,21 @@
continue;
}
+ if (Context.getLangOpts().CUDA) {
+ // While compiler may see key method in this TU, during CUDA
+ // compilation we should ignore methods that are not accessible
+ // on this side of compilation.
+ if (Context.getLangOpts().CUDAIsDevice) {
+ // In device mode ignore methods without __device__ attribute.
+ if (!MD->hasAttr<CUDADeviceAttr>())
+ continue;
+ } else {
+ // In host mode ignore __device__-only methods.
+ if (!MD->hasAttr<CUDAHostAttr>() && MD->hasAttr<CUDADeviceAttr>())
+ continue;
+ }
+ }
+
// If the key function is dllimport but the class isn't, then the class has
// no key function. The DLL that exports the key function won't export the
// vtable in this case.
@@ -2362,7 +2381,7 @@
MinEmptyStructSize = CharUnits::fromQuantity(4);
initializeLayout(RD);
layoutFields(RD);
- DataSize = Size = Size.RoundUpToAlignment(Alignment);
+ DataSize = Size = Size.alignTo(Alignment);
RequiredAlignment = std::max(
RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
finalizeLayout(RD);
@@ -2382,7 +2401,7 @@
auto RoundingAlignment = Alignment;
if (!MaxFieldAlignment.isZero())
RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
- NonVirtualSize = Size = Size.RoundUpToAlignment(RoundingAlignment);
+ NonVirtualSize = Size = Size.alignTo(RoundingAlignment);
RequiredAlignment = std::max(
RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
layoutVirtualBases(RD);
@@ -2537,7 +2556,7 @@
}
if (!FoundBase)
- BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ BaseOffset = Size.alignTo(Info.Alignment);
Bases.insert(std::make_pair(BaseDecl, BaseOffset));
Size = BaseOffset + BaseLayout.getNonVirtualSize();
PreviousBaseLayout = &BaseLayout;
@@ -2567,7 +2586,7 @@
Context.toCharUnitsFromBits(External.getExternalFieldOffset(FD));
assert(FieldOffset >= Size && "field offset already allocated");
} else {
- FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
+ FieldOffset = Size.alignTo(Info.Alignment);
}
placeFieldAtOffset(FieldOffset);
Size = FieldOffset + Info.Size;
@@ -2602,7 +2621,7 @@
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Allocate a new block of memory and place the bitfield in it.
- CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits FieldOffset = Size.alignTo(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset + Info.Size;
Alignment = std::max(Alignment, Info.Alignment);
@@ -2628,7 +2647,7 @@
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Round up the current record size to the field's alignment boundary.
- CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits FieldOffset = Size.alignTo(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset;
Alignment = std::max(Alignment, Info.Alignment);
@@ -2641,7 +2660,7 @@
// Inject the VBPointer at the injection site.
CharUnits InjectionSite = VBPtrOffset;
// But before we do, make sure it's properly aligned.
- VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
+ VBPtrOffset = VBPtrOffset.alignTo(PointerInfo.Alignment);
// Shift everything after the vbptr down, unless we're using an external
// layout.
if (UseExternalLayout)
@@ -2650,8 +2669,8 @@
CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
// Make sure that the amount we push the fields back by is a multiple of the
// alignment.
- CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment(
- std::max(RequiredAlignment, Alignment));
+ CharUnits Offset = (FieldStart - InjectionSite)
+ .alignTo(std::max(RequiredAlignment, Alignment));
Size += Offset;
for (uint64_t &FieldOffset : FieldOffsets)
FieldOffset += Context.toBits(Offset);
@@ -2665,8 +2684,8 @@
return;
// Make sure that the amount we push the struct back by is a multiple of the
// alignment.
- CharUnits Offset = PointerInfo.Size.RoundUpToAlignment(
- std::max(RequiredAlignment, Alignment));
+ CharUnits Offset =
+ PointerInfo.Size.alignTo(std::max(RequiredAlignment, Alignment));
// Push back the vbptr, but increase the size of the object and push back
// regular fields by the offset only if not using external record layout.
if (HasVBPtr)
@@ -2720,7 +2739,7 @@
// the required alignment, we don't know why.
if ((PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
BaseLayout.leadsWithZeroSizedBase()) || HasVtordisp) {
- Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
+ Size = Size.alignTo(VtorDispAlignment) + VtorDispSize;
Alignment = std::max(VtorDispAlignment, Alignment);
}
// Insert the virtual base.
@@ -2735,7 +2754,7 @@
assert(BaseOffset >= Size && "base offset already allocated");
}
if (!FoundBase)
- BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ BaseOffset = Size.alignTo(Info.Alignment);
VBases.insert(std::make_pair(BaseDecl,
ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
@@ -2754,7 +2773,7 @@
if (!MaxFieldAlignment.isZero())
RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment);
- Size = Size.RoundUpToAlignment(RoundingAlignment);
+ Size = Size.alignTo(RoundingAlignment);
}
if (Size.isZero()) {
EndsWithZeroSizedObject = true;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 00c4c19..7dfa3a9 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -295,14 +295,15 @@
std::copy(Stmts.begin(), Stmts.end(), Body);
}
-void CompoundStmt::setStmts(const ASTContext &C, Stmt **Stmts,
- unsigned NumStmts) {
- if (this->Body)
+void CompoundStmt::setStmts(const ASTContext &C, ArrayRef<Stmt *> Stmts) {
+ if (Body)
C.Deallocate(Body);
- this->CompoundStmtBits.NumStmts = NumStmts;
+ CompoundStmtBits.NumStmts = Stmts.size();
+ assert(CompoundStmtBits.NumStmts == Stmts.size() &&
+ "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
- Body = new (C) Stmt*[NumStmts];
- memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
+ Body = new (C) Stmt*[Stmts.size()];
+ std::copy(Stmts.begin(), Stmts.end(), Body);
}
const char *LabelStmt::getName() const {
@@ -730,30 +731,29 @@
assert(NumAsmToks == asmtoks.size());
assert(NumClobbers == clobbers.size());
- unsigned NumExprs = exprs.size();
- assert(NumExprs == NumOutputs + NumInputs);
- assert(NumExprs == constraints.size());
+ assert(exprs.size() == NumOutputs + NumInputs);
+ assert(exprs.size() == constraints.size());
AsmStr = copyIntoContext(C, asmstr);
- Exprs = new (C) Stmt*[NumExprs];
- for (unsigned i = 0, e = NumExprs; i != e; ++i)
- Exprs[i] = exprs[i];
+ Exprs = new (C) Stmt*[exprs.size()];
+ std::copy(exprs.begin(), exprs.end(), Exprs);
- AsmToks = new (C) Token[NumAsmToks];
- for (unsigned i = 0, e = NumAsmToks; i != e; ++i)
- AsmToks[i] = asmtoks[i];
+ AsmToks = new (C) Token[asmtoks.size()];
+ std::copy(asmtoks.begin(), asmtoks.end(), AsmToks);
- Constraints = new (C) StringRef[NumExprs];
- for (unsigned i = 0, e = NumExprs; i != e; ++i) {
- Constraints[i] = copyIntoContext(C, constraints[i]);
- }
+ Constraints = new (C) StringRef[exprs.size()];
+ std::transform(constraints.begin(), constraints.end(), Constraints,
+ [&](StringRef Constraint) {
+ return copyIntoContext(C, Constraint);
+ });
Clobbers = new (C) StringRef[NumClobbers];
- for (unsigned i = 0, e = NumClobbers; i != e; ++i) {
- // FIXME: Avoid the allocation/copy if at all possible.
- Clobbers[i] = copyIntoContext(C, clobbers[i]);
- }
+ // FIXME: Avoid the allocation/copy if at all possible.
+ std::transform(clobbers.begin(), clobbers.end(), Clobbers,
+ [&](StringRef Clobber) {
+ return copyIntoContext(C, Clobber);
+ });
}
IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
@@ -945,12 +945,49 @@
return new(C)SEHFinallyStmt(Loc,Block);
}
+CapturedStmt::Capture::Capture(SourceLocation Loc, VariableCaptureKind Kind,
+ VarDecl *Var)
+ : VarAndKind(Var, Kind), Loc(Loc) {
+ switch (Kind) {
+ case VCK_This:
+ assert(!Var && "'this' capture cannot have a variable!");
+ break;
+ case VCK_ByRef:
+ assert(Var && "capturing by reference must have a variable!");
+ break;
+ case VCK_ByCopy:
+ assert(Var && "capturing by copy must have a variable!");
+ assert(
+ (Var->getType()->isScalarType() || (Var->getType()->isReferenceType() &&
+ Var->getType()
+ ->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->isScalarType())) &&
+ "captures by copy are expected to have a scalar type!");
+ break;
+ case VCK_VLAType:
+ assert(!Var &&
+ "Variable-length array type capture cannot have a variable!");
+ break;
+ }
+}
+
+CapturedStmt::VariableCaptureKind
+CapturedStmt::Capture::getCaptureKind() const {
+ return VarAndKind.getInt();
+}
+
+VarDecl *CapturedStmt::Capture::getCapturedVar() const {
+ assert((capturesVariable() || capturesVariableByCopy()) &&
+ "No variable available for 'this' or VAT capture");
+ return VarAndKind.getPointer();
+}
+
CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const {
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
// Offset of the first Capture object.
- unsigned FirstCaptureOffset =
- llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>());
+ unsigned FirstCaptureOffset = llvm::alignTo(Size, llvm::alignOf<Capture>());
return reinterpret_cast<Capture *>(
reinterpret_cast<char *>(const_cast<CapturedStmt *>(this))
@@ -1007,7 +1044,7 @@
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (Captures.size() + 1);
if (!Captures.empty()) {
// Realign for the following Capture array.
- Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>());
+ Size = llvm::alignTo(Size, llvm::alignOf<Capture>());
Size += sizeof(Capture) * Captures.size();
}
@@ -1020,7 +1057,7 @@
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumCaptures > 0) {
// Realign for the following Capture array.
- Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>());
+ Size = llvm::alignTo(Size, llvm::alignOf<Capture>());
Size += sizeof(Capture) * NumCaptures;
}
@@ -1033,6 +1070,29 @@
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
}
+CapturedDecl *CapturedStmt::getCapturedDecl() {
+ return CapDeclAndKind.getPointer();
+}
+const CapturedDecl *CapturedStmt::getCapturedDecl() const {
+ return CapDeclAndKind.getPointer();
+}
+
+/// \brief Set the outlined function declaration.
+void CapturedStmt::setCapturedDecl(CapturedDecl *D) {
+ assert(D && "null CapturedDecl");
+ CapDeclAndKind.setPointer(D);
+}
+
+/// \brief Retrieve the captured region kind.
+CapturedRegionKind CapturedStmt::getCapturedRegionKind() const {
+ return CapDeclAndKind.getInt();
+}
+
+/// \brief Set the captured region kind.
+void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) {
+ CapDeclAndKind.setInt(Kind);
+}
+
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
for (const auto &I : captures()) {
if (!I.capturesVariable())
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 732756f..861d090 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -42,7 +42,7 @@
if (inDeclGroup()) {
if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
- if (VD->Init)
+ if (VD->hasInit())
return;
NextDecl();
diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp
index ead92b2..72e62b7 100644
--- a/lib/AST/StmtOpenMP.cpp
+++ b/lib/AST/StmtOpenMP.cpp
@@ -57,8 +57,8 @@
OMPParallelDirective *OMPParallelDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPParallelDirective *Dir =
@@ -72,8 +72,8 @@
OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPParallelDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPParallelDirective(NumClauses);
@@ -84,8 +84,8 @@
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSimdDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd));
@@ -112,8 +112,8 @@
unsigned NumClauses,
unsigned CollapsedNum,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSimdDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd));
@@ -125,8 +125,8 @@
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPForDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for));
@@ -161,8 +161,8 @@
unsigned NumClauses,
unsigned CollapsedNum,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPForDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for));
@@ -174,8 +174,8 @@
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPForSimdDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd));
@@ -209,8 +209,8 @@
unsigned NumClauses,
unsigned CollapsedNum,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPForSimdDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd));
@@ -220,8 +220,8 @@
OMPSectionsDirective *OMPSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSectionsDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPSectionsDirective *Dir =
@@ -235,8 +235,8 @@
OMPSectionsDirective *OMPSectionsDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSectionsDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPSectionsDirective(NumClauses);
@@ -247,8 +247,8 @@
SourceLocation EndLoc,
Stmt *AssociatedStmt,
bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSectionDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
OMPSectionDirective *Dir = new (Mem) OMPSectionDirective(StartLoc, EndLoc);
Dir->setAssociatedStmt(AssociatedStmt);
@@ -258,8 +258,8 @@
OMPSectionDirective *OMPSectionDirective::CreateEmpty(const ASTContext &C,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSectionDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
return new (Mem) OMPSectionDirective();
}
@@ -269,8 +269,8 @@
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSingleDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSingleDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPSingleDirective *Dir =
@@ -283,8 +283,8 @@
OMPSingleDirective *OMPSingleDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSingleDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPSingleDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPSingleDirective(NumClauses);
@@ -294,8 +294,8 @@
SourceLocation StartLoc,
SourceLocation EndLoc,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPMasterDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
OMPMasterDirective *Dir = new (Mem) OMPMasterDirective(StartLoc, EndLoc);
Dir->setAssociatedStmt(AssociatedStmt);
@@ -304,38 +304,43 @@
OMPMasterDirective *OMPMasterDirective::CreateEmpty(const ASTContext &C,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPMasterDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
return new (Mem) OMPMasterDirective();
}
OMPCriticalDirective *OMPCriticalDirective::Create(
const ASTContext &C, const DeclarationNameInfo &Name,
- SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective),
- llvm::alignOf<Stmt *>());
- void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPCriticalDirective), llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPCriticalDirective *Dir =
- new (Mem) OMPCriticalDirective(Name, StartLoc, EndLoc);
+ new (Mem) OMPCriticalDirective(Name, StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
return Dir;
}
OMPCriticalDirective *OMPCriticalDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective),
- llvm::alignOf<Stmt *>());
- void *Mem = C.Allocate(Size + sizeof(Stmt *));
- return new (Mem) OMPCriticalDirective();
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPCriticalDirective), llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPCriticalDirective(NumClauses);
}
OMPParallelForDirective *OMPParallelForDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelForDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
sizeof(Stmt *) *
numLoopChildren(CollapsedNum, OMPD_parallel_for));
@@ -369,8 +374,8 @@
OMPParallelForDirective *
OMPParallelForDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned CollapsedNum, EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelForDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
sizeof(Stmt *) *
numLoopChildren(CollapsedNum, OMPD_parallel_for));
@@ -381,8 +386,8 @@
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelForSimdDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(
Size + sizeof(OMPClause *) * Clauses.size() +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd));
@@ -416,8 +421,8 @@
OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
unsigned CollapsedNum, EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelForSimdDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(
Size + sizeof(OMPClause *) * NumClauses +
sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd));
@@ -427,8 +432,8 @@
OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelSectionsDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPParallelSectionsDirective *Dir =
@@ -442,8 +447,8 @@
OMPParallelSectionsDirective *
OMPParallelSectionsDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses, EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelSectionsDirective),
+ llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPParallelSectionsDirective(NumClauses);
@@ -453,8 +458,8 @@
OMPTaskDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, bool HasCancel) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPTaskDirective *Dir =
@@ -468,8 +473,8 @@
OMPTaskDirective *OMPTaskDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPTaskDirective(NumClauses);
@@ -522,8 +527,8 @@
SourceLocation StartLoc,
SourceLocation EndLoc,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskgroupDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
OMPTaskgroupDirective *Dir =
new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc);
@@ -533,8 +538,8 @@
OMPTaskgroupDirective *OMPTaskgroupDirective::CreateEmpty(const ASTContext &C,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective),
- llvm::alignOf<Stmt *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskgroupDirective), llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size + sizeof(Stmt *));
return new (Mem) OMPTaskgroupDirective();
}
@@ -542,8 +547,8 @@
OMPCancellationPointDirective *OMPCancellationPointDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
- unsigned Size = llvm::RoundUpToAlignment(
- sizeof(OMPCancellationPointDirective), llvm::alignOf<Stmt *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPCancellationPointDirective),
+ llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
OMPCancellationPointDirective *Dir =
new (Mem) OMPCancellationPointDirective(StartLoc, EndLoc);
@@ -553,8 +558,8 @@
OMPCancellationPointDirective *
OMPCancellationPointDirective::CreateEmpty(const ASTContext &C, EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(
- sizeof(OMPCancellationPointDirective), llvm::alignOf<Stmt *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPCancellationPointDirective),
+ llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
return new (Mem) OMPCancellationPointDirective();
}
@@ -563,9 +568,9 @@
OMPCancelDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
OpenMPDirectiveKind CancelRegion) {
- unsigned Size = llvm::RoundUpToAlignment(
- sizeof(OMPCancelDirective) + sizeof(OMPClause *) * Clauses.size(),
- llvm::alignOf<Stmt *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPCancelDirective) +
+ sizeof(OMPClause *) * Clauses.size(),
+ llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
OMPCancelDirective *Dir =
new (Mem) OMPCancelDirective(StartLoc, EndLoc, Clauses.size());
@@ -577,9 +582,9 @@
OMPCancelDirective *OMPCancelDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective) +
- sizeof(OMPClause *) * NumClauses,
- llvm::alignOf<Stmt *>());
+ unsigned Size = llvm::alignTo(sizeof(OMPCancelDirective) +
+ sizeof(OMPClause *) * NumClauses,
+ llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
return new (Mem) OMPCancelDirective(NumClauses);
}
@@ -588,8 +593,8 @@
SourceLocation StartLoc,
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPFlushDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPFlushDirective), llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size());
OMPFlushDirective *Dir =
new (Mem) OMPFlushDirective(StartLoc, EndLoc, Clauses.size());
@@ -600,8 +605,8 @@
OMPFlushDirective *OMPFlushDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPFlushDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPFlushDirective), llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses);
return new (Mem) OMPFlushDirective(NumClauses);
}
@@ -611,8 +616,8 @@
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPOrderedDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(Stmt *) + sizeof(OMPClause *) * Clauses.size());
OMPOrderedDirective *Dir =
@@ -625,8 +630,8 @@
OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPOrderedDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(Stmt *) + sizeof(OMPClause *) * NumClauses);
return new (Mem) OMPOrderedDirective(NumClauses);
@@ -636,8 +641,8 @@
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPAtomicDirective), llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
5 * sizeof(Stmt *));
OMPAtomicDirective *Dir =
@@ -656,8 +661,8 @@
OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPAtomicDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 5 * sizeof(Stmt *));
return new (Mem) OMPAtomicDirective(NumClauses);
@@ -668,8 +673,8 @@
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTargetDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPTargetDirective *Dir =
@@ -682,8 +687,8 @@
OMPTargetDirective *OMPTargetDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTargetDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPTargetDirective(NumClauses);
@@ -692,10 +697,9 @@
OMPTargetDataDirective *OMPTargetDataDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
- void *Mem =
- C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective),
- llvm::alignOf<OMPClause *>()) +
- sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ void *Mem = C.Allocate(llvm::alignTo(sizeof(OMPTargetDataDirective),
+ llvm::alignOf<OMPClause *>()) +
+ sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPTargetDataDirective *Dir =
new (Mem) OMPTargetDataDirective(StartLoc, EndLoc, Clauses.size());
Dir->setClauses(Clauses);
@@ -706,10 +710,9 @@
OMPTargetDataDirective *OMPTargetDataDirective::CreateEmpty(const ASTContext &C,
unsigned N,
EmptyShell) {
- void *Mem =
- C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective),
- llvm::alignOf<OMPClause *>()) +
- sizeof(OMPClause *) * N + sizeof(Stmt *));
+ void *Mem = C.Allocate(llvm::alignTo(sizeof(OMPTargetDataDirective),
+ llvm::alignOf<OMPClause *>()) +
+ sizeof(OMPClause *) * N + sizeof(Stmt *));
return new (Mem) OMPTargetDataDirective(N);
}
@@ -718,8 +721,8 @@
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTeamsDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
OMPTeamsDirective *Dir =
@@ -732,9 +735,148 @@
OMPTeamsDirective *OMPTeamsDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective),
- llvm::alignOf<OMPClause *>());
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTeamsDirective), llvm::alignOf<OMPClause *>());
void *Mem =
C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
return new (Mem) OMPTeamsDirective(NumClauses);
}
+
+OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskLoopDirective), llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_taskloop));
+ OMPTaskLoopDirective *Dir = new (Mem)
+ OMPTaskLoopDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ return Dir;
+}
+
+OMPTaskLoopDirective *OMPTaskLoopDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPTaskLoopDirective), llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_taskloop));
+ return new (Mem) OMPTaskLoopDirective(CollapsedNum, NumClauses);
+}
+
+OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskLoopSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_taskloop_simd));
+ OMPTaskLoopSimdDirective *Dir = new (Mem)
+ OMPTaskLoopSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ return Dir;
+}
+
+OMPTaskLoopSimdDirective *
+OMPTaskLoopSimdDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskLoopSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_taskloop_simd));
+ return new (Mem) OMPTaskLoopSimdDirective(CollapsedNum, NumClauses);
+}
+
+OMPDistributeDirective *OMPDistributeDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPDistributeDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_distribute));
+ OMPDistributeDirective *Dir = new (Mem)
+ OMPDistributeDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ return Dir;
+}
+
+OMPDistributeDirective *
+OMPDistributeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPDistributeDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_distribute));
+ return new (Mem) OMPDistributeDirective(CollapsedNum, NumClauses);
+}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 52aa59e..0d7063e 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -651,8 +651,18 @@
}
void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
- OS << "schedule("
- << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind());
+ OS << "schedule(";
+ if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_schedule,
+ Node->getFirstScheduleModifier());
+ if (Node->getSecondScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
+ OS << ", ";
+ OS << getOpenMPSimpleClauseTypeName(OMPC_schedule,
+ Node->getSecondScheduleModifier());
+ }
+ OS << ": ";
+ }
+ OS << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind());
if (Node->getChunkSize()) {
OS << ", ";
Node->getChunkSize()->printPretty(OS, nullptr, Policy);
@@ -677,6 +687,10 @@
OS << "untied";
}
+void OMPClausePrinter::VisitOMPNogroupClause(OMPNogroupClause *) {
+ OS << "nogroup";
+}
+
void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) {
OS << "mergeable";
}
@@ -709,6 +723,42 @@
OS << ")";
}
+void OMPClausePrinter::VisitOMPNumTeamsClause(OMPNumTeamsClause *Node) {
+ OS << "num_teams(";
+ Node->getNumTeams()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPThreadLimitClause(OMPThreadLimitClause *Node) {
+ OS << "thread_limit(";
+ Node->getThreadLimit()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPPriorityClause(OMPPriorityClause *Node) {
+ OS << "priority(";
+ Node->getPriority()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPGrainsizeClause(OMPGrainsizeClause *Node) {
+ OS << "grainsize(";
+ Node->getGrainsize()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPNumTasksClause(OMPNumTasksClause *Node) {
+ OS << "num_tasks(";
+ Node->getNumTasks()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPHintClause(OMPHintClause *Node) {
+ OS << "hint(";
+ Node->getHint()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
template<typename T>
void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
for (typename T::varlist_iterator I = Node->varlist_begin(),
@@ -833,15 +883,42 @@
}
void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) {
+ OS << "depend(";
+ OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
+ Node->getDependencyKind());
if (!Node->varlist_empty()) {
- OS << "depend(";
- OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
- Node->getDependencyKind())
- << " :";
+ OS << " :";
+ VisitOMPClauseList(Node, ' ');
+ }
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "map(";
+ if (Node->getMapType() != OMPC_MAP_unknown) {
+ if (Node->getMapTypeModifier() != OMPC_MAP_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_map,
+ Node->getMapTypeModifier());
+ OS << ',';
+ }
+ OS << getOpenMPSimpleClauseTypeName(OMPC_map, Node->getMapType());
+ OS << ':';
+ }
VisitOMPClauseList(Node, ' ');
OS << ")";
}
}
+
+void OMPClausePrinter::VisitOMPDistScheduleClause(OMPDistScheduleClause *Node) {
+ OS << "dist_schedule(" << getOpenMPSimpleClauseTypeName(
+ OMPC_dist_schedule, Node->getDistScheduleKind());
+ if (Node->getChunkSize()) {
+ OS << ", ";
+ Node->getChunkSize()->printPretty(OS, nullptr, Policy);
+ }
+ OS << ")";
+}
}
//===----------------------------------------------------------------------===//
@@ -913,6 +990,7 @@
Node->getDirectiveName().printName(OS);
OS << ")";
}
+ OS << " ";
PrintOMPExecutableDirective(Node);
}
@@ -1000,6 +1078,23 @@
<< getOpenMPDirectiveName(Node->getCancelRegion()) << " ";
PrintOMPExecutableDirective(Node);
}
+
+void StmtPrinter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *Node) {
+ Indent() << "#pragma omp taskloop ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTaskLoopSimdDirective(
+ OMPTaskLoopSimdDirective *Node) {
+ Indent() << "#pragma omp taskloop simd ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
+ Indent() << "#pragma omp distribute ";
+ PrintOMPExecutableDirective(Node);
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -1080,6 +1175,7 @@
switch (Node->getKind()) {
case CharacterLiteral::Ascii: break; // no prefix.
case CharacterLiteral::Wide: OS << 'L'; break;
+ case CharacterLiteral::UTF8: OS << "u8"; break;
case CharacterLiteral::UTF16: OS << 'u'; break;
case CharacterLiteral::UTF32: OS << 'U'; break;
}
@@ -1220,8 +1316,8 @@
OS << ", ";
bool PrintedSomething = false;
for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
- OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
- if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) {
+ OffsetOfNode ON = Node->getComponent(i);
+ if (ON.getKind() == OffsetOfNode::Array) {
// Array node
OS << "[";
PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
@@ -1231,7 +1327,7 @@
}
// Skip implicit base indirections.
- if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+ if (ON.getKind() == OffsetOfNode::Base)
continue;
// Field or identifier node.
@@ -1715,6 +1811,13 @@
OS << Node->getPropertyDecl()->getDeclName();
}
+void StmtPrinter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << "[";
+ PrintExpr(Node->getIdx());
+ OS << "]";
+}
+
void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
switch (Node->getLiteralOperatorKind()) {
case UserDefinedLiteral::LOK_Raw:
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 28507c1..f8aa4db 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -262,6 +262,7 @@
/// \brief Process clauses with list of variables.
template <typename T>
void VisitOMPClauseList(T *Node);
+
public:
OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { }
#define OPENMP_CLAUSE(Name, Class) \
@@ -337,6 +338,8 @@
void OMPClauseProfiler::VisitOMPSIMDClause(const OMPSIMDClause *) {}
+void OMPClauseProfiler::VisitOMPNogroupClause(const OMPNogroupClause *) {}
+
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
for (auto *E : Node->varlists()) {
@@ -450,6 +453,28 @@
void OMPClauseProfiler::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Profiler->VisitStmt(C->getDevice());
}
+void OMPClauseProfiler::VisitOMPMapClause(const OMPMapClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
+ Profiler->VisitStmt(C->getNumTeams());
+}
+void OMPClauseProfiler::VisitOMPThreadLimitClause(
+ const OMPThreadLimitClause *C) {
+ Profiler->VisitStmt(C->getThreadLimit());
+}
+void OMPClauseProfiler::VisitOMPPriorityClause(const OMPPriorityClause *C) {
+ Profiler->VisitStmt(C->getPriority());
+}
+void OMPClauseProfiler::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) {
+ Profiler->VisitStmt(C->getGrainsize());
+}
+void OMPClauseProfiler::VisitOMPNumTasksClause(const OMPNumTasksClause *C) {
+ Profiler->VisitStmt(C->getNumTasks());
+}
+void OMPClauseProfiler::VisitOMPHintClause(const OMPHintClause *C) {
+ Profiler->VisitStmt(C->getHint());
+}
}
void
@@ -572,6 +597,30 @@
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPTaskLoopSimdDirective(
+ const OMPTaskLoopSimdDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPDistributeDirective(
+ const OMPDistributeDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void OMPClauseProfiler::VisitOMPDistScheduleClause(
+ const OMPDistScheduleClause *C) {
+ if (C->getChunkSize()) {
+ Profiler->VisitStmt(C->getChunkSize());
+ if (C->getHelperChunkSize()) {
+ Profiler->VisitStmt(C->getChunkSize());
+ }
+ }
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
@@ -636,22 +685,22 @@
VisitType(S->getTypeSourceInfo()->getType());
unsigned n = S->getNumComponents();
for (unsigned i = 0; i < n; ++i) {
- const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i);
+ const OffsetOfNode &ON = S->getComponent(i);
ID.AddInteger(ON.getKind());
switch (ON.getKind()) {
- case OffsetOfExpr::OffsetOfNode::Array:
+ case OffsetOfNode::Array:
// Expressions handled below.
break;
- case OffsetOfExpr::OffsetOfNode::Field:
+ case OffsetOfNode::Field:
VisitDecl(ON.getField());
break;
- case OffsetOfExpr::OffsetOfNode::Identifier:
+ case OffsetOfNode::Identifier:
ID.AddPointer(ON.getFieldName());
break;
-
- case OffsetOfExpr::OffsetOfNode::Base:
+
+ case OffsetOfNode::Base:
// These nodes are implicit, and therefore don't need profiling.
break;
}
@@ -1016,7 +1065,6 @@
BinaryOp = BO_Comma;
return Stmt::BinaryOperatorClass;
-
case OO_ArrowStar:
BinaryOp = BO_PtrMemI;
return Stmt::BinaryOperatorClass;
@@ -1028,7 +1076,6 @@
llvm_unreachable("Invalid overloaded operator expression");
}
-
void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
if (S->isTypeDependent()) {
// Type-dependent operator calls are profiled like their underlying
@@ -1123,6 +1170,11 @@
VisitDecl(S->getPropertyDecl());
}
+void StmtProfiler::VisitMSPropertySubscriptExpr(
+ const MSPropertySubscriptExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isImplicit());
@@ -1200,7 +1252,6 @@
VisitDecl(S->getOperatorDelete());
}
-
void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
VisitExpr(S);
VisitType(S->getAllocatedType());
@@ -1234,8 +1285,7 @@
VisitName(S->getName());
ID.AddBoolean(S->hasExplicitTemplateArgs());
if (S->hasExplicitTemplateArgs())
- VisitTemplateArguments(S->getExplicitTemplateArgs().getTemplateArgs(),
- S->getExplicitTemplateArgs().NumTemplateArgs);
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 8c5a691..e9edb0d 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -53,7 +53,7 @@
}
}
- if (T->isBooleanType()) {
+ if (T->isBooleanType() && !Policy.MSVCFormatting) {
Out << (Val.getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
const char Ch = Val.getZExtValue();
@@ -520,94 +520,67 @@
const ASTTemplateArgumentListInfo *
ASTTemplateArgumentListInfo::Create(ASTContext &C,
const TemplateArgumentListInfo &List) {
- assert(llvm::alignOf<ASTTemplateArgumentListInfo>() >=
- llvm::alignOf<TemplateArgumentLoc>());
- std::size_t size = ASTTemplateArgumentListInfo::sizeFor(List.size());
+ std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>());
- ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo();
- TAI->initializeFrom(List);
- return TAI;
+ return new (Mem) ASTTemplateArgumentListInfo(List);
}
-void ASTTemplateArgumentListInfo::initializeFrom(
- const TemplateArgumentListInfo &Info) {
+ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
+ const TemplateArgumentListInfo &Info) {
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
- TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
for (unsigned i = 0; i != NumTemplateArgs; ++i)
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
}
-void ASTTemplateArgumentListInfo::initializeFrom(
- const TemplateArgumentListInfo &Info,
- bool &Dependent,
- bool &InstantiationDependent,
- bool &ContainsUnexpandedParameterPack) {
+void ASTTemplateKWAndArgsInfo::initializeFrom(
+ SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
+ TemplateArgumentLoc *OutArgArray) {
+ this->TemplateKWLoc = TemplateKWLoc;
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
- TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
- for (unsigned i = 0; i != NumTemplateArgs; ++i) {
- Dependent = Dependent || Info[i].getArgument().isDependent();
- InstantiationDependent = InstantiationDependent ||
- Info[i].getArgument().isInstantiationDependent();
- ContainsUnexpandedParameterPack
- = ContainsUnexpandedParameterPack ||
- Info[i].getArgument().containsUnexpandedParameterPack();
-
- new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
- }
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
}
-void ASTTemplateArgumentListInfo::copyInto(
- TemplateArgumentListInfo &Info) const {
- Info.setLAngleLoc(LAngleLoc);
- Info.setRAngleLoc(RAngleLoc);
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- Info.addArgument(getTemplateArgs()[I]);
-}
-
-std::size_t ASTTemplateArgumentListInfo::sizeFor(unsigned NumTemplateArgs) {
- return sizeof(ASTTemplateArgumentListInfo) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs;
-}
-
-void
-ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo &Info) {
- Base::initializeFrom(Info);
- setTemplateKeywordLoc(TemplateKWLoc);
-}
-
-void
-ASTTemplateKWAndArgsInfo
-::initializeFrom(SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo &Info,
- bool &Dependent,
- bool &InstantiationDependent,
- bool &ContainsUnexpandedParameterPack) {
- Base::initializeFrom(Info, Dependent, InstantiationDependent,
- ContainsUnexpandedParameterPack);
- setTemplateKeywordLoc(TemplateKWLoc);
-}
-
-void
-ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
- // No explicit template arguments, but template keyword loc is valid.
+void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
assert(TemplateKWLoc.isValid());
LAngleLoc = SourceLocation();
RAngleLoc = SourceLocation();
+ this->TemplateKWLoc = TemplateKWLoc;
NumTemplateArgs = 0;
- setTemplateKeywordLoc(TemplateKWLoc);
}
-std::size_t
-ASTTemplateKWAndArgsInfo::sizeFor(unsigned NumTemplateArgs) {
- // Add space for the template keyword location.
- // FIXME: There's room for this in the padding before the template args in
- // 64-bit builds.
- return Base::sizeFor(NumTemplateArgs) + sizeof(SourceLocation);
+void ASTTemplateKWAndArgsInfo::initializeFrom(
+ SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
+ TemplateArgumentLoc *OutArgArray, bool &Dependent,
+ bool &InstantiationDependent, bool &ContainsUnexpandedParameterPack) {
+ this->TemplateKWLoc = TemplateKWLoc;
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ Dependent = Dependent || Info[i].getArgument().isDependent();
+ InstantiationDependent = InstantiationDependent ||
+ Info[i].getArgument().isInstantiationDependent();
+ ContainsUnexpandedParameterPack =
+ ContainsUnexpandedParameterPack ||
+ Info[i].getArgument().containsUnexpandedParameterPack();
+
+ new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
+ }
+}
+
+void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray,
+ TemplateArgumentListInfo &Info) const {
+ Info.setLAngleLoc(LAngleLoc);
+ Info.setRAngleLoc(RAngleLoc);
+ for (unsigned I = 0; I != NumTemplateArgs; ++I)
+ Info.addArgument(ArgArray[I]);
}
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index e612f10..47e0255 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -51,6 +51,22 @@
ArgPack.Profile(ID, Context);
}
+TemplateName::TemplateName(void *Ptr) {
+ Storage = StorageType::getFromOpaqueValue(Ptr);
+}
+
+TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
+TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
+ : Storage(Storage) {}
+TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
+ : Storage(Storage) {}
+TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
+ : Storage(Storage) {}
+TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
+TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
+
+bool TemplateName::isNull() const { return Storage.isNull(); }
+
TemplateName::NameKind TemplateName::getKind() const {
if (Storage.is<TemplateDecl *>())
return Template;
@@ -81,6 +97,40 @@
return nullptr;
}
+OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
+ if (UncommonTemplateNameStorage *Uncommon =
+ Storage.dyn_cast<UncommonTemplateNameStorage *>())
+ return Uncommon->getAsOverloadedStorage();
+
+ return nullptr;
+}
+
+SubstTemplateTemplateParmStorage *
+TemplateName::getAsSubstTemplateTemplateParm() const {
+ if (UncommonTemplateNameStorage *uncommon =
+ Storage.dyn_cast<UncommonTemplateNameStorage *>())
+ return uncommon->getAsSubstTemplateTemplateParm();
+
+ return nullptr;
+}
+
+SubstTemplateTemplateParmPackStorage *
+TemplateName::getAsSubstTemplateTemplateParmPack() const {
+ if (UncommonTemplateNameStorage *Uncommon =
+ Storage.dyn_cast<UncommonTemplateNameStorage *>())
+ return Uncommon->getAsSubstTemplateTemplateParmPack();
+
+ return nullptr;
+}
+
+QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
+ return Storage.dyn_cast<QualifiedTemplateName *>();
+}
+
+DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
+ return Storage.dyn_cast<DependentTemplateName *>();
+}
+
bool TemplateName::isDependent() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
if (isa<TemplateTemplateParmDecl>(Template))
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 40fe903..b467dac 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -510,6 +510,28 @@
return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType();
}
+/// Was this type written with the special inert-in-MRC __unsafe_unretained
+/// qualifier?
+///
+/// This approximates the answer to the following question: if this
+/// translation unit were compiled in ARC, would this type be qualified
+/// with __unsafe_unretained?
+bool Type::isObjCInertUnsafeUnretainedType() const {
+ const Type *cur = this;
+ while (true) {
+ if (auto attributed = dyn_cast<AttributedType>(cur)) {
+ if (attributed->getAttrKind() ==
+ AttributedType::attr_objc_inert_unsafe_unretained)
+ return true;
+ }
+
+ // Single-step desugar until we run out of sugar.
+ QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (next.getTypePtr() == cur) return false;
+ cur = next.getTypePtr();
+ }
+}
+
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols,
@@ -948,7 +970,7 @@
== T->getDeducedType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getAutoType(deducedType, T->isDecltypeAuto(),
+ return Ctx.getAutoType(deducedType, T->getKeyword(),
T->isDependentType());
}
@@ -2592,7 +2614,7 @@
case OCLQueue:
return "queue_t";
case OCLNDRange:
- return "event_t";
+ return "ndrange_t";
case OCLReserveID:
return "reserve_id_t";
case OMPArraySection:
@@ -2952,6 +2974,7 @@
case AttributedType::attr_address_space:
case AttributedType::attr_objc_gc:
case AttributedType::attr_objc_ownership:
+ case AttributedType::attr_objc_inert_unsafe_unretained:
case AttributedType::attr_nonnull:
case AttributedType::attr_nullable:
case AttributedType::attr_null_unspecified:
@@ -3010,6 +3033,7 @@
case attr_neon_polyvector_type:
case attr_objc_gc:
case attr_objc_ownership:
+ case attr_objc_inert_unsafe_unretained:
case attr_noreturn:
case attr_nonnull:
case attr_nullable:
@@ -3337,6 +3361,8 @@
return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return Cache::get(cast<AtomicType>(T)->getValueType());
+ case Type::Pipe:
+ return Cache::get(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
@@ -3419,6 +3445,8 @@
return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ case Type::Pipe:
+ return computeLinkageInfo(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
@@ -3577,6 +3605,7 @@
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::Atomic:
+ case Type::Pipe:
return false;
}
llvm_unreachable("bad type kind!");
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index d08b07b..565fa5d 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -80,11 +80,11 @@
while (!TyLoc.isNull()) {
unsigned Align = getLocalAlignmentForType(TyLoc.getType());
MaxAlign = std::max(Align, MaxAlign);
- Total = llvm::RoundUpToAlignment(Total, Align);
+ Total = llvm::alignTo(Total, Align);
Total += TypeSizer().Visit(TyLoc);
TyLoc = TyLoc.getNextTypeLoc();
}
- Total = llvm::RoundUpToAlignment(Total, MaxAlign);
+ Total = llvm::alignTo(Total, MaxAlign);
return Total;
}
@@ -149,12 +149,12 @@
// If both data pointers are aligned to the maximum alignment, we
// can memcpy because getFullDataSize() accurately reflects the
// layout of the data.
- if (reinterpret_cast<uintptr_t>(Data)
- == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
- TypeLocMaxDataAlign) &&
- reinterpret_cast<uintptr_t>(other.Data)
- == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
- TypeLocMaxDataAlign)) {
+ if (reinterpret_cast<uintptr_t>(Data) ==
+ llvm::alignTo(reinterpret_cast<uintptr_t>(Data),
+ TypeLocMaxDataAlign) &&
+ reinterpret_cast<uintptr_t>(other.Data) ==
+ llvm::alignTo(reinterpret_cast<uintptr_t>(other.Data),
+ TypeLocMaxDataAlign)) {
memcpy(Data, other.Data, getFullDataSize());
return;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0bb50c6..b202523 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -193,6 +193,7 @@
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::Atomic:
+ case Type::Pipe:
CanPrefixQualifiers = true;
break;
@@ -835,7 +836,11 @@
if (!T->getDeducedType().isNull()) {
printBefore(T->getDeducedType(), OS);
} else {
- OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto");
+ switch (T->getKeyword()) {
+ case AutoTypeKeyword::Auto: OS << "auto"; break;
+ case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
+ case AutoTypeKeyword::GNUAutoType: OS << "__auto_type"; break;
+ }
spaceBeforePlaceHolder(OS);
}
}
@@ -855,6 +860,15 @@
}
void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
+void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) {
+ IncludeStrongLifetimeRAII Strong(Policy);
+
+ OS << "pipe";
+ spaceBeforePlaceHolder(OS);
+}
+
+void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) {
+}
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
if (DC->isTranslationUnit()) return;
@@ -921,12 +935,13 @@
} else {
// Make an unambiguous representation for anonymous types, e.g.
// (anonymous enum at /usr/include/string.h:120:9)
-
+ OS << (Policy.MSVCFormatting ? '`' : '(');
+
if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
- OS << "(lambda";
+ OS << "lambda";
HasKindDecoration = true;
} else {
- OS << "(anonymous";
+ OS << "anonymous";
}
if (Policy.AnonymousTagLocations) {
@@ -944,8 +959,8 @@
<< ':' << PLoc.getColumn();
}
}
-
- OS << ')';
+
+ OS << (Policy.MSVCFormatting ? '\'' : ')');
}
// If this is a class template specialization, print the template
@@ -1187,6 +1202,10 @@
printAfter(T->getModifiedType(), OS);
+ // Don't print the inert __unsafe_unretained attribute at all.
+ if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
+ return;
+
// Print nullability type specifiers that occur after
if (T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
@@ -1393,6 +1412,7 @@
unsigned NumArgs,
const PrintingPolicy &Policy,
bool SkipBrackets) {
+ const char *Comma = Policy.MSVCFormatting ? "," : ", ";
if (!SkipBrackets)
OS << '<';
@@ -1403,14 +1423,14 @@
llvm::raw_svector_ostream ArgOS(Buf);
if (Args[Arg].getKind() == TemplateArgument::Pack) {
if (Args[Arg].pack_size() && Arg > 0)
- OS << ", ";
+ OS << Comma;
PrintTemplateArgumentList(ArgOS,
Args[Arg].pack_begin(),
Args[Arg].pack_size(),
Policy, true);
} else {
if (Arg > 0)
- OS << ", ";
+ OS << Comma;
Args[Arg].print(Policy, ArgOS);
}
StringRef ArgString = ArgOS.str();
@@ -1442,11 +1462,12 @@
const TemplateArgumentLoc *Args, unsigned NumArgs,
const PrintingPolicy &Policy) {
OS << '<';
+ const char *Comma = Policy.MSVCFormatting ? "," : ", ";
bool needSpace = false;
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
if (Arg > 0)
- OS << ", ";
+ OS << Comma;
// Print the argument into a string.
SmallString<128> Buf;
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 6829da5..bae0186 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -2882,22 +2882,26 @@
// Put the virtual methods into VirtualMethods in the proper order:
// 1) Group overloads by declaration name. New groups are added to the
// vftable in the order of their first declarations in this class
- // (including overrides and non-virtual methods).
+ // (including overrides, non-virtual methods and any other named decl that
+ // might be nested within the class).
// 2) In each group, new overloads appear in the reverse order of declaration.
typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
SmallVector<MethodGroup, 10> Groups;
typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
VisitedGroupIndicesTy VisitedGroupIndices;
- for (const auto *MD : RD->methods()) {
- MD = MD->getCanonicalDecl();
+ for (const auto *D : RD->decls()) {
+ const auto *ND = dyn_cast<NamedDecl>(D);
+ if (!ND)
+ continue;
VisitedGroupIndicesTy::iterator J;
bool Inserted;
std::tie(J, Inserted) = VisitedGroupIndices.insert(
- std::make_pair(MD->getDeclName(), Groups.size()));
+ std::make_pair(ND->getDeclName(), Groups.size()));
if (Inserted)
Groups.push_back(MethodGroup());
- if (MD->isVirtual())
- Groups[J->second].push_back(MD);
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(ND))
+ if (MD->isVirtual())
+ Groups[J->second].push_back(MD->getCanonicalDecl());
}
for (const MethodGroup &Group : Groups)
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 571e7da..847398c 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -197,9 +197,6 @@
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
- // Disables data recursion. We intercept Traverse* methods in the RAV, which
- // are not triggered during data recursion.
- bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
// Used for updating the depth during traversal.
@@ -487,9 +484,6 @@
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
- // Disables data recursion. We intercept Traverse* methods in the RAV, which
- // are not triggered during data recursion.
- bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
class TimeBucketRegion {
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index eb41de1..e2c9a47 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -108,6 +108,7 @@
REGISTER_MATCHER(autoType);
REGISTER_MATCHER(binaryOperator);
REGISTER_MATCHER(blockPointerType);
+ REGISTER_MATCHER(booleanType);
REGISTER_MATCHER(breakStmt);
REGISTER_MATCHER(builtinType);
REGISTER_MATCHER(callExpr);
@@ -173,6 +174,7 @@
REGISTER_MATCHER(fieldDecl);
REGISTER_MATCHER(floatLiteral);
REGISTER_MATCHER(forEach);
+ REGISTER_MATCHER(forEachArgumentWithParam);
REGISTER_MATCHER(forEachConstructorInitializer);
REGISTER_MATCHER(forEachDescendant);
REGISTER_MATCHER(forEachSwitchCase);
@@ -194,6 +196,7 @@
REGISTER_MATCHER(hasArgument);
REGISTER_MATCHER(hasArgumentOfType);
REGISTER_MATCHER(hasAttr);
+ REGISTER_MATCHER(hasAutomaticStorageDuration);
REGISTER_MATCHER(hasBase);
REGISTER_MATCHER(hasBody);
REGISTER_MATCHER(hasCanonicalType);
@@ -238,9 +241,11 @@
REGISTER_MATCHER(hasSize);
REGISTER_MATCHER(hasSizeExpr);
REGISTER_MATCHER(hasSourceExpression);
+ REGISTER_MATCHER(hasStaticStorageDuration);
REGISTER_MATCHER(hasTargetDecl);
REGISTER_MATCHER(hasTemplateArgument);
REGISTER_MATCHER(hasThen);
+ REGISTER_MATCHER(hasThreadStorageDuration);
REGISTER_MATCHER(hasTrueExpression);
REGISTER_MATCHER(hasTypeLoc);
REGISTER_MATCHER(hasUnaryOperand);
@@ -265,6 +270,7 @@
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isCopyConstructor);
REGISTER_MATCHER(isDefaultConstructor);
+ REGISTER_MATCHER(isDefaulted);
REGISTER_MATCHER(isDefinition);
REGISTER_MATCHER(isDeleted);
REGISTER_MATCHER(isExceptionVariable);
@@ -285,6 +291,7 @@
REGISTER_MATCHER(isListInitialization);
REGISTER_MATCHER(isMemberInitializer);
REGISTER_MATCHER(isMoveConstructor);
+ REGISTER_MATCHER(isNoThrow);
REGISTER_MATCHER(isOverride);
REGISTER_MATCHER(isPrivate);
REGISTER_MATCHER(isProtected);
@@ -295,6 +302,7 @@
REGISTER_MATCHER(isUnion);
REGISTER_MATCHER(isVariadic);
REGISTER_MATCHER(isVirtual);
+ REGISTER_MATCHER(isVolatileQualified);
REGISTER_MATCHER(isWritten);
REGISTER_MATCHER(labelStmt);
REGISTER_MATCHER(lambdaExpr);
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index d7fb7e9..52c7f26 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -148,6 +148,23 @@
}
}
+ auto *CXXMethod = dyn_cast<CXXMethodDecl>(D);
+ if (!CXXMethod)
+ return nullptr;
+
+ const CXXRecordDecl *parent = CXXMethod->getParent();
+ if (!parent->isLambda())
+ return nullptr;
+
+ for (const LambdaCapture &LC : parent->captures()) {
+ if (!LC.capturesVariable())
+ continue;
+
+ VarDecl *VD = LC.getCapturedVar();
+ if (VD->getName() == "self")
+ return dyn_cast<ImplicitParamDecl>(VD);
+ }
+
return nullptr;
}
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 0990436..2118301 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -383,10 +383,49 @@
return Val.getValue();
}
+static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
+ const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
+
+ if (IVar)
+ return IVar;
+
+ // When a readonly property is shadowed in a class extensions with a
+ // a readwrite property, the instance variable belongs to the shadowing
+ // property rather than the shadowed property. If there is no instance
+ // variable on a readonly property, check to see whether the property is
+ // shadowed and if so try to get the instance variable from shadowing
+ // property.
+ if (!Prop->isReadOnly())
+ return nullptr;
+
+ auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
+ const ObjCInterfaceDecl *PrimaryInterface = nullptr;
+ if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ PrimaryInterface = InterfaceDecl;
+ } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
+ PrimaryInterface = CategoryDecl->getClassInterface();
+ } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
+ PrimaryInterface = ImplDecl->getClassInterface();
+ } else {
+ return nullptr;
+ }
+
+ // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
+ // is guaranteed to find the shadowing property, if it exists, rather than
+ // the shadowed property.
+ auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
+ Prop->getIdentifier(), Prop->getQueryKind());
+ if (ShadowingProp && ShadowingProp != Prop) {
+ IVar = ShadowingProp->getPropertyIvarDecl();
+ }
+
+ return IVar;
+}
+
static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
const ObjCPropertyDecl *Prop) {
// First, find the backing ivar.
- const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
+ const ObjCIvarDecl *IVar = findBackingIvar(Prop);
if (!IVar)
return nullptr;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 6cb63f2..ed2239f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -460,6 +460,7 @@
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
CFGBlock *VisitLabelStmt(LabelStmt *L);
+ CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc);
CFGBlock *VisitLogicalOperator(BinaryOperator *B);
std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
@@ -824,10 +825,7 @@
// * Variable x is equal to the largest literal.
// * Variable x is greater than largest literal.
bool AlwaysTrue = true, AlwaysFalse = true;
- for (unsigned int ValueIndex = 0;
- ValueIndex < sizeof(Values) / sizeof(Values[0]);
- ++ValueIndex) {
- llvm::APSInt Value = Values[ValueIndex];
+ for (llvm::APSInt Value : Values) {
TryResult Res1, Res2;
Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
@@ -1453,7 +1451,7 @@
return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
case Stmt::BlockExprClass:
- return VisitNoRecurse(cast<Expr>(S), asc);
+ return VisitBlockExpr(cast<BlockExpr>(S), asc);
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
@@ -1942,7 +1940,15 @@
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
- addLocalScopeAndDtors(C);
+ LocalScope::const_iterator scopeBeginPos = ScopePos;
+ if (BuildOpts.AddImplicitDtors) {
+ addLocalScopeForStmt(C);
+ }
+ if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
+ // If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt
+ addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
+ }
+
CFGBlock *LastBlock = Block;
for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
@@ -2325,6 +2331,18 @@
return LabelBlock;
}
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
+ CFGBlock *LastBlock = VisitNoRecurse(E, asc);
+ for (const BlockDecl::Capture &CI : E->getBlockDecl()->captures()) {
+ if (Expr *CopyExpr = CI.getCopyExpr()) {
+ CFGBlock *Tmp = Visit(CopyExpr);
+ if (Tmp)
+ LastBlock = Tmp;
+ }
+ }
+ return LastBlock;
+}
+
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index bce5175..b282a5b 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -258,16 +258,15 @@
typedef SmallVector<const ValueDecl*, 4> BeforeVect;
struct BeforeInfo {
- BeforeInfo() : Vect(nullptr), Visited(false) { }
- BeforeInfo(BeforeInfo &&O)
- : Vect(std::move(O.Vect)), Visited(O.Visited)
- {}
+ BeforeInfo() : Visited(0) {}
+ BeforeInfo(BeforeInfo &&O) : Vect(std::move(O.Vect)), Visited(O.Visited) {}
- std::unique_ptr<BeforeVect> Vect;
- int Visited;
+ BeforeVect Vect;
+ int Visited;
};
- typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap;
+ typedef llvm::DenseMap<const ValueDecl *, std::unique_ptr<BeforeInfo>>
+ BeforeMap;
typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap;
public:
@@ -276,6 +275,9 @@
BeforeInfo* insertAttrExprs(const ValueDecl* Vd,
ThreadSafetyAnalyzer& Analyzer);
+ BeforeInfo *getBeforeInfoForDecl(const ValueDecl *Vd,
+ ThreadSafetyAnalyzer &Analyzer);
+
void checkBeforeAfter(const ValueDecl* Vd,
const FactSet& FSet,
ThreadSafetyAnalyzer& Analyzer,
@@ -965,26 +967,27 @@
BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
ThreadSafetyAnalyzer& Analyzer) {
// Create a new entry for Vd.
- auto& Entry = BMap.FindAndConstruct(Vd);
- BeforeInfo* Info = &Entry.second;
- BeforeVect* Bv = nullptr;
+ BeforeInfo *Info = nullptr;
+ {
+ // Keep InfoPtr in its own scope in case BMap is modified later and the
+ // reference becomes invalid.
+ std::unique_ptr<BeforeInfo> &InfoPtr = BMap[Vd];
+ if (!InfoPtr)
+ InfoPtr.reset(new BeforeInfo());
+ Info = InfoPtr.get();
+ }
for (Attr* At : Vd->attrs()) {
switch (At->getKind()) {
case attr::AcquiredBefore: {
auto *A = cast<AcquiredBeforeAttr>(At);
- // Create a new BeforeVect for Vd if necessary.
- if (!Bv) {
- Bv = new BeforeVect;
- Info->Vect.reset(Bv);
- }
// Read exprs from the attribute, and add them to BeforeVect.
for (const auto *Arg : A->args()) {
CapabilityExpr Cp =
Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
if (const ValueDecl *Cpvd = Cp.valueDecl()) {
- Bv->push_back(Cpvd);
+ Info->Vect.push_back(Cpvd);
auto It = BMap.find(Cpvd);
if (It == BMap.end())
insertAttrExprs(Cpvd, Analyzer);
@@ -1001,20 +1004,8 @@
Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
if (const ValueDecl *ArgVd = Cp.valueDecl()) {
// Get entry for mutex listed in attribute
- BeforeInfo* ArgInfo;
- auto It = BMap.find(ArgVd);
- if (It == BMap.end())
- ArgInfo = insertAttrExprs(ArgVd, Analyzer);
- else
- ArgInfo = &It->second;
-
- // Create a new BeforeVect if necessary.
- BeforeVect* ArgBv = ArgInfo->Vect.get();
- if (!ArgBv) {
- ArgBv = new BeforeVect;
- ArgInfo->Vect.reset(ArgBv);
- }
- ArgBv->push_back(Vd);
+ BeforeInfo *ArgInfo = getBeforeInfoForDecl(ArgVd, Analyzer);
+ ArgInfo->Vect.push_back(Vd);
}
}
break;
@@ -1027,6 +1018,18 @@
return Info;
}
+BeforeSet::BeforeInfo *
+BeforeSet::getBeforeInfoForDecl(const ValueDecl *Vd,
+ ThreadSafetyAnalyzer &Analyzer) {
+ auto It = BMap.find(Vd);
+ BeforeInfo *Info = nullptr;
+ if (It == BMap.end())
+ Info = insertAttrExprs(Vd, Analyzer);
+ else
+ Info = It->second.get();
+ assert(Info && "BMap contained nullptr?");
+ return Info;
+}
/// Return true if any mutexes in FSet are in the acquired_before set of Vd.
void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
@@ -1041,12 +1044,7 @@
if (!Vd)
return false;
- BeforeSet::BeforeInfo* Info;
- auto It = BMap.find(Vd);
- if (It == BMap.end())
- Info = insertAttrExprs(Vd, Analyzer);
- else
- Info = &It->second;
+ BeforeSet::BeforeInfo *Info = getBeforeInfoForDecl(Vd, Analyzer);
if (Info->Visited == 1)
return true;
@@ -1054,13 +1052,12 @@
if (Info->Visited == 2)
return false;
- BeforeVect* Bv = Info->Vect.get();
- if (!Bv)
+ if (Info->Vect.empty())
return false;
InfoVect.push_back(Info);
Info->Visited = 1;
- for (auto *Vdb : *Bv) {
+ for (auto *Vdb : Info->Vect) {
// Exclude mutexes in our immediate before set.
if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
StringRef L1 = StartVd->getName();
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 69b10c1..fb6a645 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -48,10 +48,20 @@
AuxTSRecords = AuxTarget->getTargetBuiltins();
}
+bool Builtin::Context::isBuiltinFunc(const char *Name) {
+ StringRef FuncName(Name);
+ for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i)
+ if (FuncName.equals(BuiltinInfo[i].Name))
+ return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr;
+
+ return false;
+}
+
bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo,
const LangOptions &LangOpts) {
- bool BuiltinsUnsupported = LangOpts.NoBuiltin &&
- strchr(BuiltinInfo.Attributes, 'f');
+ bool BuiltinsUnsupported =
+ (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) &&
+ strchr(BuiltinInfo.Attributes, 'f');
bool MathBuiltinsUnsupported =
LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 0caa876..7cf7305 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -226,12 +226,12 @@
// Update all diagnostic states that are active after the given location.
for (DiagStatePointsTy::iterator
I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
- GetCurDiagState()->setMapping(Diag, Mapping);
+ I->State->setMapping(Diag, Mapping);
}
// If the location corresponds to an existing point, just update its state.
if (Pos->Loc == Loc) {
- GetCurDiagState()->setMapping(Diag, Mapping);
+ Pos->State->setMapping(Diag, Mapping);
return;
}
@@ -240,7 +240,7 @@
assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
DiagStates.push_back(*Pos->State);
DiagState *NewState = &DiagStates.back();
- GetCurDiagState()->setMapping(Diag, Mapping);
+ NewState->setMapping(Diag, Mapping);
DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
FullSourceLoc(Loc, *SourceMgr)));
}
@@ -278,8 +278,8 @@
return true;
// Perform the mapping change.
- for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
- DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]);
+ for (diag::kind Diag : GroupDiags) {
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Error ||
Info.getSeverity() == diag::Severity::Fatal)
@@ -309,8 +309,8 @@
return true;
// Perform the mapping change.
- for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
- DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]);
+ for (diag::kind Diag : GroupDiags) {
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Fatal)
Info.setSeverity(diag::Severity::Error);
@@ -329,9 +329,9 @@
Diags->getAllDiagnostics(Flavor, AllDiags);
// Set the mapping.
- for (unsigned i = 0, e = AllDiags.size(); i != e; ++i)
- if (Diags->isBuiltinWarningOrExtension(AllDiags[i]))
- setSeverity(AllDiags[i], Map, Loc);
+ for (diag::kind Diag : AllDiags)
+ if (Diags->isBuiltinWarningOrExtension(Diag))
+ setSeverity(Diag, Map, Loc);
}
void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 8a523d2..cb3f75c 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -22,6 +22,7 @@
#include "clang/Frontend/PCHContainerOperations.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -58,12 +59,7 @@
this->FS = vfs::getRealFileSystem();
}
-FileManager::~FileManager() {
- for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
- delete VirtualFileEntries[i];
- for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
- delete VirtualDirectoryEntries[i];
-}
+FileManager::~FileManager() = default;
void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache,
bool AtBeginning) {
@@ -137,14 +133,14 @@
// at the same time. Therefore, if DirName is already in the cache,
// we don't need to recurse as its ancestors must also already be in
// the cache.
- if (NamedDirEnt.second)
+ if (NamedDirEnt.second && NamedDirEnt.second != NON_EXISTENT_DIR)
return;
// Add the virtual directory to the cache.
- DirectoryEntry *UDE = new DirectoryEntry;
+ auto UDE = llvm::make_unique<DirectoryEntry>();
UDE->Name = NamedDirEnt.first().data();
- NamedDirEnt.second = UDE;
- VirtualDirectoryEntries.push_back(UDE);
+ NamedDirEnt.second = UDE.get();
+ VirtualDirectoryEntries.push_back(std::move(UDE));
// Recursively add the other ancestors.
addAncestorsAsVirtualDirs(DirName);
@@ -375,8 +371,8 @@
}
if (!UFE) {
- UFE = new FileEntry();
- VirtualFileEntries.push_back(UFE);
+ VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
+ UFE = VirtualFileEntries.back().get();
NamedFileEnt.second = UFE;
}
@@ -513,11 +509,9 @@
UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
// Map virtual file entries
- for (SmallVectorImpl<FileEntry *>::const_iterator
- VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
- VFE != VFEEnd; ++VFE)
- if (*VFE && *VFE != NON_EXISTENT_FILE)
- UIDToFiles[(*VFE)->getUID()] = *VFE;
+ for (const auto &VFE : VirtualFileEntries)
+ if (VFE && VFE.get() != NON_EXISTENT_FILE)
+ UIDToFiles[VFE->getUID()] = VFE.get();
}
void FileManager::modifyFileEntry(FileEntry *File,
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 2c87845..1b08b06 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/StringRef.h"
using namespace clang;
@@ -36,3 +37,10 @@
ImplementationOfModule.clear();
}
+bool LangOptions::isNoBuiltinFunc(const char *Name) const {
+ StringRef FuncName(Name);
+ for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i)
+ if (FuncName.equals(NoBuiltinFuncs[i]))
+ return true;
+ return false;
+}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 7a7557e..687bf4c 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -87,8 +87,11 @@
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_PROC_BIND_unknown);
case OMPC_schedule:
- return llvm::StringSwitch<OpenMPScheduleClauseKind>(Str)
-#define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##Name)
+ return llvm::StringSwitch<unsigned>(Str)
+#define OPENMP_SCHEDULE_KIND(Name) \
+ .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_##Name))
+#define OPENMP_SCHEDULE_MODIFIER(Name) \
+ .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_MODIFIER_##Name))
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_SCHEDULE_unknown);
case OMPC_depend:
@@ -101,6 +104,16 @@
#define OPENMP_LINEAR_KIND(Name) .Case(#Name, OMPC_LINEAR_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_LINEAR_unknown);
+ case OMPC_map:
+ return llvm::StringSwitch<OpenMPMapClauseKind>(Str)
+#define OPENMP_MAP_KIND(Name) .Case(#Name, OMPC_MAP_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_MAP_unknown);
+ case OMPC_dist_schedule:
+ return llvm::StringSwitch<OpenMPDistScheduleClauseKind>(Str)
+#define OPENMP_DIST_SCHEDULE_KIND(Name) .Case(#Name, OMPC_DIST_SCHEDULE_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_DIST_SCHEDULE_unknown);
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -130,6 +143,13 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -161,12 +181,17 @@
case OMPC_schedule:
switch (Type) {
case OMPC_SCHEDULE_unknown:
+ case OMPC_SCHEDULE_MODIFIER_last:
return "unknown";
#define OPENMP_SCHEDULE_KIND(Name) \
- case OMPC_SCHEDULE_##Name: \
- return #Name;
+ case OMPC_SCHEDULE_##Name: \
+ return #Name;
+#define OPENMP_SCHEDULE_MODIFIER(Name) \
+ case OMPC_SCHEDULE_MODIFIER_##Name: \
+ return #Name;
#include "clang/Basic/OpenMPKinds.def"
}
+ llvm_unreachable("Invalid OpenMP 'schedule' clause type");
case OMPC_depend:
switch (Type) {
case OMPC_DEPEND_unknown:
@@ -176,7 +201,7 @@
return #Name;
#include "clang/Basic/OpenMPKinds.def"
}
- llvm_unreachable("Invalid OpenMP 'schedule' clause type");
+ llvm_unreachable("Invalid OpenMP 'depend' clause type");
case OMPC_linear:
switch (Type) {
case OMPC_LINEAR_unknown:
@@ -187,6 +212,28 @@
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'linear' clause type");
+ case OMPC_map:
+ switch (Type) {
+ case OMPC_MAP_unknown:
+ return "unknown";
+#define OPENMP_MAP_KIND(Name) \
+ case OMPC_MAP_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP 'map' clause type");
+ case OMPC_dist_schedule:
+ switch (Type) {
+ case OMPC_DIST_SCHEDULE_unknown:
+ return "unknown";
+#define OPENMP_DIST_SCHEDULE_KIND(Name) \
+ case OMPC_DIST_SCHEDULE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'dist_schedule' clause type");
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -216,6 +263,13 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -381,7 +435,47 @@
break;
case OMPD_ordered:
switch (CKind) {
-#define OPENMP_ORDERED_CLAUSE(Name) \
+#define OPENMP_ORDERED_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_taskloop:
+ switch (CKind) {
+#define OPENMP_TASKLOOP_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_taskloop_simd:
+ switch (CKind) {
+#define OPENMP_TASKLOOP_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_critical:
+ switch (CKind) {
+#define OPENMP_CRITICAL_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_distribute:
+ switch (CKind) {
+#define OPENMP_DISTRIBUTE_CLAUSE(Name) \
case OMPC_##Name: \
return true;
#include "clang/Basic/OpenMPKinds.def"
@@ -393,7 +487,6 @@
case OMPD_threadprivate:
case OMPD_section:
case OMPD_master:
- case OMPD_critical:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
@@ -406,8 +499,10 @@
bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd ||
- DKind == OMPD_parallel_for ||
- DKind == OMPD_parallel_for_simd; // TODO add next directives.
+ DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd ||
+ DKind == OMPD_taskloop ||
+ DKind == OMPD_taskloop_simd ||
+ DKind == OMPD_distribute; // TODO add next directives.
}
bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
@@ -418,6 +513,10 @@
DKind == OMPD_parallel_sections; // TODO add next directives.
}
+bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd;
+}
+
bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_parallel || DKind == OMPD_parallel_for ||
DKind == OMPD_parallel_for_simd ||
@@ -434,7 +533,12 @@
bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for_simd ||
- DKind == OMPD_parallel_for_simd; // TODO add next directives.
+ DKind == OMPD_parallel_for_simd ||
+ DKind == OMPD_taskloop_simd; // TODO add next directives.
+}
+
+bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) {
+ return Kind == OMPD_distribute; // TODO add next directives.
}
bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 536ae7f..4c50161 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -279,9 +279,7 @@
/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
///
unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
- if (!LineTable)
- LineTable = new LineTableInfo();
- return LineTable->getLineTableFilenameID(Name);
+ return getLineTable().getLineTableFilenameID(Name);
}
@@ -302,9 +300,7 @@
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
- if (!LineTable)
- LineTable = new LineTableInfo();
- LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
+ getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
}
/// AddLineNote - Add a GNU line marker to the line table.
@@ -332,8 +328,7 @@
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
- if (!LineTable)
- LineTable = new LineTableInfo();
+ (void) getLineTable();
SrcMgr::CharacteristicKind FileKind;
if (IsExternCHeader)
@@ -366,7 +361,7 @@
SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
bool UserFilesAreVolatile)
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
- UserFilesAreVolatile(UserFilesAreVolatile),
+ UserFilesAreVolatile(UserFilesAreVolatile), FilesAreTransient(false),
ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0),
NumBinaryProbes(0) {
clearIDTables();
@@ -444,6 +439,7 @@
}
Entry->IsSystemFile = isSystemFile;
+ Entry->IsTransient = FilesAreTransient;
return Entry;
}
@@ -678,11 +674,9 @@
OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File);
}
-void SourceManager::embedFileContentsInModule(const FileEntry *File) {
- // We model an embedded file as a file whose buffer has been overridden
- // by its contents as they are now.
+void SourceManager::setFileIsTransient(const FileEntry *File) {
const SrcMgr::ContentCache *CC = getOrCreateContentCache(File);
- const_cast<SrcMgr::ContentCache *>(CC)->BufferOverridden = true;
+ const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true;
}
StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
@@ -1723,7 +1717,7 @@
unsigned Col) const {
// Lines are used as a one-based index into a zero-based array. This assert
// checks for possible buffer underruns.
- assert(Line != 0 && "Passed a zero-based line");
+ assert(Line && Col && "Line and column should start from 1!");
if (FID.isInvalid())
return SourceLocation();
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a6cda4b..d75aa3e 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -223,7 +223,24 @@
public:
DarwinTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
- this->TLSSupported = Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 7);
+ // By default, no TLS, and we whitelist permitted architecture/OS
+ // combinations.
+ this->TLSSupported = false;
+
+ if (Triple.isMacOSX())
+ this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7);
+ else if (Triple.isiOS()) {
+ // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards.
+ if (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::aarch64)
+ this->TLSSupported = !Triple.isOSVersionLT(8);
+ else if (Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb)
+ this->TLSSupported = !Triple.isOSVersionLT(9);
+ } else if (Triple.isWatchOS())
+ this->TLSSupported = !Triple.isOSVersionLT(2);
+
this->MCountName = "\01mcount";
}
@@ -1826,8 +1843,15 @@
}
bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- return true;
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default: break;
+ case 'v': // vgpr
+ case 's': // sgpr
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -2088,6 +2112,7 @@
bool HasXSAVEOPT = false;
bool HasXSAVEC = false;
bool HasXSAVES = false;
+ bool HasPKU = false;
/// \brief Enumeration of all of the X86 CPUs supported by Clang.
///
@@ -2358,6 +2383,20 @@
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override;
+ bool validateGlobalRegisterVariable(StringRef RegName,
+ unsigned RegSize,
+ bool &HasSizeMismatch) const override {
+ // esp and ebp are the only 32-bit registers the x86 backend can currently
+ // handle.
+ if (RegName.equals("esp") || RegName.equals("ebp")) {
+ // Check that the register size is 32-bit.
+ HasSizeMismatch = RegSize != 32;
+ return true;
+ }
+
+ return false;
+ }
+
bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
bool validateInputSize(StringRef Constraint, unsigned Size) const override;
@@ -2575,6 +2614,7 @@
setFeatureEnabledImpl(Features, "avx512vl", true);
setFeatureEnabledImpl(Features, "xsavec", true);
setFeatureEnabledImpl(Features, "xsaves", true);
+ setFeatureEnabledImpl(Features, "pku", true);
// FALLTHROUGH
case CK_Broadwell:
setFeatureEnabledImpl(Features, "rdseed", true);
@@ -3000,6 +3040,8 @@
HasXSAVEC = true;
} else if (Feature == "+xsaves") {
HasXSAVES = true;
+ } else if (Feature == "+pku") {
+ HasPKU = true;
}
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
@@ -3301,7 +3343,8 @@
Builder.defineMacro("__XSAVEC__");
if (HasXSAVES)
Builder.defineMacro("__XSAVES__");
-
+ if (HasPKU)
+ Builder.defineMacro("__PKU__");
if (HasCX16)
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
@@ -3370,11 +3413,6 @@
}
if (CPU >= CK_i586)
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
-
- if (getTriple().isOSIAMCU()) {
- Builder.defineMacro("__iamcu");
- Builder.defineMacro("__iamcu__");
- }
}
bool X86TargetInfo::hasFeature(StringRef Feature) const {
@@ -3424,6 +3462,7 @@
.Case("xsavec", HasXSAVEC)
.Case("xsaves", HasXSAVES)
.Case("xsaveopt", HasXSAVEOPT)
+ .Case("pku", HasPKU)
.Default(false);
}
@@ -3623,11 +3662,6 @@
IntPtrType = SignedInt;
RegParmMax = 3;
- if (getTriple().isOSIAMCU()) {
- LongDoubleWidth = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- }
-
// Use fpret for all types.
RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
(1 << TargetInfo::Double) |
@@ -3823,7 +3857,6 @@
public:
CygwinX86_32TargetInfo(const llvm::Triple &Triple)
: X86_32TargetInfo(Triple) {
- TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
DataLayoutString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32";
@@ -3860,6 +3893,28 @@
}
};
+// X86-32 MCU target
+class MCUX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ MCUX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) {
+ LongDoubleWidth = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ UserLabelPrefix = "";
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ // On MCU we support only C calling convention.
+ return CC == CC_C ? CCCR_OK : CCCR_Warning;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__iamcu");
+ Builder.defineMacro("__iamcu__");
+ }
+};
+
// RTEMS Target
template<typename Target>
class RTEMSTargetInfo : public OSTargetInfo<Target> {
@@ -3974,6 +4029,22 @@
// for x32 we need it here explicitly
bool hasInt128Type() const override { return true; }
+
+ bool validateGlobalRegisterVariable(StringRef RegName,
+ unsigned RegSize,
+ bool &HasSizeMismatch) const override {
+ // rsp and rbp are the only 64-bit registers the x86 backend can currently
+ // handle.
+ if (RegName.equals("rsp") || RegName.equals("rbp")) {
+ // Check that the register size is 64-bit.
+ HasSizeMismatch = RegSize != 64;
+ return true;
+ }
+
+ // Check if the register is a 32-bit register the backend can handle.
+ return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize,
+ HasSizeMismatch);
+ }
};
// x86-64 Windows target
@@ -4366,15 +4437,10 @@
default:
return llvm::ARM::getCPUAttr(ArchKind);
case llvm::ARM::AK_ARMV6M:
- case llvm::ARM::AK_ARMV6SM:
- case llvm::ARM::AK_ARMV6HL:
return "6M";
case llvm::ARM::AK_ARMV7S:
return "7S";
- case llvm::ARM::AK_ARMV7:
case llvm::ARM::AK_ARMV7A:
- case llvm::ARM::AK_ARMV7L:
- case llvm::ARM::AK_ARMV7HL:
return "7A";
case llvm::ARM::AK_ARMV7R:
return "7R";
@@ -4434,7 +4500,7 @@
Triple.getOS() == llvm::Triple::UnknownOS ||
StringRef(CPU).startswith("cortex-m")) {
setABI("aapcs");
- } else if (Triple.isWatchOS()) {
+ } else if (Triple.isWatchABI()) {
setABI("aapcs16");
} else {
setABI("apcs-gnu");
@@ -4506,13 +4572,14 @@
const std::vector<std::string> &FeaturesVec) const override {
std::vector<const char*> TargetFeatures;
+ unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName());
// get default FPU features
- unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU);
+ unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch);
llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures);
// get default Extension features
- unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU);
+ unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch);
llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures);
for (const char *Feature : TargetFeatures)
@@ -4649,7 +4716,7 @@
// Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU
// happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__.
- if (getTriple().isWatchOS())
+ if (getTriple().isWatchABI())
Builder.defineMacro("__ARM_ARCH_7K__", "2");
if (!CPUAttr.empty())
@@ -4657,7 +4724,7 @@
// ACLE 6.4.1 ARM/Thumb instruction set architecture
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
- Builder.defineMacro("__ARM_ARCH", llvm::utostr(ArchVersion));
+ Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
if (ArchVersion >= 8) {
// ACLE 6.5.7 Crypto Extension
@@ -4825,6 +4892,9 @@
if (Opts.UnsafeFPMath)
Builder.defineMacro("__ARM_FP_FAST", "1");
+
+ if (ArchKind == llvm::ARM::AK_ARMV8_1A)
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -4835,8 +4905,8 @@
BuiltinVaListKind getBuiltinVaListKind() const override {
return IsAAPCS
? AAPCSABIBuiltinVaList
- : (getTriple().isWatchOS() ? TargetInfo::CharPtrBuiltinVaList
- : TargetInfo::VoidPtrBuiltinVaList);
+ : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList
+ : TargetInfo::VoidPtrBuiltinVaList);
}
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
@@ -5177,7 +5247,7 @@
// ARMleTargetInfo.
MaxAtomicInlineWidth = 64;
- if (Triple.isWatchOS()) {
+ if (Triple.isWatchABI()) {
// Darwin on iOS uses a variant of the ARM C++ ABI.
TheCXXABI.set(TargetCXXABI::WatchOS);
@@ -5206,6 +5276,7 @@
unsigned CRC;
unsigned Crypto;
unsigned Unaligned;
+ unsigned V8_1A;
static const Builtin::Info BuiltinInfo[];
@@ -5263,7 +5334,8 @@
bool setCPU(const std::string &Name) override {
bool CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("generic", true)
- .Cases("cortex-a53", "cortex-a57", "cortex-a72", true)
+ .Cases("cortex-a53", "cortex-a57", "cortex-a72",
+ "cortex-a35", "exynos-m1", true)
.Case("cyclone", true)
.Default(false);
return CPUKnown;
@@ -5328,6 +5400,9 @@
if (Unaligned)
Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
+ if (V8_1A)
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+
// All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
@@ -5353,6 +5428,7 @@
CRC = 0;
Crypto = 0;
Unaligned = 1;
+ V8_1A = 0;
for (const auto &Feature : Features) {
if (Feature == "+neon")
@@ -5363,6 +5439,8 @@
Crypto = 1;
if (Feature == "+strict-align")
Unaligned = 0;
+ if (Feature == "+v8.1a")
+ V8_1A = 1;
}
setDataLayoutString();
@@ -5591,14 +5669,27 @@
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
std::string CPU;
+ bool HasHVX, HasHVXDouble;
+
public:
HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
- DataLayoutString = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32";
+ DataLayoutString = "e-m:e-p:32:32:32-"
+ "i64:64:64-i32:32:32-i16:16:16-i1:8:8-"
+ "f64:64:64-f32:32:32-v64:64:64-v32:32:32-a:0-n16:32";
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
// {} in inline assembly are packet specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
+
+ LargeArrayMinWidth = 64;
+ LargeArrayAlign = 64;
+ UseBitFieldTypeAlignment = true;
+ ZeroLengthBitfieldBoundary = 32;
+ HasHVX = HasHVXDouble = false;
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -5614,10 +5705,23 @@
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
+ bool isCLZForZeroUndef() const override { return false; }
+
bool hasFeature(StringRef Feature) const override {
- return Feature == "hexagon";
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("hexagon", true)
+ .Case("hvx", HasHVX)
+ .Case("hvx-double", HasHVXDouble)
+ .Default(false);
}
+ bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU, const std::vector<std::string> &FeaturesVec)
+ const override;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
@@ -5631,71 +5735,77 @@
return llvm::StringSwitch<const char*>(Name)
.Case("hexagonv4", "4")
.Case("hexagonv5", "5")
+ .Case("hexagonv55", "55")
+ .Case("hexagonv60", "60")
.Default(nullptr);
}
bool setCPU(const std::string &Name) override {
if (!getHexagonCPUSuffix(Name))
return false;
-
CPU = Name;
return true;
}
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ return RegNo < 2 ? RegNo : -1;
+ }
};
void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("qdsp6");
- Builder.defineMacro("__qdsp6", "1");
+ MacroBuilder &Builder) const {
Builder.defineMacro("__qdsp6__", "1");
-
- Builder.defineMacro("hexagon");
- Builder.defineMacro("__hexagon", "1");
Builder.defineMacro("__hexagon__", "1");
- if(CPU == "hexagonv1") {
- Builder.defineMacro("__HEXAGON_V1__");
- Builder.defineMacro("__HEXAGON_ARCH__", "1");
- if(Opts.HexagonQdsp6Compat) {
- Builder.defineMacro("__QDSP6_V1__");
- Builder.defineMacro("__QDSP6_ARCH__", "1");
- }
- }
- else if(CPU == "hexagonv2") {
- Builder.defineMacro("__HEXAGON_V2__");
- Builder.defineMacro("__HEXAGON_ARCH__", "2");
- if(Opts.HexagonQdsp6Compat) {
- Builder.defineMacro("__QDSP6_V2__");
- Builder.defineMacro("__QDSP6_ARCH__", "2");
- }
- }
- else if(CPU == "hexagonv3") {
- Builder.defineMacro("__HEXAGON_V3__");
- Builder.defineMacro("__HEXAGON_ARCH__", "3");
- if(Opts.HexagonQdsp6Compat) {
- Builder.defineMacro("__QDSP6_V3__");
- Builder.defineMacro("__QDSP6_ARCH__", "3");
- }
- }
- else if(CPU == "hexagonv4") {
+ if (CPU == "hexagonv4") {
Builder.defineMacro("__HEXAGON_V4__");
Builder.defineMacro("__HEXAGON_ARCH__", "4");
- if(Opts.HexagonQdsp6Compat) {
+ if (Opts.HexagonQdsp6Compat) {
Builder.defineMacro("__QDSP6_V4__");
Builder.defineMacro("__QDSP6_ARCH__", "4");
}
- }
- else if(CPU == "hexagonv5") {
+ } else if (CPU == "hexagonv5") {
Builder.defineMacro("__HEXAGON_V5__");
Builder.defineMacro("__HEXAGON_ARCH__", "5");
if(Opts.HexagonQdsp6Compat) {
Builder.defineMacro("__QDSP6_V5__");
Builder.defineMacro("__QDSP6_ARCH__", "5");
}
+ } else if (CPU == "hexagonv60") {
+ Builder.defineMacro("__HEXAGON_V60__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "60");
+ Builder.defineMacro("__QDSP6_V60__");
+ Builder.defineMacro("__QDSP6_ARCH__", "60");
}
}
-const char * const HexagonTargetInfo::GCCRegNames[] = {
+bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ for (auto &F : Features) {
+ if (F == "+hvx")
+ HasHVX = true;
+ else if (F == "-hvx")
+ HasHVX = HasHVXDouble = false;
+ else if (F == "+hvx-double")
+ HasHVX = HasHVXDouble = true;
+ else if (F == "-hvx-double")
+ HasHVXDouble = false;
+ }
+ return true;
+}
+
+bool HexagonTargetInfo::initFeatureMap(llvm::StringMap<bool> &Features,
+ DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ // Default for v60: -hvx, -hvx-double.
+ Features["hvx"] = false;
+ Features["hvx-double"] = false;
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+
+const char *const HexagonTargetInfo::GCCRegNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
@@ -5704,16 +5814,15 @@
"sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp"
};
-ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const {
+ArrayRef<const char*> HexagonTargetInfo::getGCCRegNames() const {
return llvm::makeArrayRef(GCCRegNames);
}
-
const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
{ { "sp" }, "r29" },
{ { "fp" }, "r30" },
{ { "lr" }, "r31" },
- };
+};
ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const {
return llvm::makeArrayRef(GCCRegAliases);
@@ -5839,6 +5948,7 @@
case CK_NIAGARA4:
return CG_V9;
}
+ llvm_unreachable("Unexpected CPU kind");
}
CPUKind getCPUKind(StringRef Name) const {
@@ -5949,8 +6059,10 @@
break;
case CG_V9:
Builder.defineMacro("__sparcv9");
- if (getTriple().getOS() != llvm::Triple::Solaris)
+ if (getTriple().getOS() != llvm::Triple::Solaris) {
Builder.defineMacro("__sparcv9__");
+ Builder.defineMacro("__sparc_v9__");
+ }
break;
}
}
@@ -6498,6 +6610,12 @@
Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
+
+ // These shouldn't be defined for MIPS-I but there's no need to check
+ // for that since MIPS-I isn't supported.
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -6872,6 +6990,8 @@
}
else
llvm_unreachable("Invalid ABI for Mips64.");
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
@@ -7079,6 +7199,8 @@
LargeArrayAlign = 128;
SimdDefaultAlign = 128;
SigAtomicType = SignedLong;
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
}
protected:
@@ -7133,7 +7255,6 @@
clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
BuiltinVaListKind getBuiltinVaListKind() const final {
- // TODO: Implement va_list properly.
return VoidPtrBuiltinVaList;
}
ArrayRef<const char *> getGCCRegNames() const final {
@@ -7178,7 +7299,7 @@
explicit WebAssembly32TargetInfo(const llvm::Triple &T)
: WebAssemblyTargetInfo(T) {
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
- DataLayoutString = "e-p:32:32-i64:64-n32:64-S128";
+ DataLayoutString = "e-m:e-p:32:32-i64:64-n32:64-S128";
}
protected:
@@ -7196,7 +7317,7 @@
LongAlign = LongWidth = 64;
PointerAlign = PointerWidth = 64;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- DataLayoutString = "e-p:64:64-i64:64-n32:64-S128";
+ DataLayoutString = "e-m:e-p:64:64-i64:64-n32:64-S128";
}
protected:
@@ -7731,6 +7852,8 @@
return new RTEMSX86_32TargetInfo(Triple);
case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_32TargetInfo>(Triple);
+ case llvm::Triple::ELFIAMCU:
+ return new MCUX86_32TargetInfo(Triple);
default:
return new X86_32TargetInfo(Triple);
}
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index 3ea61c4..6977f40 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -658,6 +658,23 @@
EC = make_error_code(llvm::errc::not_a_directory);
return directory_iterator(std::make_shared<InMemoryDirIterator>());
}
+
+std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
+ SmallString<128> Path;
+ P.toVector(Path);
+
+ // Fix up relative paths. This just prepends the current working directory.
+ std::error_code EC = makeAbsolute(Path);
+ assert(!EC);
+ (void)EC;
+
+ if (useNormalizedPaths())
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+
+ if (!Path.empty())
+ WorkingDirectory = Path.str();
+ return std::error_code();
+}
}
}
@@ -962,8 +979,7 @@
KeyStatusPair("use-external-name", false),
};
- DenseMap<StringRef, KeyStatus> Keys(
- &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
+ DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
bool HasContents = false; // external or otherwise
std::vector<std::unique_ptr<Entry>> EntryArrayContents;
@@ -1121,8 +1137,7 @@
KeyStatusPair("roots", true),
};
- DenseMap<StringRef, KeyStatus> Keys(
- &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
+ DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
// Parse configuration and 'roots'
for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index b2a65c6..6d746c2 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -22,11 +22,13 @@
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/FunctionInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/FunctionIndexObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/TargetRegistry.h"
@@ -95,7 +97,7 @@
return PerFunctionPasses;
}
- void CreatePasses();
+ void CreatePasses(FunctionInfoIndex *FunctionIndex);
/// Generates the TargetMachine.
/// Returns Null if it is unable to create the target machine.
@@ -113,15 +115,13 @@
bool AddEmitPasses(BackendAction Action, raw_pwrite_stream &OS);
public:
- EmitAssemblyHelper(DiagnosticsEngine &_Diags,
- const CodeGenOptions &CGOpts,
+ EmitAssemblyHelper(DiagnosticsEngine &_Diags, const CodeGenOptions &CGOpts,
const clang::TargetOptions &TOpts,
- const LangOptions &LOpts,
- Module *M)
- : Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
- TheModule(M), CodeGenerationTime("Code Generation Time"),
- CodeGenPasses(nullptr), PerModulePasses(nullptr),
- PerFunctionPasses(nullptr) {}
+ const LangOptions &LOpts, Module *M)
+ : Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
+ TheModule(M), CodeGenerationTime("Code Generation Time"),
+ CodeGenPasses(nullptr), PerModulePasses(nullptr),
+ PerFunctionPasses(nullptr) {}
~EmitAssemblyHelper() {
delete CodeGenPasses;
@@ -194,14 +194,20 @@
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
- PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/false));
- PM.add(createAddressSanitizerModulePass(/*CompileKernel*/false));
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address);
+ PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/false, Recover));
+ PM.add(createAddressSanitizerModulePass(/*CompileKernel*/false, Recover));
}
static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
- PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/true));
- PM.add(createAddressSanitizerModulePass(/*CompileKernel*/true));
+ PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/true,
+ /*Recover*/true));
+ PM.add(createAddressSanitizerModulePass(/*CompileKernel*/true,
+ /*Recover*/true));
}
static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
@@ -242,6 +248,13 @@
TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
TLII->disableAllFunctions();
+ else {
+ // Disable individual libc/libm calls in TargetLibraryInfo.
+ LibFunc::Func F;
+ for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs())
+ if (TLII->getLibFunc(FuncName, F))
+ TLII->setUnavailable(F);
+ }
switch (CodeGenOpts.getVecLib()) {
case CodeGenOptions::Accelerate:
@@ -264,7 +277,7 @@
MPM->add(createRewriteSymbolsPass(DL));
}
-void EmitAssemblyHelper::CreatePasses() {
+void EmitAssemblyHelper::CreatePasses(FunctionInfoIndex *FunctionIndex) {
if (CodeGenOpts.DisableLLVMPasses)
return;
@@ -279,6 +292,29 @@
}
PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
+
+ // Figure out TargetLibraryInfo.
+ Triple TargetTriple(TheModule->getTargetTriple());
+ PMBuilder.LibraryInfo = createTLII(TargetTriple, CodeGenOpts);
+
+ switch (Inlining) {
+ case CodeGenOptions::NoInlining:
+ break;
+ case CodeGenOptions::NormalInlining: {
+ PMBuilder.Inliner =
+ createFunctionInliningPass(OptLevel, CodeGenOpts.OptimizeSize);
+ break;
+ }
+ case CodeGenOptions::OnlyAlwaysInlining:
+ // Respect always_inline.
+ if (OptLevel == 0)
+ // Do not insert lifetime intrinsics at -O0.
+ PMBuilder.Inliner = createAlwaysInlinerPass(false);
+ else
+ PMBuilder.Inliner = createAlwaysInlinerPass();
+ break;
+ }
+
PMBuilder.OptLevel = OptLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB;
@@ -291,6 +327,16 @@
PMBuilder.PrepareForLTO = CodeGenOpts.PrepareForLTO;
PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
+ legacy::PassManager *MPM = getPerModulePasses();
+
+ // If we are performing a ThinLTO importing compile, invoke the LTO
+ // pipeline and pass down the in-memory function index.
+ if (FunctionIndex) {
+ PMBuilder.FunctionIndex = FunctionIndex;
+ PMBuilder.populateLTOPassManager(*MPM);
+ return;
+ }
+
PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
addAddDiscriminatorsPass);
@@ -355,27 +401,6 @@
addDataFlowSanitizerPass);
}
- // Figure out TargetLibraryInfo.
- Triple TargetTriple(TheModule->getTargetTriple());
- PMBuilder.LibraryInfo = createTLII(TargetTriple, CodeGenOpts);
-
- switch (Inlining) {
- case CodeGenOptions::NoInlining: break;
- case CodeGenOptions::NormalInlining: {
- PMBuilder.Inliner =
- createFunctionInliningPass(OptLevel, CodeGenOpts.OptimizeSize);
- break;
- }
- case CodeGenOptions::OnlyAlwaysInlining:
- // Respect always_inline.
- if (OptLevel == 0)
- // Do not insert lifetime intrinsics at -O0.
- PMBuilder.Inliner = createAlwaysInlinerPass(false);
- else
- PMBuilder.Inliner = createAlwaysInlinerPass();
- break;
- }
-
// Set up the per-function pass manager.
legacy::FunctionPassManager *FPM = getPerFunctionPasses();
if (CodeGenOpts.VerifyModule)
@@ -383,7 +408,6 @@
PMBuilder.populateFunctionPassManager(*FPM);
// Set up the per-module pass manager.
- legacy::PassManager *MPM = getPerModulePasses();
if (!CodeGenOpts.RewriteMapFiles.empty())
addSymbolRewriterPass(CodeGenOpts, MPM);
@@ -534,11 +558,26 @@
Options.DataSections = CodeGenOpts.DataSections;
Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
+ switch (CodeGenOpts.getDebuggerTuning()) {
+ case CodeGenOptions::DebuggerKindGDB:
+ Options.DebuggerTuning = llvm::DebuggerKind::GDB;
+ break;
+ case CodeGenOptions::DebuggerKindLLDB:
+ Options.DebuggerTuning = llvm::DebuggerKind::LLDB;
+ break;
+ case CodeGenOptions::DebuggerKindSCE:
+ Options.DebuggerTuning = llvm::DebuggerKind::SCE;
+ break;
+ default:
+ break;
+ }
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
+ Options.MCOptions.MCIncrementalLinkerCompatible =
+ CodeGenOpts.IncrementalLinkerCompatible;
Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
Options.MCOptions.ABIName = TargetOpts.ABI;
@@ -601,7 +640,28 @@
return;
if (TM)
TheModule->setDataLayout(TM->createDataLayout());
- CreatePasses();
+
+ // If we are performing a ThinLTO importing compile, load the function
+ // index into memory and pass it into CreatePasses, which will add it
+ // to the PassManagerBuilder and invoke LTO passes.
+ std::unique_ptr<FunctionInfoIndex> FunctionIndex;
+ if (!CodeGenOpts.ThinLTOIndexFile.empty()) {
+ ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
+ llvm::getFunctionIndexForFile(CodeGenOpts.ThinLTOIndexFile,
+ [&](const DiagnosticInfo &DI) {
+ TheModule->getContext().diagnose(DI);
+ });
+ if (std::error_code EC = IndexOrErr.getError()) {
+ std::string Error = EC.message();
+ errs() << "Error loading index file '" << CodeGenOpts.ThinLTOIndexFile
+ << "': " << Error << "\n";
+ return;
+ }
+ FunctionIndex = std::move(IndexOrErr.get());
+ assert(FunctionIndex && "Expected non-empty function index");
+ }
+
+ CreatePasses(FunctionIndex.get());
switch (Action) {
case Backend_EmitNothing:
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 0025b13..1ef5d10 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -79,7 +79,7 @@
auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment());
AtomicSizeInBits = C.toBits(
C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1)
- .RoundUpToAlignment(lvalue.getAlignment()));
+ .alignTo(lvalue.getAlignment()));
auto VoidPtrAddr = CGF.EmitCastToVoidPtr(lvalue.getBitFieldPointer());
auto OffsetInChars =
(C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) *
@@ -613,8 +613,8 @@
break;
case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
+ PostOp = llvm::Instruction::And; // the NOT is special cased below
+ // Fall through.
case AtomicExpr::AO__atomic_fetch_nand:
Op = llvm::AtomicRMWInst::Nand;
break;
@@ -853,6 +853,7 @@
MemTy->isPointerType() ? getContext().getIntPtrType() : MemTy;
QualType RetTy;
bool HaveRetTy = false;
+ llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
llvm_unreachable("Already handled!");
@@ -906,84 +907,71 @@
case AtomicExpr::AO__atomic_load_n:
LibCallName = "__atomic_load";
break;
+ // T __atomic_add_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_add_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_add_fetch:
+ PostOp = llvm::Instruction::Add;
+ // Fall through.
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
LibCallName = "__atomic_fetch_add";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
LoweredMemTy, E->getExprLoc(), sizeChars);
break;
+ // T __atomic_and_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_and_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_and_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_and:
LibCallName = "__atomic_fetch_and";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
+ // T __atomic_or_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_or_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_or_fetch:
+ PostOp = llvm::Instruction::Or;
+ // Fall through.
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_or:
LibCallName = "__atomic_fetch_or";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
+ // T __atomic_sub_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_sub_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_sub_fetch:
+ PostOp = llvm::Instruction::Sub;
+ // Fall through.
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
LibCallName = "__atomic_fetch_sub";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
LoweredMemTy, E->getExprLoc(), sizeChars);
break;
+ // T __atomic_xor_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_xor_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_xor_fetch:
+ PostOp = llvm::Instruction::Xor;
+ // Fall through.
case AtomicExpr::AO__c11_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_xor:
LibCallName = "__atomic_fetch_xor";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
+ // T __atomic_nand_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_nand_N(T *mem, T val, int order)
+ case AtomicExpr::AO__atomic_nand_fetch:
+ PostOp = llvm::Instruction::And; // the NOT is special cased below
+ // Fall through.
case AtomicExpr::AO__atomic_fetch_nand:
LibCallName = "__atomic_fetch_nand";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
-
- // T __atomic_add_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_add_fetch:
- LibCallName = "__atomic_add_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_and_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_and_fetch:
- LibCallName = "__atomic_and_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_or_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_or_fetch:
- LibCallName = "__atomic_or_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_sub_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_sub_fetch:
- LibCallName = "__atomic_sub_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- LoweredMemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_xor_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_xor_fetch:
- LibCallName = "__atomic_xor_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
- // T __atomic_nand_fetch_N(T *mem, T val, int order)
- case AtomicExpr::AO__atomic_nand_fetch:
- LibCallName = "__atomic_nand_fetch";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
- MemTy, E->getExprLoc(), sizeChars);
- break;
}
// Optimized functions have the size in their name.
@@ -1007,6 +995,11 @@
Args.add(RValue::get(Order),
getContext().IntTy);
+ // PostOp is only needed for the atomic_*_fetch operations, and
+ // thus is only needed for and implemented in the
+ // UseOptimizedLibcall codepath.
+ assert(UseOptimizedLibcall || !PostOp);
+
RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
// The value is returned directly from the libcall.
if (E->isCmpXChg())
@@ -1016,6 +1009,13 @@
// provided an out-param.
if (UseOptimizedLibcall && Res.getScalarVal()) {
llvm::Value *ResVal = Res.getScalarVal();
+ if (PostOp) {
+ llvm::Value *LoadVal1 = Args[1].RV.getScalarVal();
+ ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1);
+ }
+ if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
+ ResVal = Builder.CreateNot(ResVal);
+
Builder.CreateStore(
ResVal,
Builder.CreateBitCast(Dest, ResVal->getType()->getPointerTo()));
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 18e766d..742a523 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -399,9 +399,15 @@
// Block pointers require copy/dispose. So do Objective-C pointers.
} else if (variable->getType()->isObjCRetainableType()) {
- info.NeedsCopyDispose = true;
- // used for mrr below.
- lifetime = Qualifiers::OCL_Strong;
+ // But honor the inert __unsafe_unretained qualifier, which doesn't
+ // actually make it into the type system.
+ if (variable->getType()->isObjCInertUnsafeUnretainedType()) {
+ lifetime = Qualifiers::OCL_ExplicitNone;
+ } else {
+ info.NeedsCopyDispose = true;
+ // used for mrr below.
+ lifetime = Qualifiers::OCL_Strong;
+ }
// So do types that require non-trivial copy construction.
} else if (CI.hasCopyExpr()) {
@@ -502,7 +508,7 @@
// At this point, we just have to add padding if the end align still
// isn't aligned right.
if (endAlign < maxFieldAlign) {
- CharUnits newBlockSize = blockSize.RoundUpToAlignment(maxFieldAlign);
+ CharUnits newBlockSize = blockSize.alignTo(maxFieldAlign);
CharUnits padding = newBlockSize - blockSize;
// If we haven't yet added any fields, remember that there was an
@@ -1235,7 +1241,7 @@
if (IsLambdaConversionToBlock)
EmitLambdaBlockInvokeBody();
else {
- PGO.assignRegionCounters(blockDecl, fn);
+ PGO.assignRegionCounters(GlobalDecl(blockDecl), fn);
incrementProfileCounter(blockDecl->getBody());
EmitStmt(blockDecl->getBody());
}
@@ -2102,7 +2108,7 @@
bool packed = false;
CharUnits varAlign = getContext().getDeclAlign(D);
- CharUnits varOffset = size.RoundUpToAlignment(varAlign);
+ CharUnits varOffset = size.alignTo(varAlign);
// We may have to insert padding.
if (varOffset != size) {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index e2bd9fc..787ac53 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -21,7 +21,6 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
@@ -343,65 +342,69 @@
return Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue);
}
-// Returns true if we have a valid set of target features.
-bool CodeGenFunction::checkBuiltinTargetFeatures(
- const FunctionDecl *TargetDecl) {
- // Early exit if this is an indirect call.
- if (!TargetDecl)
- return true;
+/// Checks if using the result of __builtin_object_size(p, @p From) in place of
+/// __builtin_object_size(p, @p To) is correct
+static bool areBOSTypesCompatible(int From, int To) {
+ // Note: Our __builtin_object_size implementation currently treats Type=0 and
+ // Type=2 identically. Encoding this implementation detail here may make
+ // improving __builtin_object_size difficult in the future, so it's omitted.
+ return From == To || (From == 0 && To == 1) || (From == 3 && To == 2);
+}
- // Get the current enclosing function if it exists. If it doesn't
- // we can't check the target features anyhow.
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl);
- if (!FD) return true;
+static llvm::Value *
+getDefaultBuiltinObjectSizeResult(unsigned Type, llvm::IntegerType *ResType) {
+ return ConstantInt::get(ResType, (Type & 2) ? 0 : -1, /*isSigned=*/true);
+}
- unsigned BuiltinID = TargetDecl->getBuiltinID();
- const char *FeatureList =
- CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
+llvm::Value *
+CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+ uint64_t ObjectSize;
+ if (!E->tryEvaluateObjectSize(ObjectSize, getContext(), Type))
+ return emitBuiltinObjectSize(E, Type, ResType);
+ return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
+}
- if (!FeatureList || StringRef(FeatureList) == "")
- return true;
+/// Returns a Value corresponding to the size of the given expression.
+/// This Value may be either of the following:
+/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
+/// it)
+/// - A call to the @llvm.objectsize intrinsic
+llvm::Value *
+CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType) {
+ // We need to reference an argument if the pointer is a parameter with the
+ // pass_object_size attribute.
+ if (auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
+ auto *Param = dyn_cast<ParmVarDecl>(D->getDecl());
+ auto *PS = D->getDecl()->getAttr<PassObjectSizeAttr>();
+ if (Param != nullptr && PS != nullptr &&
+ areBOSTypesCompatible(PS->getType(), Type)) {
+ auto Iter = SizeArguments.find(Param);
+ assert(Iter != SizeArguments.end());
- StringRef TargetCPU = Target.getTargetOpts().CPU;
- llvm::StringMap<bool> FeatureMap;
+ const ImplicitParamDecl *D = Iter->second;
+ auto DIter = LocalDeclMap.find(D);
+ assert(DIter != LocalDeclMap.end());
- if (const auto *TD = FD->getAttr<TargetAttr>()) {
- // If we have a TargetAttr build up the feature map based on that.
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
-
- // Make a copy of the features as passed on the command line into the
- // beginning of the additional features from the function to override.
- ParsedAttr.first.insert(ParsedAttr.first.begin(),
- Target.getTargetOpts().FeaturesAsWritten.begin(),
- Target.getTargetOpts().FeaturesAsWritten.end());
-
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
-
- // Now populate the feature map, first with the TargetCPU which is either
- // the default or a new one from the target attribute string. Then we'll use
- // the passed in features (FeaturesAsWritten) along with the new ones from
- // the attribute.
- Target.initFeatureMap(FeatureMap, CGM.getDiags(), TargetCPU,
- ParsedAttr.first);
- } else {
- Target.initFeatureMap(FeatureMap, CGM.getDiags(), TargetCPU,
- Target.getTargetOpts().Features);
+ return EmitLoadOfScalar(DIter->second, /*volatile=*/false,
+ getContext().getSizeType(), E->getLocStart());
+ }
}
- // If we have at least one of the features in the feature list return
- // true, otherwise return false.
- SmallVector<StringRef, 1> AttrFeatures;
- StringRef(FeatureList).split(AttrFeatures, ",");
- return std::all_of(AttrFeatures.begin(), AttrFeatures.end(),
- [&](StringRef &Feature) {
- SmallVector<StringRef, 1> OrFeatures;
- Feature.split(OrFeatures, "|");
- return std::any_of(OrFeatures.begin(), OrFeatures.end(),
- [&](StringRef &Feature) {
- return FeatureMap[Feature];
- });
- });
+ // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
+ // evaluate E for side-effects. In either case, we shouldn't lower to
+ // @llvm.objectsize.
+ if (Type == 3 || E->HasSideEffects(getContext()))
+ return getDefaultBuiltinObjectSizeResult(Type, ResType);
+
+ // LLVM only supports 0 and 2, make sure that we pass along that
+ // as a boolean.
+ auto *CI = ConstantInt::get(Builder.getInt1Ty(), (Type & 2) >> 1);
+ // FIXME: Get right address space.
+ llvm::Type *Tys[] = {ResType, Builder.getInt8PtrTy(0)};
+ Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
+ return Builder.CreateCall(F, {EmitScalarExpr(E), CI});
}
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
@@ -648,26 +651,13 @@
return RValue::get(Builder.CreateCall(F, ArgValue));
}
case Builtin::BI__builtin_object_size: {
- // We rely on constant folding to deal with expressions with side effects.
- assert(!E->getArg(0)->HasSideEffects(getContext()) &&
- "should have been constant folded");
+ unsigned Type =
+ E->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
+ auto *ResType = cast<llvm::IntegerType>(ConvertType(E->getType()));
- // We pass this builtin onto the optimizer so that it can
- // figure out the object size in more complex cases.
- llvm::Type *ResType = ConvertType(E->getType());
-
- // LLVM only supports 0 and 2, make sure that we pass along that
- // as a boolean.
- Value *Ty = EmitScalarExpr(E->getArg(1));
- ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
- assert(CI);
- uint64_t val = CI->getZExtValue();
- CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
- // FIXME: Get right address space.
- llvm::Type *Tys[] = { ResType, Builder.getInt8PtrTy(0) };
- Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
- return RValue::get(
- Builder.CreateCall(F, {EmitScalarExpr(E->getArg(0)), CI}));
+ // We pass this builtin onto the optimizer so that it can figure out the
+ // object size in more complex cases.
+ return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType));
}
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
@@ -1992,10 +1982,7 @@
// This is down here to avoid non-target specific builtins, however, if
// generic builtins start to require generic target features then we
// can move this up to the beginning of the function.
- if (!checkBuiltinTargetFeatures(FD))
- CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature)
- << FD->getDeclName()
- << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
+ checkTargetFeatures(E, FD);
// See if we have a target specific intrinsic.
const char *Name = getContext().BuiltinInfo.getName(BuiltinID);
@@ -2249,29 +2236,32 @@
namespace {
struct NeonIntrinsicInfo {
+ const char *NameHint;
unsigned BuiltinID;
unsigned LLVMIntrinsic;
unsigned AltLLVMIntrinsic;
- const char *NameHint;
unsigned TypeModifier;
bool operator<(unsigned RHSBuiltinID) const {
return BuiltinID < RHSBuiltinID;
}
+ bool operator<(const NeonIntrinsicInfo &TE) const {
+ return BuiltinID < TE.BuiltinID;
+ }
};
} // end anonymous namespace
#define NEONMAP0(NameBase) \
- { NEON::BI__builtin_neon_ ## NameBase, 0, 0, #NameBase, 0 }
+ { #NameBase, NEON::BI__builtin_neon_ ## NameBase, 0, 0, 0 }
#define NEONMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
- { NEON:: BI__builtin_neon_ ## NameBase, \
- Intrinsic::LLVMIntrinsic, 0, #NameBase, TypeModifier }
+ { #NameBase, NEON:: BI__builtin_neon_ ## NameBase, \
+ Intrinsic::LLVMIntrinsic, 0, TypeModifier }
#define NEONMAP2(NameBase, LLVMIntrinsic, AltLLVMIntrinsic, TypeModifier) \
- { NEON:: BI__builtin_neon_ ## NameBase, \
+ { #NameBase, NEON:: BI__builtin_neon_ ## NameBase, \
Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \
- #NameBase, TypeModifier }
+ TypeModifier }
static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP2(vabd_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
@@ -2816,9 +2806,7 @@
#ifndef NDEBUG
if (!MapProvenSorted) {
- // FIXME: use std::is_sorted once C++11 is allowed
- for (unsigned i = 0; i < IntrinsicMap.size() - 1; ++i)
- assert(IntrinsicMap[i].BuiltinID <= IntrinsicMap[i + 1].BuiltinID);
+ assert(std::is_sorted(std::begin(IntrinsicMap), std::end(IntrinsicMap)));
MapProvenSorted = true;
}
#endif
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 045e19b..9dd7928 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -259,6 +259,8 @@
TheModule, FatbinWrapperTy, true, llvm::GlobalValue::InternalLinkage,
llvm::ConstantStruct::get(FatbinWrapperTy, Values),
"__cuda_fatbin_wrapper");
+ // NVIDIA's cuobjdump looks for fatbins in this section.
+ FatbinWrapper->setSection(".nvFatBinSegment");
// GpuBinaryHandle = __cudaRegisterFatBinary(&FatbinWrapper);
llvm::CallInst *RegisterFatbinCall = CtorBuilder.CreateCall(
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index ea32e38..6847df9 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -131,11 +131,6 @@
if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
- // Don't create a weak alias for a dllexport'd symbol.
- if (AliasDecl.getDecl()->hasAttr<DLLExportAttr>() &&
- llvm::GlobalValue::isWeakForLinker(Linkage))
- return true;
-
llvm::GlobalValue::LinkageTypes TargetLinkage =
getFunctionLinkage(TargetDecl);
@@ -173,6 +168,16 @@
return false;
}
+ // If we have a weak, non-discardable alias (weak, weak_odr), like an extern
+ // template instantiation or a dllexported class, avoid forming it on COFF.
+ // A COFF weak external alias cannot satisfy a normal undefined symbol
+ // reference from another TU. The other TU must also mark the referenced
+ // symbol as weak, which we cannot rely on.
+ if (llvm::GlobalValue::isWeakForLinker(Linkage) &&
+ getTriple().isOSBinFormatCOFF()) {
+ return true;
+ }
+
if (!InEveryTU) {
// If we don't have a definition for the destructor yet, don't
// emit. We can't emit aliases to declarations; that's just not
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 078b98d..e4da447 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -85,7 +85,7 @@
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT));
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
return llvm::Constant::getNullValue(FTy->getPointerTo());
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 7667361..3f240b1 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -538,11 +538,9 @@
/// thread_local variables, a list of functions to perform the
/// initialization.
virtual void EmitThreadLocalInitFuncs(
- CodeGenModule &CGM,
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
- CXXThreadLocals,
+ CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) = 0;
+ ArrayRef<const VarDecl *> CXXThreadLocalInitVars) = 0;
// Determine if references to thread_local global variables can be made
// directly or require access through a thread wrapper function.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 99a0932..715e8e7 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -15,6 +15,7 @@
#include "CGCall.h"
#include "ABIInfo.h"
#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
@@ -92,15 +93,41 @@
FTNP->getExtInfo(), RequiredArgs(0));
}
+/// Adds the formal paramaters in FPT to the given prefix. If any parameter in
+/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
+static void appendParameterTypes(const CodeGenTypes &CGT,
+ SmallVectorImpl<CanQualType> &prefix,
+ const CanQual<FunctionProtoType> &FPT,
+ const FunctionDecl *FD) {
+ // Fast path: unknown target.
+ if (FD == nullptr) {
+ prefix.append(FPT->param_type_begin(), FPT->param_type_end());
+ return;
+ }
+
+ // In the vast majority cases, we'll have precisely FPT->getNumParams()
+ // parameters; the only thing that can change this is the presence of
+ // pass_object_size. So, we preallocate for the common case.
+ prefix.reserve(prefix.size() + FPT->getNumParams());
+
+ assert(FD->getNumParams() == FPT->getNumParams());
+ for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
+ prefix.push_back(FPT->getParamType(I));
+ if (FD->getParamDecl(I)->hasAttr<PassObjectSizeAttr>())
+ prefix.push_back(CGT.getContext().getSizeType());
+ }
+}
+
/// Arrange the LLVM function layout for a value of the given function
/// type, on top of any implicit parameters already stored.
static const CGFunctionInfo &
arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
SmallVectorImpl<CanQualType> &prefix,
- CanQual<FunctionProtoType> FTP) {
+ CanQual<FunctionProtoType> FTP,
+ const FunctionDecl *FD) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size());
// FIXME: Kill copy.
- prefix.append(FTP->param_type_begin(), FTP->param_type_end());
+ appendParameterTypes(CGT, prefix, FTP, FD);
CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
/*chainCall=*/false, prefix,
@@ -110,10 +137,11 @@
/// Arrange the argument and result information for a value of the
/// given freestanding function type.
const CGFunctionInfo &
-CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP) {
+CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP,
+ const FunctionDecl *FD) {
SmallVector<CanQualType, 16> argTypes;
return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
- FTP);
+ FTP, FD);
}
static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
@@ -156,7 +184,8 @@
/// constructor or destructor.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP) {
+ const FunctionProtoType *FTP,
+ const CXXMethodDecl *MD) {
SmallVector<CanQualType, 16> argTypes;
// Add the 'this' pointer.
@@ -167,7 +196,7 @@
return ::arrangeLLVMFunctionInfo(
*this, true, argTypes,
- FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
+ FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(), MD);
}
/// Arrange the argument and result information for a declaration or
@@ -184,10 +213,10 @@
if (MD->isInstance()) {
// The abstract case is perfectly fine.
const CXXRecordDecl *ThisType = TheCXXABI.getThisArgumentTypeForMethod(MD);
- return arrangeCXXMethodType(ThisType, prototype.getTypePtr());
+ return arrangeCXXMethodType(ThisType, prototype.getTypePtr(), MD);
}
- return arrangeFreeFunctionType(prototype);
+ return arrangeFreeFunctionType(prototype, MD);
}
const CGFunctionInfo &
@@ -208,7 +237,7 @@
CanQual<FunctionProtoType> FTP = GetFormalType(MD);
// Add the formal parameters.
- argTypes.append(FTP->param_type_begin(), FTP->param_type_end());
+ appendParameterTypes(*this, argTypes, FTP, MD);
TheCXXABI.buildStructorSignature(MD, Type, argTypes);
@@ -274,7 +303,7 @@
}
assert(isa<FunctionProtoType>(FTy));
- return arrangeFreeFunctionType(FTy.getAs<FunctionProtoType>());
+ return arrangeFreeFunctionType(FTy.getAs<FunctionProtoType>(), FD);
}
/// Arrange the argument and result information for the declaration or
@@ -1391,11 +1420,20 @@
return GetFunctionType(*Info);
}
-void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
- const Decl *TargetDecl,
- AttributeListType &PAL,
- unsigned &CallingConv,
- bool AttrOnCallSite) {
+static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
+ llvm::AttrBuilder &FuncAttrs,
+ const FunctionProtoType *FPT) {
+ if (!FPT)
+ return;
+
+ if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
+ FPT->isNothrow(Ctx))
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+}
+
+void CodeGenModule::ConstructAttributeList(
+ StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
+ AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
bool HasOptnone = false;
@@ -1405,6 +1443,13 @@
if (FI.isNoReturn())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ // If we have information about the function prototype, we can learn
+ // attributes form there.
+ AddAttributesFromFunctionProtoType(getContext(), FuncAttrs,
+ CalleeInfo.getCalleeFunctionProtoType());
+
+ const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
+
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
@@ -1417,10 +1462,8 @@
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
- const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
- if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
- FPT->isNothrow(getContext()))
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ AddAttributesFromFunctionProtoType(
+ getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
// Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
// These attributes are not inherited by overloads.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
@@ -1465,7 +1508,8 @@
if (AttrOnCallSite) {
// Attributes that should go on the call site only.
- if (!CodeGenOpts.SimplifyLibCalls)
+ if (!CodeGenOpts.SimplifyLibCalls ||
+ CodeGenOpts.isNoBuiltinFunc(Name.data()))
FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
if (!CodeGenOpts.TrapFuncName.empty())
FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
@@ -1481,8 +1525,12 @@
FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
}
+ bool DisableTailCalls =
+ CodeGenOpts.DisableTailCalls ||
+ (TargetDecl && TargetDecl->hasAttr<DisableTailCallsAttr>());
FuncAttrs.addAttribute("disable-tail-calls",
- llvm::toStringRef(CodeGenOpts.DisableTailCalls));
+ llvm::toStringRef(DisableTailCalls));
+
FuncAttrs.addAttribute("less-precise-fpmad",
llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
FuncAttrs.addAttribute("no-infs-fp-math",
@@ -1506,24 +1554,7 @@
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
if (FD && FD->hasAttr<TargetAttr>()) {
llvm::StringMap<bool> FeatureMap;
- const auto *TD = FD->getAttr<TargetAttr>();
- TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
-
- // Make a copy of the features as passed on the command line into the
- // beginning of the additional features from the function to override.
- ParsedAttr.first.insert(
- ParsedAttr.first.begin(),
- getTarget().getTargetOpts().FeaturesAsWritten.begin(),
- getTarget().getTargetOpts().FeaturesAsWritten.end());
-
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
-
- // Now populate the feature map, first with the TargetCPU which is either
- // the default or a new one from the target attribute string. Then we'll
- // use the passed in features (FeaturesAsWritten) along with the new ones
- // from the attribute.
- getTarget().initFeatureMap(FeatureMap, Diags, TargetCPU, ParsedAttr.first);
+ getFunctionFeatureMap(FeatureMap, FD);
// Produce the canonical string for this set of features.
std::vector<std::string> Features;
@@ -1533,6 +1564,13 @@
Features.push_back((it->second ? "+" : "-") + it->first().str());
// Now add the target-cpu and target-features to the function.
+ // While we populated the feature map above, we still need to
+ // get and parse the target attribute so we can get the cpu for
+ // the function.
+ const auto *TD = FD->getAttr<TargetAttr>();
+ TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
+ if (ParsedAttr.second != "")
+ TargetCPU = ParsedAttr.second;
if (TargetCPU != "")
FuncAttrs.addAttribute("target-cpu", TargetCPU);
if (!Features.empty()) {
@@ -2793,6 +2831,21 @@
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
const FunctionDecl *CalleeDecl, unsigned ParamsToSkip) {
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
+
+ auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg) {
+ if (CalleeDecl == nullptr || I >= CalleeDecl->getNumParams())
+ return;
+ auto *PS = CalleeDecl->getParamDecl(I)->getAttr<PassObjectSizeAttr>();
+ if (PS == nullptr)
+ return;
+
+ const auto &Context = getContext();
+ auto SizeTy = Context.getSizeType();
+ auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
+ llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T);
+ Args.add(RValue::get(V), SizeTy);
+ };
+
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
// because arguments are destroyed left to right in the callee.
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
@@ -2813,6 +2866,7 @@
EmitCallArg(Args, *Arg, ArgTypes[I]);
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
CalleeDecl, ParamsToSkip + I);
+ MaybeEmitImplicitObjectSize(I, *Arg);
}
// Un-reverse the arguments we just evaluated so they match up with the LLVM
@@ -2827,6 +2881,7 @@
EmitCallArg(Args, *Arg, ArgTypes[I]);
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
CalleeDecl, ParamsToSkip + I);
+ MaybeEmitImplicitObjectSize(I, *Arg);
}
}
@@ -2991,8 +3046,7 @@
return EmitRuntimeCall(callee, None, name);
}
-/// Emits a simple call (never an invoke) to the given runtime
-/// function.
+/// Emits a simple call (never an invoke) to the given runtime function.
llvm::CallInst *
CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
ArrayRef<llvm::Value*> args,
@@ -3002,27 +3056,48 @@
return call;
}
+// Calls which may throw must have operand bundles indicating which funclet
+// they are nested within.
+static void
+getBundlesForFunclet(llvm::Value *Callee, llvm::Instruction *CurrentFuncletPad,
+ SmallVectorImpl<llvm::OperandBundleDef> &BundleList) {
+ // There is no need for a funclet operand bundle if we aren't inside a
+ // funclet.
+ if (!CurrentFuncletPad)
+ return;
+
+ // Skip intrinsics which cannot throw.
+ auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts());
+ if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow())
+ return;
+
+ BundleList.emplace_back("funclet", CurrentFuncletPad);
+}
+
/// Emits a call or invoke to the given noreturn runtime function.
void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
ArrayRef<llvm::Value*> args) {
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
+ getBundlesForFunclet(callee, CurrentFuncletPad, BundleList);
+
if (getInvokeDest()) {
llvm::InvokeInst *invoke =
Builder.CreateInvoke(callee,
getUnreachableBlock(),
getInvokeDest(),
- args);
+ args,
+ BundleList);
invoke->setDoesNotReturn();
invoke->setCallingConv(getRuntimeCC());
} else {
- llvm::CallInst *call = Builder.CreateCall(callee, args);
+ llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList);
call->setDoesNotReturn();
call->setCallingConv(getRuntimeCC());
Builder.CreateUnreachable();
}
}
-/// Emits a call or invoke instruction to the given nullary runtime
-/// function.
+/// Emits a call or invoke instruction to the given nullary runtime function.
llvm::CallSite
CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
const Twine &name) {
@@ -3083,7 +3158,7 @@
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
- const Decl *TargetDecl,
+ CGCalleeInfo CalleeInfo,
llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
@@ -3412,23 +3487,38 @@
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList,
- CallingConv, true);
+ CGM.ConstructAttributeList(Callee->getName(), CallInfo, CalleeInfo,
+ AttributeList, CallingConv,
+ /*AttrOnCallSite=*/true);
llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
AttributeList);
- llvm::BasicBlock *InvokeDest = nullptr;
- if (!Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind) ||
- currentFunctionUsesSEHTry())
- InvokeDest = getInvokeDest();
+ bool CannotThrow;
+ if (currentFunctionUsesSEHTry()) {
+ // SEH cares about asynchronous exceptions, everything can "throw."
+ CannotThrow = false;
+ } else if (isCleanupPadScope() &&
+ EHPersonality::get(*this).isMSVCXXPersonality()) {
+ // The MSVC++ personality will implicitly terminate the program if an
+ // exception is thrown. An unwind edge cannot be reached.
+ CannotThrow = true;
+ } else {
+ // Otherwise, nowunind callsites will never throw.
+ CannotThrow = Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind);
+ }
+ llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest();
+
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
+ getBundlesForFunclet(Callee, CurrentFuncletPad, BundleList);
llvm::CallSite CS;
if (!InvokeDest) {
- CS = Builder.CreateCall(Callee, IRCallArgs);
+ CS = Builder.CreateCall(Callee, IRCallArgs, BundleList);
} else {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, IRCallArgs);
+ CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, IRCallArgs,
+ BundleList);
EmitBlock(Cont);
}
if (callOrInvoke)
@@ -3440,14 +3530,8 @@
Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
llvm::Attribute::AlwaysInline);
- // Disable inlining inside SEH __try blocks and cleanup funclets. None of the
- // funclet EH personalities that clang supports have tables that are
- // expressive enough to describe catching an exception inside a cleanup.
- // __CxxFrameHandler3, for example, will terminate the program without
- // catching it.
- // FIXME: Move this decision to the LLVM inliner. Before we can do that, the
- // inliner needs to know if a given call site is part of a cleanuppad.
- if (isSEHTryScope() || isCleanupPadScope())
+ // Disable inlining inside SEH __try blocks.
+ if (isSEHTryScope())
Attrs =
Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline);
@@ -3493,9 +3577,11 @@
// lexical order, so deactivate it and run it manually here.
CallArgs.freeArgumentMemory(*this);
- if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI))
+ if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
+ const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
+ }
RValue Ret = [&] {
switch (RetAI.getKind()) {
@@ -3568,6 +3654,8 @@
llvm_unreachable("Unhandled ABIArgInfo::Kind");
} ();
+ const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
+
if (Ret.isScalar() && TargetDecl) {
if (const auto *AA = TargetDecl->getAttr<AssumeAlignedAttr>()) {
llvm::Value *OffsetValue = nullptr;
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 77ec7f2..d55b73a 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -26,6 +26,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/Transforms/Utils/SanitizerStats.h"
using namespace clang;
using namespace CodeGen;
@@ -2551,16 +2552,39 @@
return;
SanitizerScope SanScope(this);
+ llvm::SanitizerStatKind SSK;
+ switch (TCK) {
+ case CFITCK_VCall:
+ SSK = llvm::SanStat_CFI_VCall;
+ break;
+ case CFITCK_NVCall:
+ SSK = llvm::SanStat_CFI_NVCall;
+ break;
+ case CFITCK_DerivedCast:
+ SSK = llvm::SanStat_CFI_DerivedCast;
+ break;
+ case CFITCK_UnrelatedCast:
+ SSK = llvm::SanStat_CFI_UnrelatedCast;
+ break;
+ }
+ EmitSanitizerStatReport(SSK);
- llvm::Value *BitSetName = llvm::MetadataAsValue::get(
- getLLVMContext(),
- CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)));
+ llvm::Metadata *MD =
+ CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
+ llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
llvm::Value *BitSetTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
{CastedVTable, BitSetName});
+ if (CGM.getCodeGenOpts().SanitizeCfiCrossDso) {
+ if (auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD)) {
+ EmitCfiSlowPathCheck(BitSetTest, TypeId, CastedVTable);
+ return;
+ }
+ }
+
SanitizerMask M;
switch (TCK) {
case CFITCK_VCall:
@@ -2578,9 +2602,9 @@
}
llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
- llvm::ConstantInt::get(Int8Ty, TCK),
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
+ llvm::ConstantInt::get(Int8Ty, TCK),
};
EmitCheck(std::make_pair(BitSetTest, M), "cfi_bad_type", StaticData,
CastedVTable);
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 5b6e497..2678b33 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -112,7 +112,7 @@
/// Push an entry of the given size onto this protected-scope stack.
char *EHScopeStack::allocate(size_t Size) {
- Size = llvm::RoundUpToAlignment(Size, ScopeStackAlignment);
+ Size = llvm::alignTo(Size, ScopeStackAlignment);
if (!StartOfBuffer) {
unsigned Capacity = 1024;
while (Capacity < Size) Capacity *= 2;
@@ -143,7 +143,7 @@
}
void EHScopeStack::deallocate(size_t Size) {
- StartOfData += llvm::RoundUpToAlignment(Size, ScopeStackAlignment);
+ StartOfData += llvm::alignTo(Size, ScopeStackAlignment);
}
bool EHScopeStack::containsOnlyLifetimeMarkers(
@@ -246,13 +246,6 @@
InnermostEHScope = stable_begin();
}
-void EHScopeStack::pushPadEnd(llvm::BasicBlock *PadEndBB) {
- char *Buffer = allocate(EHPadEndScope::getSize());
- auto *CES = new (Buffer) EHPadEndScope(InnermostEHScope);
- CES->setCachedEHDispatchBlock(PadEndBB);
- InnermostEHScope = stable_begin();
-}
-
/// Remove any 'null' fixups on the stack. However, we can't pop more
/// fixups than the fixup depth on the innermost normal cleanup, or
/// else fixups that we try to add to that cleanup will end up in the
@@ -683,13 +676,25 @@
return;
}
- // Copy the cleanup emission data out. Note that SmallVector
- // guarantees maximal alignment for its buffer regardless of its
- // type parameter.
+ // Copy the cleanup emission data out. This uses either a stack
+ // array or malloc'd memory, depending on the size, which is
+ // behavior that SmallVector would provide, if we could use it
+ // here. Unfortunately, if you ask for a SmallVector<char>, the
+ // alignment isn't sufficient.
auto *CleanupSource = reinterpret_cast<char *>(Scope.getCleanupBuffer());
- SmallVector<char, 8 * sizeof(void *)> CleanupBuffer(
- CleanupSource, CleanupSource + Scope.getCleanupSize());
- auto *Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBuffer.data());
+ llvm::AlignedCharArray<EHScopeStack::ScopeStackAlignment, 8 * sizeof(void *)> CleanupBufferStack;
+ std::unique_ptr<char[]> CleanupBufferHeap;
+ size_t CleanupSize = Scope.getCleanupSize();
+ EHScopeStack::Cleanup *Fn;
+
+ if (CleanupSize <= sizeof(CleanupBufferStack)) {
+ memcpy(CleanupBufferStack.buffer, CleanupSource, CleanupSize);
+ Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferStack.buffer);
+ } else {
+ CleanupBufferHeap.reset(new char[CleanupSize]);
+ memcpy(CleanupBufferHeap.get(), CleanupSource, CleanupSize);
+ Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferHeap.get());
+ }
EHScopeStack::Cleanup::Flags cleanupFlags;
if (Scope.isNormalCleanup())
@@ -909,24 +914,17 @@
// throwing cleanups. For funclet EH personalities, the cleanupendpad models
// program termination when cleanups throw.
bool PushedTerminate = false;
- SaveAndRestore<bool> RestoreIsCleanupPadScope(IsCleanupPadScope);
+ SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
+ CurrentFuncletPad);
llvm::CleanupPadInst *CPI = nullptr;
- llvm::BasicBlock *CleanupEndBB = nullptr;
if (!EHPersonality::get(*this).usesFuncletPads()) {
EHStack.pushTerminate();
PushedTerminate = true;
} else {
- CPI = Builder.CreateCleanupPad({});
-
- // Build a cleanupendpad to unwind through. Our insertion point should be
- // in the cleanuppad block.
- CleanupEndBB = createBasicBlock("ehcleanup.end");
- CGBuilderTy(*this, CleanupEndBB).CreateCleanupEndPad(CPI, NextAction);
- EHStack.pushPadEnd(CleanupEndBB);
-
- // Mark that we're inside a cleanuppad to block inlining.
- // FIXME: Remove this once the inliner knows when it's safe to do so.
- IsCleanupPadScope = true;
+ llvm::Value *ParentPad = CurrentFuncletPad;
+ if (!ParentPad)
+ ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
+ CurrentFuncletPad = CPI = Builder.CreateCleanupPad(ParentPad);
}
// We only actually emit the cleanup code if the cleanup is either
@@ -941,17 +939,6 @@
else
Builder.CreateBr(NextAction);
- // Insert the cleanupendpad block here, if it has any uses.
- if (CleanupEndBB) {
- EHStack.popPadEnd();
- if (CleanupEndBB->hasNUsesOrMore(1)) {
- CurFn->getBasicBlockList().insertAfter(
- Builder.GetInsertBlock()->getIterator(), CleanupEndBB);
- } else {
- delete CleanupEndBB;
- }
- }
-
// Leave the terminate scope.
if (PushedTerminate)
EHStack.popTerminate();
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index 5a0145e..4823773 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -540,7 +540,7 @@
Size = EHPadEndScope::getSize();
break;
}
- Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment);
+ Ptr += llvm::alignTo(Size, ScopeStackAlignment);
return *this;
}
@@ -587,14 +587,6 @@
deallocate(EHTerminateScope::getSize());
}
-inline void EHScopeStack::popPadEnd() {
- assert(!empty() && "popping exception stack when not empty");
-
- EHPadEndScope &scope = cast<EHPadEndScope>(*begin());
- InnermostEHScope = scope.getEnclosingEHScope();
- deallocate(EHPadEndScope::getSize());
-}
-
inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
assert(sp.isValid() && "finding invalid savepoint");
assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 30a184c..675b5eb 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -183,22 +183,31 @@
IdentifierInfo *FII = FD->getIdentifier();
FunctionTemplateSpecializationInfo *Info =
FD->getTemplateSpecializationInfo();
- if (!Info && FII)
+
+ if (!Info && FII && !CGM.getCodeGenOpts().EmitCodeView)
return FII->getName();
// Otherwise construct human readable name for debug info.
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
- FD->printName(OS);
+ PrintingPolicy Policy(CGM.getLangOpts());
- // Add any template specialization args.
- if (Info) {
- const TemplateArgumentList *TArgs = Info->TemplateArguments;
- const TemplateArgument *Args = TArgs->data();
- unsigned NumArgs = TArgs->size();
- PrintingPolicy Policy(CGM.getLangOpts());
- TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
- Policy);
+ if (CGM.getCodeGenOpts().EmitCodeView) {
+ // Print a fully qualified name like MSVC would.
+ Policy.MSVCFormatting = true;
+ FD->printQualifiedName(OS, Policy);
+ } else {
+ // Print the unqualified name with some template arguments. This is what
+ // DWARF-based debuggers expect.
+ FD->printName(OS);
+ // Add any template specialization args.
+ if (Info) {
+ const TemplateArgumentList *TArgs = Info->TemplateArguments;
+ const TemplateArgument *Args = TArgs->data();
+ unsigned NumArgs = TArgs->size();
+ TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
+ Policy);
+ }
}
// Copy this name on the side and use its reference.
@@ -712,10 +721,6 @@
const Type *Ty,
QualType PointeeTy,
llvm::DIFile *Unit) {
- if (Tag == llvm::dwarf::DW_TAG_reference_type ||
- Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
- return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit));
-
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
@@ -723,8 +728,13 @@
uint64_t Size = CGM.getTarget().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
- Align);
+ if (Tag == llvm::dwarf::DW_TAG_reference_type ||
+ Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
+ return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit),
+ Size, Align);
+ else
+ return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
+ Align);
}
llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
@@ -1526,8 +1536,9 @@
const RecordDecl *RD,
const LangOptions &LangOpts) {
// Does the type exist in an imported clang module?
- if (DebugTypeExtRefs && RD->isFromASTFile() && RD->getDefinition())
- return true;
+ if (DebugTypeExtRefs && RD->isFromASTFile() && RD->getDefinition() &&
+ (RD->isExternallyVisible() || !RD->getName().empty()))
+ return true;
if (DebugKind > CodeGenOptions::LimitedDebugInfo)
return false;
@@ -1729,11 +1740,14 @@
bool IsRootModule = M ? !M->Parent : true;
if (CreateSkeletonCU && IsRootModule) {
+ // PCH files don't have a signature field in the control block,
+ // but LLVM detects skeleton CUs by looking for a non-zero DWO id.
+ uint64_t Signature = Mod.getSignature() ? Mod.getSignature() : ~1ULL;
llvm::DIBuilder DIB(CGM.getModule());
DIB.createCompileUnit(TheCU->getSourceLanguage(), Mod.getModuleName(),
Mod.getPath(), TheCU->getProducer(), true,
StringRef(), 0, Mod.getASTFile(),
- llvm::DIBuilder::FullDebug, Mod.getSignature());
+ llvm::DIBuilder::FullDebug, Signature);
DIB.finalize();
}
llvm::DIModule *Parent =
@@ -1790,7 +1804,7 @@
}
// Create entries for all of the properties.
- for (const auto *PD : ID->properties()) {
+ auto AddProperty = [&](const ObjCPropertyDecl *PD) {
SourceLocation Loc = PD->getLocation();
llvm::DIFile *PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
@@ -1804,6 +1818,21 @@
: getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
EltTys.push_back(PropertyNode);
+ };
+ {
+ llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
+ for (const ObjCCategoryDecl *ClassExt : ID->known_extensions())
+ for (auto *PD : ClassExt->properties()) {
+ PropertySet.insert(PD->getIdentifier());
+ AddProperty(PD);
+ }
+ for (const auto *PD : ID->properties()) {
+ // Don't emit duplicate metadata for properties that were already in a
+ // class extension.
+ if (!PropertySet.insert(PD->getIdentifier()).second)
+ continue;
+ AddProperty(PD);
+ }
}
const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
@@ -2000,6 +2029,11 @@
return getOrCreateType(Ty->getValueType(), U);
}
+llvm::DIType* CGDebugInfo::CreateType(const PipeType *Ty,
+ llvm::DIFile *U) {
+ return getOrCreateType(Ty->getElementType(), U);
+}
+
llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
const EnumDecl *ED = Ty->getDecl();
@@ -2190,8 +2224,12 @@
// option.
FullSourceLoc Loc(D->getLocation(), CGM.getContext().getSourceManager());
if (Module *M = ClangModuleMap->inferModuleFromLocation(Loc)) {
+ // This is a (sub-)module.
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);
+ } else {
+ // This the precompiled header being built.
+ return getOrCreateModuleRef(PCHDescriptor, /*SkeletonCU=*/false);
}
}
@@ -2259,6 +2297,9 @@
case Type::Atomic:
return CreateType(cast<AtomicType>(Ty), Unit);
+ case Type::Pipe:
+ return CreateType(cast<PipeType>(Ty), Unit);
+
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
@@ -2863,8 +2904,7 @@
CGM.getTarget().getPointerAlign(0))) {
CharUnits FieldOffsetInBytes =
CGM.getContext().toCharUnitsFromBits(FieldOffset);
- CharUnits AlignedOffsetInBytes =
- FieldOffsetInBytes.RoundUpToAlignment(Align);
+ CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align);
CharUnits NumPaddingBytes = AlignedOffsetInBytes - FieldOffsetInBytes;
if (NumPaddingBytes.isPositive()) {
@@ -3328,7 +3368,7 @@
// variable for each member of the anonymous union so that it's possible
// to find the name of any field in the union.
if (T->isUnionType() && DeclName.empty()) {
- const RecordDecl *RD = cast<RecordType>(T)->getDecl();
+ const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
assert(RD->isAnonymousStructOrUnion() &&
"unnamed non-anonymous struct or union?");
GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
@@ -3392,10 +3432,14 @@
void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
return;
- DBuilder.createImportedModule(
- getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
- getOrCreateNameSpace(UD.getNominatedNamespace()),
- getLineNumber(UD.getLocation()));
+ const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
+ if (!NSDecl->isAnonymousNamespace() ||
+ CGM.getCodeGenOpts().DebugExplicitImport) {
+ DBuilder.createImportedModule(
+ getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
+ getOrCreateNameSpace(NSDecl),
+ getLineNumber(UD.getLocation()));
+ }
}
void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
@@ -3414,11 +3458,13 @@
}
void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
- auto Info = ExternalASTSource::ASTSourceDescriptor(*ID.getImportedModule());
- DBuilder.createImportedDeclaration(
- getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
- getOrCreateModuleRef(Info, DebugTypeExtRefs),
- getLineNumber(ID.getLocation()));
+ if (Module *M = ID.getImportedModule()) {
+ auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
+ DBuilder.createImportedDeclaration(
+ getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
+ getOrCreateModuleRef(Info, DebugTypeExtRefs),
+ getLineNumber(ID.getLocation()));
+ }
}
llvm::DIImportedEntity *
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 7e7ba74..55d8138 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -16,6 +16,7 @@
#include "CGBuilder.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -57,6 +58,7 @@
llvm::DIBuilder DBuilder;
llvm::DICompileUnit *TheCU = nullptr;
ModuleMap *ClangModuleMap = nullptr;
+ ExternalASTSource::ASTSourceDescriptor PCHDescriptor;
SourceLocation CurLoc;
llvm::DIType *VTablePtrType = nullptr;
llvm::DIType *ClassTy = nullptr;
@@ -168,6 +170,7 @@
llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit);
llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
+ llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
/// Get enumeration type.
llvm::DIType *CreateEnumType(const EnumType *Ty);
llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
@@ -274,6 +277,8 @@
void finalize();
+ /// Module debugging: Support for building PCMs.
+ /// @{
/// Set the main CU's DwoId field to \p Signature.
void setDwoId(uint64_t Signature);
@@ -282,6 +287,14 @@
/// the module of origin of each Decl.
void setModuleMap(ModuleMap &MMap) { ClangModuleMap = &MMap; }
+ /// When generating debug information for a clang module or
+ /// precompiled header, this module map will be used to determine
+ /// the module of origin of each Decl.
+ void setPCHDescriptor(ExternalASTSource::ASTSourceDescriptor PCH) {
+ PCHDescriptor = PCH;
+ }
+ /// @}
+
/// Update the current source location. If \arg loc is invalid it is
/// ignored.
void setLocation(SourceLocation Loc);
@@ -574,7 +587,7 @@
/// passing an empty SourceLocation to \a CGDebugInfo::setLocation()
/// will result in the last valid location being reused. Note that
/// all instructions that do not have a location at the beginning of
- /// a function are counted towards to funciton prologue.
+ /// a function are counted towards to function prologue.
static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF) {
return ApplyDebugLocation(CGF, true, SourceLocation());
}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 35c7dfb..cdf8f61 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -600,12 +600,15 @@
static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
const LValue &destLV, const Expr *init) {
+ bool needsCast = false;
+
while (auto castExpr = dyn_cast<CastExpr>(init->IgnoreParens())) {
switch (castExpr->getCastKind()) {
// Look through casts that don't require representation changes.
case CK_NoOp:
case CK_BitCast:
case CK_BlockPointerToObjCPointerCast:
+ needsCast = true;
break;
// If we find an l-value to r-value cast from a __weak variable,
@@ -618,12 +621,19 @@
// Emit the source l-value.
LValue srcLV = CGF.EmitLValue(srcExpr);
+ // Handle a formal type change to avoid asserting.
+ auto srcAddr = srcLV.getAddress();
+ if (needsCast) {
+ srcAddr = CGF.Builder.CreateElementBitCast(srcAddr,
+ destLV.getAddress().getElementType());
+ }
+
// If it was an l-value, use objc_copyWeak.
if (srcExpr->getValueKind() == VK_LValue) {
- CGF.EmitARCCopyWeak(destLV.getAddress(), srcLV.getAddress());
+ CGF.EmitARCCopyWeak(destLV.getAddress(), srcAddr);
} else {
assert(srcExpr->getValueKind() == VK_XValue);
- CGF.EmitARCMoveWeak(destLV.getAddress(), srcLV.getAddress());
+ CGF.EmitARCMoveWeak(destLV.getAddress(), srcAddr);
}
return true;
}
@@ -705,8 +715,7 @@
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
- // nothing to do
- value = EmitScalarExpr(init);
+ value = EmitARCUnsafeUnretainedScalarExpr(init);
break;
case Qualifiers::OCL_Strong: {
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index e74467b..adba731 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -337,7 +337,7 @@
// FIXME: We only need to register one __cxa_thread_atexit function for the
// entire TU.
CXXThreadLocalInits.push_back(Fn);
- CXXThreadLocalInitVars.push_back(Addr);
+ CXXThreadLocalInitVars.push_back(D);
} else if (PerformInit && ISA) {
EmitPointerToInitFunc(D, Addr, Fn, ISA);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
@@ -518,14 +518,14 @@
llvm::Value *GuardVal = Builder.CreateLoad(Guard);
llvm::Value *Uninit = Builder.CreateIsNull(GuardVal,
"guard.uninitialized");
- // Mark as initialized before initializing anything else. If the
- // initializers use previously-initialized thread_local vars, that's
- // probably supposed to be OK, but the standard doesn't say.
- Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
llvm::BasicBlock *InitBlock = createBasicBlock("init");
ExitBlock = createBasicBlock("exit");
Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
EmitBlock(InitBlock);
+ // Mark as initialized before initializing anything else. If the
+ // initializers use previously-initialized thread_local vars, that's
+ // probably supposed to be OK, but the standard doesn't say.
+ Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
}
RunCleanupsScope Scope(*this);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index eaa7610..fce2e75 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -871,58 +871,50 @@
return lpad;
}
-static llvm::BasicBlock *emitCatchPadBlock(CodeGenFunction &CGF,
- EHCatchScope &CatchScope) {
+static void emitCatchPadBlock(CodeGenFunction &CGF, EHCatchScope &CatchScope) {
llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();
assert(DispatchBlock);
CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP();
CGF.EmitBlockAfterUses(DispatchBlock);
- // Figure out the next block.
- llvm::BasicBlock *NextBlock = nullptr;
+ llvm::Value *ParentPad = CGF.CurrentFuncletPad;
+ if (!ParentPad)
+ ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext());
+ llvm::BasicBlock *UnwindBB =
+ CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope());
+
+ unsigned NumHandlers = CatchScope.getNumHandlers();
+ llvm::CatchSwitchInst *CatchSwitch =
+ CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers);
// Test against each of the exception types we claim to catch.
- for (unsigned I = 0, E = CatchScope.getNumHandlers(); I < E; ++I) {
+ for (unsigned I = 0; I < NumHandlers; ++I) {
const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);
CatchTypeInfo TypeInfo = Handler.Type;
if (!TypeInfo.RTTI)
TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);
- // If this is the last handler, we're at the end, and the next
- // block is the block for the enclosing EH scope.
- if (I + 1 == E) {
- NextBlock = CGF.createBasicBlock("catchendblock");
- CGBuilderTy(CGF, NextBlock).CreateCatchEndPad(
- CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope()));
- } else {
- NextBlock = CGF.createBasicBlock("catch.dispatch");
- }
+ CGF.Builder.SetInsertPoint(Handler.Block);
if (EHPersonality::get(CGF).isMSVCXXPersonality()) {
- CGF.Builder.CreateCatchPad(Handler.Block, NextBlock,
- {TypeInfo.RTTI,
- CGF.Builder.getInt32(TypeInfo.Flags),
- llvm::Constant::getNullValue(CGF.VoidPtrTy)});
+ CGF.Builder.CreateCatchPad(
+ CatchSwitch, {TypeInfo.RTTI, CGF.Builder.getInt32(TypeInfo.Flags),
+ llvm::Constant::getNullValue(CGF.VoidPtrTy)});
} else {
- CGF.Builder.CreateCatchPad(Handler.Block, NextBlock, {TypeInfo.RTTI});
+ CGF.Builder.CreateCatchPad(CatchSwitch, {TypeInfo.RTTI});
}
- // Otherwise we need to emit and continue at that block.
- CGF.EmitBlock(NextBlock);
+ CatchSwitch->addHandler(Handler.Block);
}
CGF.Builder.restoreIP(SavedIP);
-
- return NextBlock;
}
/// Emit the structure of the dispatch block for the given catch scope.
/// It is an invariant that the dispatch block already exists.
-/// If the catchblock instructions are used for EH dispatch, then the basic
-/// block holding the final catchendblock instruction is returned.
-static llvm::BasicBlock *emitCatchDispatchBlock(CodeGenFunction &CGF,
- EHCatchScope &catchScope) {
+static void emitCatchDispatchBlock(CodeGenFunction &CGF,
+ EHCatchScope &catchScope) {
if (EHPersonality::get(CGF).usesFuncletPads())
return emitCatchPadBlock(CGF, catchScope);
@@ -934,7 +926,7 @@
if (catchScope.getNumHandlers() == 1 &&
catchScope.getHandler(0).isCatchAll()) {
assert(dispatchBlock == catchScope.getHandler(0).Block);
- return nullptr;
+ return;
}
CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP();
@@ -992,12 +984,11 @@
// If the next handler is a catch-all, we're completely done.
if (nextIsEnd) {
CGF.Builder.restoreIP(savedIP);
- return nullptr;
+ return;
}
// Otherwise we need to emit and continue at that block.
CGF.EmitBlock(nextBlock);
}
- return nullptr;
}
void CodeGenFunction::popCatchScope() {
@@ -1020,7 +1011,7 @@
}
// Emit the structure of the EH dispatch for this catch.
- llvm::BasicBlock *CatchEndBlockBB = emitCatchDispatchBlock(*this, CatchScope);
+ emitCatchDispatchBlock(*this, CatchScope);
// Copy the handler blocks off before we pop the EH stack. Emitting
// the handlers might scribble on this memory.
@@ -1043,9 +1034,6 @@
doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
isa<CXXConstructorDecl>(CurCodeDecl);
- if (CatchEndBlockBB)
- EHStack.pushPadEnd(CatchEndBlockBB);
-
// Perversely, we emit the handlers backwards precisely because we
// want them to appear in source order. In all of these cases, the
// catch block will have exactly one predecessor, which will be a
@@ -1065,6 +1053,8 @@
RunCleanupsScope CatchScope(*this);
// Initialize the catch variable and set up the cleanups.
+ SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
+ CurrentFuncletPad);
CGM.getCXXABI().emitBeginCatch(*this, C);
// Emit the PGO counter increment.
@@ -1098,8 +1088,6 @@
EmitBlock(ContBB);
incrementProfileCounter(&S);
- if (CatchEndBlockBB)
- EHStack.popPadEnd();
}
namespace {
@@ -1337,17 +1325,20 @@
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
+ llvm::Value *Exn = nullptr;
if (EHPersonality::get(*this).usesFuncletPads()) {
- Builder.CreateTerminatePad(/*UnwindBB=*/nullptr, CGM.getTerminateFn());
+ llvm::Value *ParentPad = CurrentFuncletPad;
+ if (!ParentPad)
+ ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
+ Builder.CreateCleanupPad(ParentPad);
} else {
- llvm::Value *Exn = nullptr;
if (getLangOpts().CPlusPlus)
Exn = getExceptionFromSlot();
- llvm::CallInst *terminateCall =
- CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
- terminateCall->setDoesNotReturn();
- Builder.CreateUnreachable();
}
+ llvm::CallInst *terminateCall =
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
+ terminateCall->setDoesNotReturn();
+ Builder.CreateUnreachable();
// Restore the saved insertion state.
Builder.restoreIP(SavedIP);
@@ -1502,8 +1493,9 @@
};
} // end anonymous namespace
-Address CodeGenFunction::recoverAddrOfEscapedLocal(
- CodeGenFunction &ParentCGF, Address ParentVar, llvm::Value *ParentFP) {
+Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
+ Address ParentVar,
+ llvm::Value *ParentFP) {
llvm::CallInst *RecoverCall = nullptr;
CGBuilderTy Builder(*this, AllocaInsertPt);
if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar.getPointer())) {
@@ -1557,27 +1549,32 @@
return;
}
- llvm::Value *EntryEBP = nullptr;
- llvm::Value *ParentFP;
+ llvm::Value *EntryFP = nullptr;
+ CGBuilderTy Builder(CGM, AllocaInsertPt);
if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) {
// 32-bit SEH filters need to be careful about FP recovery. The end of the
// EH registration is passed in as the EBP physical register. We can
- // recover that with llvm.frameaddress(1), and adjust that to recover the
- // parent's true frame pointer.
- CGBuilderTy Builder(CGM, AllocaInsertPt);
- EntryEBP = Builder.CreateCall(
+ // recover that with llvm.frameaddress(1).
+ EntryFP = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)});
- llvm::Function *RecoverFPIntrin =
- CGM.getIntrinsic(llvm::Intrinsic::x86_seh_recoverfp);
- llvm::Constant *ParentI8Fn =
- llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
- ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryEBP});
} else {
// Otherwise, for x64 and 32-bit finally functions, the parent FP is the
// second parameter.
auto AI = CurFn->arg_begin();
++AI;
- ParentFP = &*AI;
+ EntryFP = &*AI;
+ }
+
+ llvm::Value *ParentFP = EntryFP;
+ if (IsFilter) {
+ // Given whatever FP the runtime provided us in EntryFP, recover the true
+ // frame pointer of the parent function. We only need to do this in filters,
+ // since finally funclets recover the parent FP for us.
+ llvm::Function *RecoverFPIntrin =
+ CGM.getIntrinsic(llvm::Intrinsic::x86_seh_recoverfp);
+ llvm::Constant *ParentI8Fn =
+ llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
+ ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP});
}
// Create llvm.localrecover calls for all captures.
@@ -1601,8 +1598,8 @@
continue;
Address ParentVar = I->second;
- setAddrOfLocalVar(VD,
- recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP));
+ setAddrOfLocalVar(
+ VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP));
}
if (Finder.SEHCodeSlot.isValid()) {
@@ -1611,7 +1608,7 @@
}
if (IsFilter)
- EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryEBP);
+ EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryFP);
}
/// Arrange a function prototype that can be called by Windows exception
@@ -1727,7 +1724,7 @@
void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
llvm::Value *ParentFP,
- llvm::Value *EntryEBP) {
+ llvm::Value *EntryFP) {
// Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the
// __exception_info intrinsic.
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
@@ -1740,7 +1737,7 @@
// exception registration object. It contains 6 32-bit fields, and the info
// pointer is stored in the second field. So, GEP 20 bytes backwards and
// load the pointer.
- SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryEBP, -20);
+ SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryFP, -20);
SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo());
SEHInfo = Builder.CreateAlignedLoad(Int8PtrTy, SEHInfo, getPointerAlign());
SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal(
@@ -1857,18 +1854,16 @@
emitCatchDispatchBlock(*this, CatchScope);
// Grab the block before we pop the handler.
- llvm::BasicBlock *ExceptBB = CatchScope.getHandler(0).Block;
+ llvm::BasicBlock *CatchPadBB = CatchScope.getHandler(0).Block;
EHStack.popCatch();
- EmitBlockAfterUses(ExceptBB);
+ EmitBlockAfterUses(CatchPadBB);
// __except blocks don't get outlined into funclets, so immediately do a
// catchret.
- llvm::BasicBlock *CatchPadBB = ExceptBB->getSinglePredecessor();
- assert(CatchPadBB && "only ExceptBB pred should be catchpad");
llvm::CatchPadInst *CPI =
cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());
- ExceptBB = createBasicBlock("__except");
+ llvm::BasicBlock *ExceptBB = createBasicBlock("__except");
Builder.CreateCatchRet(CPI, ExceptBB);
EmitBlock(ExceptBB);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index d606fe7..7d1c77a 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -32,6 +32,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Transforms/Utils/SanitizerStats.h"
using namespace clang;
using namespace CodeGen;
@@ -824,7 +825,8 @@
getNaturalPointeeTypeAlignment(E->getType(), Source));
}
- if (SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
+ if (SanOpts.has(SanitizerKind::CFIUnrelatedCast) &&
+ CE->getCastKind() == CK_BitCast) {
if (auto PT = E->getType()->getAs<PointerType>())
EmitVTablePtrCheckForCast(PT->getPointeeType(), Addr.getPointer(),
/*MayBeNull=*/true,
@@ -2532,6 +2534,34 @@
EmitBlock(Cont);
}
+void CodeGenFunction::EmitCfiSlowPathCheck(llvm::Value *Cond,
+ llvm::ConstantInt *TypeId,
+ llvm::Value *Ptr) {
+ auto &Ctx = getLLVMContext();
+ llvm::BasicBlock *Cont = createBasicBlock("cfi.cont");
+
+ llvm::BasicBlock *CheckBB = createBasicBlock("cfi.slowpath");
+ llvm::BranchInst *BI = Builder.CreateCondBr(Cond, Cont, CheckBB);
+
+ llvm::MDBuilder MDHelper(getLLVMContext());
+ llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
+ BI->setMetadata(llvm::LLVMContext::MD_prof, Node);
+
+ EmitBlock(CheckBB);
+
+ llvm::Constant *SlowPathFn = CGM.getModule().getOrInsertFunction(
+ "__cfi_slowpath",
+ llvm::FunctionType::get(
+ llvm::Type::getVoidTy(Ctx),
+ {llvm::Type::getInt64Ty(Ctx),
+ llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(Ctx))},
+ false));
+ llvm::CallInst *CheckCall = Builder.CreateCall(SlowPathFn, {TypeId, Ptr});
+ CheckCall->setDoesNotThrow();
+
+ EmitBlock(Cont);
+}
+
void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
llvm::BasicBlock *Cont = createBasicBlock("cont");
@@ -3337,6 +3367,7 @@
case CK_PointerToBoolean:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
@@ -3741,12 +3772,32 @@
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
const CallExpr *E, ReturnValueSlot ReturnValue,
- const Decl *TargetDecl, llvm::Value *Chain) {
+ CGCalleeInfo CalleeInfo, llvm::Value *Chain) {
// Get the actual function type. The callee type will always be a pointer to
// function type or a block pointer type.
assert(CalleeType->isFunctionPointerType() &&
"Call must have function pointer type!");
+ // Preserve the non-canonical function type because things like exception
+ // specifications disappear in the canonical type. That information is useful
+ // to drive the generation of more accurate code for this call later on.
+ const FunctionProtoType *NonCanonicalFTP = CalleeType->getAs<PointerType>()
+ ->getPointeeType()
+ ->getAs<FunctionProtoType>();
+
+ const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
+
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
+ // We can only guarantee that a function is called from the correct
+ // context/function based on the appropriate target attributes,
+ // so only check in the case where we have both always_inline and target
+ // since otherwise we could be making a conditional call after a check for
+ // the proper cpu features (and it won't cause code generation issues due to
+ // function based code generation).
+ if (TargetDecl->hasAttr<AlwaysInlineAttr>() &&
+ TargetDecl->hasAttr<TargetAttr>())
+ checkTargetFeatures(E, FD);
+
CalleeType = getContext().getCanonicalType(CalleeType);
const auto *FnType =
@@ -3802,22 +3853,27 @@
if (SanOpts.has(SanitizerKind::CFIICall) &&
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
SanitizerScope SanScope(this);
+ EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
- llvm::Value *BitSetName = llvm::MetadataAsValue::get(
- getLLVMContext(),
- CGM.CreateMetadataIdentifierForType(QualType(FnType, 0)));
+ llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
+ llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *CastedCallee = Builder.CreateBitCast(Callee, Int8PtrTy);
llvm::Value *BitSetTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
{CastedCallee, BitSetName});
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(E->getLocStart()),
- EmitCheckTypeDescriptor(QualType(FnType, 0)),
- };
- EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
- "cfi_bad_icall", StaticData, CastedCallee);
+ auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD);
+ if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) {
+ EmitCfiSlowPathCheck(BitSetTest, TypeId, CastedCallee);
+ } else {
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(E->getLocStart()),
+ EmitCheckTypeDescriptor(QualType(FnType, 0)),
+ };
+ EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
+ "cfi_bad_icall", StaticData, CastedCallee);
+ }
}
CallArgList Args;
@@ -3856,7 +3912,8 @@
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
}
- return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl);
+ return EmitCall(FnInfo, Callee, ReturnValue, Args,
+ CGCalleeInfo(NonCanonicalFTP, TargetDecl));
}
LValue CodeGenFunction::
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 20838db..a4547a9 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -721,6 +721,7 @@
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 6565f83..604cde7 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1904,6 +1904,7 @@
"destination type must be a record type!");
Value = CGM.getCXXABI().EmitDynamicCastCall(*this, ThisAddr, SrcRecordTy,
DestTy, DestRecordTy, CastEnd);
+ CastNotNull = Builder.GetInsertBlock();
}
if (ShouldNullCheckSrcValue) {
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 4b45bce..22910d9 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -462,6 +462,7 @@
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
@@ -585,19 +586,25 @@
// We *must* use the full CG function call building logic here because the
// complex type has special ABI handling. We also should not forget about
// special calling convention which may be used for compiler builtins.
- const CGFunctionInfo &FuncInfo =
- CGF.CGM.getTypes().arrangeFreeFunctionCall(
- Op.Ty, Args, FunctionType::ExtInfo(/* No CC here - will be added later */),
- RequiredArgs::All);
+
+ // We create a function qualified type to state that this call does not have
+ // any exceptions.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI = EPI.withExceptionSpec(
+ FunctionProtoType::ExceptionSpecInfo(EST_BasicNoexcept));
+ SmallVector<QualType, 4> ArgsQTys(
+ 4, Op.Ty->castAs<ComplexType>()->getElementType());
+ QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI);
+ const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall(
+ Args, cast<FunctionType>(FQTy.getTypePtr()), false);
+
llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName);
llvm::Instruction *Call;
RValue Res = CGF.EmitCall(FuncInfo, Func, ReturnValueSlot(), Args,
- nullptr, &Call);
+ FQTy->getAs<FunctionProtoType>(), &Call);
cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC());
- cast<llvm::CallInst>(Call)->setDoesNotThrow();
-
return Res.getComplexVal();
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index bbd04dd..2aed3bb 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -111,7 +111,7 @@
// Round up the field offset to the alignment of the field type.
CharUnits AlignedNextFieldOffsetInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
+ NextFieldOffsetInChars.alignTo(FieldAlignment);
if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) {
// We need to append padding.
@@ -121,7 +121,7 @@
"Did not add enough padding!");
AlignedNextFieldOffsetInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
+ NextFieldOffsetInChars.alignTo(FieldAlignment);
}
if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) {
@@ -162,8 +162,8 @@
if (FieldOffset > NextFieldOffsetInBits) {
// We need to add padding.
CharUnits PadSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(FieldOffset - NextFieldOffsetInBits,
- Context.getTargetInfo().getCharAlign()));
+ llvm::alignTo(FieldOffset - NextFieldOffsetInBits,
+ Context.getTargetInfo().getCharAlign()));
AppendPadding(PadSize);
}
@@ -334,7 +334,7 @@
CharUnits ElementAlign = CharUnits::fromQuantity(
CGM.getDataLayout().getABITypeAlignment(C->getType()));
CharUnits AlignedElementOffsetInChars =
- ElementOffsetInChars.RoundUpToAlignment(ElementAlign);
+ ElementOffsetInChars.alignTo(ElementAlign);
if (AlignedElementOffsetInChars > ElementOffsetInChars) {
// We need some padding.
@@ -508,13 +508,12 @@
} else {
// Append tail padding if necessary.
CharUnits LLVMSizeInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+ NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
if (LLVMSizeInChars != LayoutSizeInChars)
AppendTailPadding(LayoutSizeInChars);
- LLVMSizeInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+ LLVMSizeInChars = NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
// Check if we need to convert the struct to a packed struct.
if (NextFieldOffsetInChars <= LayoutSizeInChars &&
@@ -526,8 +525,7 @@
"Converting to packed did not help!");
}
- LLVMSizeInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+ LLVMSizeInChars = NextFieldOffsetInChars.alignTo(LLVMStructAlignment);
assert(LayoutSizeInChars == LLVMSizeInChars &&
"Tail padding mismatch!");
@@ -546,8 +544,9 @@
llvm::Constant *Result = llvm::ConstantStruct::get(STy, Elements);
- assert(NextFieldOffsetInChars.RoundUpToAlignment(getAlignment(Result)) ==
- getSizeInChars(Result) && "Size mismatch!");
+ assert(NextFieldOffsetInChars.alignTo(getAlignment(Result)) ==
+ getSizeInChars(Result) &&
+ "Size mismatch!");
return Result;
}
@@ -735,6 +734,7 @@
case CK_PointerToBoolean:
case CK_NullToPointer:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToPointer:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
@@ -1350,15 +1350,17 @@
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
- SmallVector<llvm::Constant *, 4> Inits;
unsigned NumElts = Value.getVectorLength();
+ SmallVector<llvm::Constant *, 4> Inits(NumElts);
- for (unsigned i = 0; i != NumElts; ++i) {
- const APValue &Elt = Value.getVectorElt(i);
+ for (unsigned I = 0; I != NumElts; ++I) {
+ const APValue &Elt = Value.getVectorElt(I);
if (Elt.isInt())
- Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
+ Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt());
+ else if (Elt.isFloat())
+ Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat());
else
- Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
+ llvm_unreachable("unsupported vector element type");
}
return llvm::ConstantVector::get(Inits);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 59296a3..5b39b5d4 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -523,8 +523,9 @@
#undef HANDLEBINOP
// Comparisons.
- Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc,
- unsigned SICmpOpc, unsigned FCmpOpc);
+ Value *EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc,
+ llvm::CmpInst::Predicate SICmpOpc,
+ llvm::CmpInst::Predicate FCmpOpc);
#define VISITCOMP(CODE, UI, SI, FP) \
Value *VisitBin##CODE(const BinaryOperator *E) { \
return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
@@ -810,14 +811,15 @@
// A scalar can be splatted to an extended vector of the same element type
if (DstType->isExtVectorType() && !SrcType->isVectorType()) {
- // Cast the scalar to element type
- QualType EltTy = DstType->getAs<ExtVectorType>()->getElementType();
- llvm::Value *Elt = EmitScalarConversion(
- Src, SrcType, EltTy, Loc, CGF.getContext().getLangOpts().OpenCL);
+ // Sema should add casts to make sure that the source expression's type is
+ // the same as the vector's element type (sans qualifiers)
+ assert(DstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
+ SrcType.getTypePtr() &&
+ "Splatted expr doesn't match with vector element type?");
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- return Builder.CreateVectorSplat(NumElements, Elt, "splat");
+ return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
// Allow bitcast from vector to integer/fp of the same size.
@@ -1364,8 +1366,9 @@
QualType DestTy = CE->getType();
CastKind Kind = CE->getCastKind();
- if (!DestTy->isVoidType())
- TestAndClearIgnoreResultAssign();
+ // These cases are generally not written to ignore the result of
+ // evaluating their sub-expressions, so we clear this now.
+ bool Ignored = TestAndClearIgnoreResultAssign();
// Since almost all cast kinds apply to scalars, this switch doesn't have
// a default case, so the compiler will warn on a missing case. The cases
@@ -1492,11 +1495,8 @@
return CGF.EmitARCRetainScalarExpr(E);
case CK_ARCConsumeObject:
return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
- case CK_ARCReclaimReturnedObject: {
- llvm::Value *value = Visit(E);
- value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
- return CGF.EmitObjCConsumeObject(E->getType(), value);
- }
+ case CK_ARCReclaimReturnedObject:
+ return CGF.EmitARCReclaimReturnedObject(E, /*allowUnsafe*/ Ignored);
case CK_ARCExtendBlockObject:
return CGF.EmitARCExtendBlockObject(E);
@@ -1540,15 +1540,7 @@
}
case CK_VectorSplat: {
llvm::Type *DstTy = ConvertType(DestTy);
- // Need an IgnoreImpCasts here as by default a boolean will be promoted to
- // an int, which will not perform the sign extension, so if we know we are
- // going to cast to a vector we have to strip the implicit cast off.
- Value *Elt = Visit(const_cast<Expr*>(E->IgnoreImpCasts()));
- Elt = EmitScalarConversion(Elt, E->IgnoreImpCasts()->getType(),
- DestTy->getAs<VectorType>()->getElementType(),
- CE->getExprLoc(),
- CGF.getContext().getLangOpts().OpenCL);
-
+ Value *Elt = Visit(const_cast<Expr*>(E));
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
return Builder.CreateVectorSplat(NumElements, Elt, "splat");
@@ -1560,6 +1552,10 @@
case CK_FloatingCast:
return EmitScalarConversion(Visit(E), E->getType(), DestTy,
CE->getExprLoc());
+ case CK_BooleanToSignedIntegral:
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc(),
+ /*TreatBooleanAsSigned=*/true);
case CK_IntegralToBoolean:
return EmitIntToBoolConversion(Visit(E));
case CK_PointerToBoolean:
@@ -1923,10 +1919,10 @@
llvm::Value* Result = llvm::Constant::getNullValue(ResultType);
QualType CurrentType = E->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
- OffsetOfExpr::OffsetOfNode ON = E->getComponent(i);
+ OffsetOfNode ON = E->getComponent(i);
llvm::Value *Offset = nullptr;
switch (ON.getKind()) {
- case OffsetOfExpr::OffsetOfNode::Array: {
+ case OffsetOfNode::Array: {
// Compute the index
Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex());
llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr);
@@ -1946,7 +1942,7 @@
break;
}
- case OffsetOfExpr::OffsetOfNode::Field: {
+ case OffsetOfNode::Field: {
FieldDecl *MemberDecl = ON.getField();
RecordDecl *RD = CurrentType->getAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
@@ -1972,10 +1968,10 @@
break;
}
- case OffsetOfExpr::OffsetOfNode::Identifier:
+ case OffsetOfNode::Identifier:
llvm_unreachable("dependent __builtin_offsetof");
- case OffsetOfExpr::OffsetOfNode::Base: {
+ case OffsetOfNode::Base: {
if (ON.getBase()->isVirtual()) {
CGF.ErrorUnsupported(E, "virtual base in offsetof");
continue;
@@ -2564,19 +2560,17 @@
return nullptr;
// We have a potentially fusable op. Look for a mul on one of the operands.
- if (llvm::BinaryOperator* LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
- if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) {
- assert(LHSBinOp->getNumUses() == 0 &&
- "Operations with multiple uses shouldn't be contracted.");
+ // Also, make sure that the mul result isn't used directly. In that case,
+ // there's no point creating a muladd operation.
+ if (auto *LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
+ if (LHSBinOp->getOpcode() == llvm::Instruction::FMul &&
+ LHSBinOp->use_empty())
return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub);
- }
- } else if (llvm::BinaryOperator* RHSBinOp =
- dyn_cast<llvm::BinaryOperator>(op.RHS)) {
- if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) {
- assert(RHSBinOp->getNumUses() == 0 &&
- "Operations with multiple uses shouldn't be contracted.");
+ }
+ if (auto *RHSBinOp = dyn_cast<llvm::BinaryOperator>(op.RHS)) {
+ if (RHSBinOp->getOpcode() == llvm::Instruction::FMul &&
+ RHSBinOp->use_empty())
return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false);
- }
}
return nullptr;
@@ -2834,8 +2828,10 @@
}
}
-Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
- unsigned SICmpOpc, unsigned FCmpOpc) {
+Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
+ llvm::CmpInst::Predicate UICmpOpc,
+ llvm::CmpInst::Predicate SICmpOpc,
+ llvm::CmpInst::Predicate FCmpOpc) {
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
@@ -2918,15 +2914,12 @@
}
if (LHS->getType()->isFPOrFPVectorTy()) {
- Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc,
- LHS, RHS, "cmp");
+ Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
} else if (LHSTy->hasSignedIntegerRepresentation()) {
- Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc,
- LHS, RHS, "cmp");
+ Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");
} else {
// Unsigned integers and pointers.
- Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
- LHS, RHS, "cmp");
+ Result = Builder.CreateICmp(UICmpOpc, LHS, RHS, "cmp");
}
// If this is a vector comparison, sign extend the result to the appropriate
@@ -2961,17 +2954,13 @@
Value *ResultR, *ResultI;
if (CETy->isRealFloatingType()) {
- ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
- LHS.first, RHS.first, "cmp.r");
- ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
- LHS.second, RHS.second, "cmp.i");
+ ResultR = Builder.CreateFCmp(FCmpOpc, LHS.first, RHS.first, "cmp.r");
+ ResultI = Builder.CreateFCmp(FCmpOpc, LHS.second, RHS.second, "cmp.i");
} else {
// Complex comparisons can only be equality comparisons. As such, signed
// and unsigned opcodes are the same.
- ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
- LHS.first, RHS.first, "cmp.r");
- ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
- LHS.second, RHS.second, "cmp.i");
+ ResultR = Builder.CreateICmp(UICmpOpc, LHS.first, RHS.first, "cmp.r");
+ ResultI = Builder.CreateICmp(UICmpOpc, LHS.second, RHS.second, "cmp.i");
}
if (E->getOpcode() == BO_EQ) {
@@ -3002,15 +2991,17 @@
std::tie(LHS, RHS) = CGF.EmitARCStoreAutoreleasing(E);
break;
+ case Qualifiers::OCL_ExplicitNone:
+ std::tie(LHS, RHS) = CGF.EmitARCStoreUnsafeUnretained(E, Ignore);
+ break;
+
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
break;
- // No reason to do any of these differently.
case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
// __block variables need to have the rhs evaluated first, plus
// this should improve codegen just a little.
RHS = Visit(E->getRHS());
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 766102e..989d911 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -557,7 +557,7 @@
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
StartObjCMethod(OMD, OMD->getClassInterface());
- PGO.assignRegionCounters(OMD, CurFn);
+ PGO.assignRegionCounters(GlobalDecl(OMD), CurFn);
assert(isa<CompoundStmt>(OMD->getBody()));
incrementProfileCounter(OMD->getBody());
EmitCompoundStmtWithoutScope(*cast<CompoundStmt>(OMD->getBody()));
@@ -949,11 +949,11 @@
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
llvm::Instruction *CallInstruction;
- RValue RV = EmitCall(getTypes().arrangeFreeFunctionCall(propType, args,
- FunctionType::ExtInfo(),
- RequiredArgs::All),
- getPropertyFn, ReturnValueSlot(), args, nullptr,
- &CallInstruction);
+ RValue RV = EmitCall(
+ getTypes().arrangeFreeFunctionCall(
+ propType, args, FunctionType::ExtInfo(), RequiredArgs::All),
+ getPropertyFn, ReturnValueSlot(), args, CGCalleeInfo(),
+ &CallInstruction);
if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
call->setTailCall();
@@ -1980,20 +1980,14 @@
return result;
}
-/// Retain the given object which is the result of a function call.
-/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
-///
-/// Yes, this function name is one character away from a different
-/// call with completely different semantics.
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
// Fetch the void(void) inline asm which marks that we're going to
- // retain the autoreleased return value.
+ // do something with the autoreleased return value.
llvm::InlineAsm *&marker
- = CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
+ = CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
if (!marker) {
StringRef assembly
- = CGM.getTargetCodeGenInfo()
+ = CGF.CGM.getTargetCodeGenInfo()
.getARCRetainAutoreleasedReturnValueMarker();
// If we have an empty assembly string, there's nothing to do.
@@ -2001,9 +1995,9 @@
// Otherwise, at -O0, build an inline asm that we're going to call
// in a moment.
- } else if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::FunctionType *type =
- llvm::FunctionType::get(VoidTy, /*variadic*/false);
+ llvm::FunctionType::get(CGF.VoidTy, /*variadic*/false);
marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
@@ -2012,25 +2006,50 @@
// optimizer to pick up.
} else {
llvm::NamedMDNode *metadata =
- CGM.getModule().getOrInsertNamedMetadata(
+ CGF.CGM.getModule().getOrInsertNamedMetadata(
"clang.arc.retainAutoreleasedReturnValueMarker");
assert(metadata->getNumOperands() <= 1);
if (metadata->getNumOperands() == 0) {
- metadata->addOperand(llvm::MDNode::get(
- getLLVMContext(), llvm::MDString::get(getLLVMContext(), assembly)));
+ auto &ctx = CGF.getLLVMContext();
+ metadata->addOperand(llvm::MDNode::get(ctx,
+ llvm::MDString::get(ctx, assembly)));
}
}
}
// Call the marker asm if we made one, which we do only at -O0.
if (marker)
- Builder.CreateCall(marker);
+ CGF.Builder.CreateCall(marker);
+}
+/// Retain the given object which is the result of a function call.
+/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
+///
+/// Yes, this function name is one character away from a different
+/// call with completely different semantics.
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+ emitAutoreleasedReturnValueMarker(*this);
return emitARCValueOperation(*this, value,
- CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
+ CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
"objc_retainAutoreleasedReturnValue");
}
+/// Claim a possibly-autoreleased return value at +0. This is only
+/// valid to do in contexts which do not rely on the retain to keep
+/// the object valid for for all of its uses; for example, when
+/// the value is ignored, or when it is being assigned to an
+/// __unsafe_unretained variable.
+///
+/// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
+ emitAutoreleasedReturnValueMarker(*this);
+ return emitARCValueOperation(*this, value,
+ CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
+ "objc_unsafeClaimAutoreleasedReturnValue");
+}
+
/// Release the given object.
/// call void \@objc_release(i8* %value)
void CodeGenFunction::EmitARCRelease(llvm::Value *value,
@@ -2446,25 +2465,22 @@
return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
}
-static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
- llvm::Value *value);
+typedef llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ llvm::Value *value)>
+ ValueTransform;
-/// Given that the given expression is some sort of call (which does
-/// not return retained), emit a retain following it.
-static llvm::Value *emitARCRetainCall(CodeGenFunction &CGF, const Expr *e) {
- llvm::Value *value = CGF.EmitScalarExpr(e);
- return emitARCRetainAfterCall(CGF, value);
-}
-
-static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
- llvm::Value *value) {
+/// Insert code immediately after a call.
+static llvm::Value *emitARCOperationAfterCall(CodeGenFunction &CGF,
+ llvm::Value *value,
+ ValueTransform doAfterCall,
+ ValueTransform doFallback) {
if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
// Place the retain immediately following the call.
CGF.Builder.SetInsertPoint(call->getParent(),
++llvm::BasicBlock::iterator(call));
- value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+ value = doAfterCall(CGF, value);
CGF.Builder.restoreIP(ip);
return value;
@@ -2474,7 +2490,7 @@
// Place the retain at the beginning of the normal destination block.
llvm::BasicBlock *BB = invoke->getNormalDest();
CGF.Builder.SetInsertPoint(BB, BB->begin());
- value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+ value = doAfterCall(CGF, value);
CGF.Builder.restoreIP(ip);
return value;
@@ -2483,7 +2499,7 @@
// the operand.
} else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
llvm::Value *operand = bitcast->getOperand(0);
- operand = emitARCRetainAfterCall(CGF, operand);
+ operand = emitARCOperationAfterCall(CGF, operand, doAfterCall, doFallback);
bitcast->setOperand(0, operand);
return bitcast;
@@ -2491,7 +2507,46 @@
} else {
// Retain using the non-block variant: we never need to do a copy
// of a block that's been returned to us.
- return CGF.EmitARCRetainNonBlock(value);
+ return doFallback(CGF, value);
+ }
+}
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), emit a retain following it.
+static llvm::Value *emitARCRetainCallResult(CodeGenFunction &CGF,
+ const Expr *e) {
+ llvm::Value *value = CGF.EmitScalarExpr(e);
+ return emitARCOperationAfterCall(CGF, value,
+ [](CodeGenFunction &CGF, llvm::Value *value) {
+ return CGF.EmitARCRetainAutoreleasedReturnValue(value);
+ },
+ [](CodeGenFunction &CGF, llvm::Value *value) {
+ return CGF.EmitARCRetainNonBlock(value);
+ });
+}
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), perform an unsafeClaim following it.
+static llvm::Value *emitARCUnsafeClaimCallResult(CodeGenFunction &CGF,
+ const Expr *e) {
+ llvm::Value *value = CGF.EmitScalarExpr(e);
+ return emitARCOperationAfterCall(CGF, value,
+ [](CodeGenFunction &CGF, llvm::Value *value) {
+ return CGF.EmitARCUnsafeClaimAutoreleasedReturnValue(value);
+ },
+ [](CodeGenFunction &CGF, llvm::Value *value) {
+ return value;
+ });
+}
+
+llvm::Value *CodeGenFunction::EmitARCReclaimReturnedObject(const Expr *E,
+ bool allowUnsafeClaim) {
+ if (allowUnsafeClaim &&
+ CGM.getLangOpts().ObjCRuntime.hasARCUnsafeClaimAutoreleasedReturnValue()) {
+ return emitARCUnsafeClaimCallResult(*this, E);
+ } else {
+ llvm::Value *value = emitARCRetainCallResult(*this, E);
+ return EmitObjCConsumeObject(E->getType(), value);
}
}
@@ -2531,17 +2586,52 @@
return true;
}
-/// Try to emit a PseudoObjectExpr at +1.
+namespace {
+/// A CRTP base class for emitting expressions of retainable object
+/// pointer type in ARC.
+template <typename Impl, typename Result> class ARCExprEmitter {
+protected:
+ CodeGenFunction &CGF;
+ Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+ ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {}
+
+public:
+ Result visit(const Expr *e);
+ Result visitCastExpr(const CastExpr *e);
+ Result visitPseudoObjectExpr(const PseudoObjectExpr *e);
+ Result visitBinaryOperator(const BinaryOperator *e);
+ Result visitBinAssign(const BinaryOperator *e);
+ Result visitBinAssignUnsafeUnretained(const BinaryOperator *e);
+ Result visitBinAssignAutoreleasing(const BinaryOperator *e);
+ Result visitBinAssignWeak(const BinaryOperator *e);
+ Result visitBinAssignStrong(const BinaryOperator *e);
+
+ // Minimal implementation:
+ // Result visitLValueToRValue(const Expr *e)
+ // Result visitConsumeObject(const Expr *e)
+ // Result visitExtendBlockObject(const Expr *e)
+ // Result visitReclaimReturnedObject(const Expr *e)
+ // Result visitCall(const Expr *e)
+ // Result visitExpr(const Expr *e)
+ //
+ // Result emitBitCast(Result result, llvm::Type *resultType)
+ // llvm::Value *getValueOfResult(Result result)
+};
+}
+
+/// Try to emit a PseudoObjectExpr under special ARC rules.
///
/// This massively duplicates emitPseudoObjectRValue.
-static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
- const PseudoObjectExpr *E) {
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitPseudoObjectExpr(const PseudoObjectExpr *E) {
SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
// Find the result expression.
const Expr *resultExpr = E->getResultExpr();
assert(resultExpr);
- TryEmitResult result;
+ Result result;
for (PseudoObjectExpr::const_semantics_iterator
i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
@@ -2557,8 +2647,9 @@
// expression, try to evaluate the source as +1.
if (ov == resultExpr) {
assert(!OVMA::shouldBindAsLValue(ov));
- result = tryEmitARCRetainScalarExpr(CGF, ov->getSourceExpr());
- opaqueData = OVMA::bind(CGF, ov, RValue::get(result.getPointer()));
+ result = asImpl().visit(ov->getSourceExpr());
+ opaqueData = OVMA::bind(CGF, ov,
+ RValue::get(asImpl().getValueOfResult(result)));
// Otherwise, just bind it.
} else {
@@ -2569,7 +2660,7 @@
// Otherwise, if the expression is the result, evaluate it
// and remember the result.
} else if (semantic == resultExpr) {
- result = tryEmitARCRetainScalarExpr(CGF, semantic);
+ result = asImpl().visit(semantic);
// Otherwise, evaluate the expression in an ignored context.
} else {
@@ -2584,146 +2675,240 @@
return result;
}
-static TryEmitResult
-tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
- // We should *never* see a nested full-expression here, because if
- // we fail to emit at +1, our caller must not retain after we close
- // out the full-expression.
- assert(!isa<ExprWithCleanups>(e));
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) {
+ switch (e->getCastKind()) {
- // The desired result type, if it differs from the type of the
- // ultimate opaque expression.
- llvm::Type *resultType = nullptr;
+ // No-op casts don't change the type, so we just ignore them.
+ case CK_NoOp:
+ return asImpl().visit(e->getSubExpr());
- while (true) {
- e = e->IgnoreParens();
-
- // There's a break at the end of this if-chain; anything
- // that wants to keep looping has to explicitly continue.
- if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
- switch (ce->getCastKind()) {
- // No-op casts don't change the type, so we just ignore them.
- case CK_NoOp:
- e = ce->getSubExpr();
- continue;
-
- case CK_LValueToRValue: {
- TryEmitResult loadResult
- = tryEmitARCRetainLoadOfScalar(CGF, ce->getSubExpr());
- if (resultType) {
- llvm::Value *value = loadResult.getPointer();
- value = CGF.Builder.CreateBitCast(value, resultType);
- loadResult.setPointer(value);
- }
- return loadResult;
- }
-
- // These casts can change the type, so remember that and
- // soldier on. We only need to remember the outermost such
- // cast, though.
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_BitCast:
- if (!resultType)
- resultType = CGF.ConvertType(ce->getType());
- e = ce->getSubExpr();
- assert(e->getType()->hasPointerRepresentation());
- continue;
-
- // For consumptions, just emit the subexpression and thus elide
- // the retain/release pair.
- case CK_ARCConsumeObject: {
- llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
- }
-
- // Block extends are net +0. Naively, we could just recurse on
- // the subexpression, but actually we need to ensure that the
- // value is copied as a block, so there's a little filter here.
- case CK_ARCExtendBlockObject: {
- llvm::Value *result; // will be a +0 value
-
- // If we can't safely assume the sub-expression will produce a
- // block-copied value, emit the sub-expression at +0.
- if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) {
- result = CGF.EmitScalarExpr(ce->getSubExpr());
-
- // Otherwise, try to emit the sub-expression at +1 recursively.
- } else {
- TryEmitResult subresult
- = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr());
- result = subresult.getPointer();
-
- // If that produced a retained value, just use that,
- // possibly casting down.
- if (subresult.getInt()) {
- if (resultType)
- result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
- }
-
- // Otherwise it's +0.
- }
-
- // Retain the object as a block, then cast down.
- result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
- }
-
- // For reclaims, emit the subexpression as a retained call and
- // skip the consumption.
- case CK_ARCReclaimReturnedObject: {
- llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
- }
-
- default:
- break;
- }
-
- // Skip __extension__.
- } else if (const UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
- if (op->getOpcode() == UO_Extension) {
- e = op->getSubExpr();
- continue;
- }
-
- // For calls and message sends, use the retained-call logic.
- // Delegate inits are a special case in that they're the only
- // returns-retained expression that *isn't* surrounded by
- // a consume.
- } else if (isa<CallExpr>(e) ||
- (isa<ObjCMessageExpr>(e) &&
- !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
- llvm::Value *result = emitARCRetainCall(CGF, e);
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
-
- // Look through pseudo-object expressions.
- } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
- TryEmitResult result
- = tryEmitARCRetainPseudoObject(CGF, pseudo);
- if (resultType) {
- llvm::Value *value = result.getPointer();
- value = CGF.Builder.CreateBitCast(value, resultType);
- result.setPointer(value);
- }
- return result;
- }
-
- // Conservatively halt the search at any other expression kind.
- break;
+ // These casts can change the type.
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_BitCast: {
+ llvm::Type *resultType = CGF.ConvertType(e->getType());
+ assert(e->getSubExpr()->getType()->hasPointerRepresentation());
+ Result result = asImpl().visit(e->getSubExpr());
+ return asImpl().emitBitCast(result, resultType);
}
- // We didn't find an obvious production, so emit what we've got and
- // tell the caller that we didn't manage to retain.
- llvm::Value *result = CGF.EmitScalarExpr(e);
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, false);
+ // Handle some casts specially.
+ case CK_LValueToRValue:
+ return asImpl().visitLValueToRValue(e->getSubExpr());
+ case CK_ARCConsumeObject:
+ return asImpl().visitConsumeObject(e->getSubExpr());
+ case CK_ARCExtendBlockObject:
+ return asImpl().visitExtendBlockObject(e->getSubExpr());
+ case CK_ARCReclaimReturnedObject:
+ return asImpl().visitReclaimReturnedObject(e->getSubExpr());
+
+ // Otherwise, use the default logic.
+ default:
+ return asImpl().visitExpr(e);
+ }
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinaryOperator(const BinaryOperator *e) {
+ switch (e->getOpcode()) {
+ case BO_Comma:
+ CGF.EmitIgnoredExpr(e->getLHS());
+ CGF.EnsureInsertPoint();
+ return asImpl().visit(e->getRHS());
+
+ case BO_Assign:
+ return asImpl().visitBinAssign(e);
+
+ default:
+ return asImpl().visitExpr(e);
+ }
+}
+
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visitBinAssign(const BinaryOperator *e) {
+ switch (e->getLHS()->getType().getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return asImpl().visitBinAssignUnsafeUnretained(e);
+
+ case Qualifiers::OCL_Weak:
+ return asImpl().visitBinAssignWeak(e);
+
+ case Qualifiers::OCL_Autoreleasing:
+ return asImpl().visitBinAssignAutoreleasing(e);
+
+ case Qualifiers::OCL_Strong:
+ return asImpl().visitBinAssignStrong(e);
+
+ case Qualifiers::OCL_None:
+ return asImpl().visitExpr(e);
+ }
+ llvm_unreachable("bad ObjC ownership qualifier");
+}
+
+/// The default rule for __unsafe_unretained emits the RHS recursively,
+/// stores into the unsafe variable, and propagates the result outward.
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::
+ visitBinAssignUnsafeUnretained(const BinaryOperator *e) {
+ // Recursively emit the RHS.
+ // For __block safety, do this before emitting the LHS.
+ Result result = asImpl().visit(e->getRHS());
+
+ // Perform the store.
+ LValue lvalue =
+ CGF.EmitCheckedLValue(e->getLHS(), CodeGenFunction::TCK_Store);
+ CGF.EmitStoreThroughLValue(RValue::get(asImpl().getValueOfResult(result)),
+ lvalue);
+
+ return result;
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignAutoreleasing(const BinaryOperator *e) {
+ return asImpl().visitExpr(e);
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignWeak(const BinaryOperator *e) {
+ return asImpl().visitExpr(e);
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignStrong(const BinaryOperator *e) {
+ return asImpl().visitExpr(e);
+}
+
+/// The general expression-emission logic.
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visit(const Expr *e) {
+ // We should *never* see a nested full-expression here, because if
+ // we fail to emit at +1, our caller must not retain after we close
+ // out the full-expression. This isn't as important in the unsafe
+ // emitter.
+ assert(!isa<ExprWithCleanups>(e));
+
+ // Look through parens, __extension__, generic selection, etc.
+ e = e->IgnoreParens();
+
+ // Handle certain kinds of casts.
+ if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
+ return asImpl().visitCastExpr(ce);
+
+ // Handle the comma operator.
+ } else if (auto op = dyn_cast<BinaryOperator>(e)) {
+ return asImpl().visitBinaryOperator(op);
+
+ // TODO: handle conditional operators here
+
+ // For calls and message sends, use the retained-call logic.
+ // Delegate inits are a special case in that they're the only
+ // returns-retained expression that *isn't* surrounded by
+ // a consume.
+ } else if (isa<CallExpr>(e) ||
+ (isa<ObjCMessageExpr>(e) &&
+ !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
+ return asImpl().visitCall(e);
+
+ // Look through pseudo-object expressions.
+ } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+ return asImpl().visitPseudoObjectExpr(pseudo);
+ }
+
+ return asImpl().visitExpr(e);
+}
+
+namespace {
+
+/// An emitter for +1 results.
+struct ARCRetainExprEmitter :
+ public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> {
+
+ ARCRetainExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
+
+ llvm::Value *getValueOfResult(TryEmitResult result) {
+ return result.getPointer();
+ }
+
+ TryEmitResult emitBitCast(TryEmitResult result, llvm::Type *resultType) {
+ llvm::Value *value = result.getPointer();
+ value = CGF.Builder.CreateBitCast(value, resultType);
+ result.setPointer(value);
+ return result;
+ }
+
+ TryEmitResult visitLValueToRValue(const Expr *e) {
+ return tryEmitARCRetainLoadOfScalar(CGF, e);
+ }
+
+ /// For consumptions, just emit the subexpression and thus elide
+ /// the retain/release pair.
+ TryEmitResult visitConsumeObject(const Expr *e) {
+ llvm::Value *result = CGF.EmitScalarExpr(e);
+ return TryEmitResult(result, true);
+ }
+
+ /// Block extends are net +0. Naively, we could just recurse on
+ /// the subexpression, but actually we need to ensure that the
+ /// value is copied as a block, so there's a little filter here.
+ TryEmitResult visitExtendBlockObject(const Expr *e) {
+ llvm::Value *result; // will be a +0 value
+
+ // If we can't safely assume the sub-expression will produce a
+ // block-copied value, emit the sub-expression at +0.
+ if (shouldEmitSeparateBlockRetain(e)) {
+ result = CGF.EmitScalarExpr(e);
+
+ // Otherwise, try to emit the sub-expression at +1 recursively.
+ } else {
+ TryEmitResult subresult = asImpl().visit(e);
+
+ // If that produced a retained value, just use that.
+ if (subresult.getInt()) {
+ return subresult;
+ }
+
+ // Otherwise it's +0.
+ result = subresult.getPointer();
+ }
+
+ // Retain the object as a block.
+ result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
+ return TryEmitResult(result, true);
+ }
+
+ /// For reclaims, emit the subexpression as a retained call and
+ /// skip the consumption.
+ TryEmitResult visitReclaimReturnedObject(const Expr *e) {
+ llvm::Value *result = emitARCRetainCallResult(CGF, e);
+ return TryEmitResult(result, true);
+ }
+
+ /// When we have an undecorated call, retroactively do a claim.
+ TryEmitResult visitCall(const Expr *e) {
+ llvm::Value *result = emitARCRetainCallResult(CGF, e);
+ return TryEmitResult(result, true);
+ }
+
+ // TODO: maybe special-case visitBinAssignWeak?
+
+ TryEmitResult visitExpr(const Expr *e) {
+ // We didn't find an obvious production, so emit what we've got and
+ // tell the caller that we didn't manage to retain.
+ llvm::Value *result = CGF.EmitScalarExpr(e);
+ return TryEmitResult(result, false);
+ }
+};
+}
+
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+ return ARCRetainExprEmitter(CGF).visit(e);
}
static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
@@ -2807,6 +2992,96 @@
return EmitScalarExpr(expr);
}
+namespace {
+
+/// An emitter for assigning into an __unsafe_unretained context.
+struct ARCUnsafeUnretainedExprEmitter :
+ public ARCExprEmitter<ARCUnsafeUnretainedExprEmitter, llvm::Value*> {
+
+ ARCUnsafeUnretainedExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
+
+ llvm::Value *getValueOfResult(llvm::Value *value) {
+ return value;
+ }
+
+ llvm::Value *emitBitCast(llvm::Value *value, llvm::Type *resultType) {
+ return CGF.Builder.CreateBitCast(value, resultType);
+ }
+
+ llvm::Value *visitLValueToRValue(const Expr *e) {
+ return CGF.EmitScalarExpr(e);
+ }
+
+ /// For consumptions, just emit the subexpression and perform the
+ /// consumption like normal.
+ llvm::Value *visitConsumeObject(const Expr *e) {
+ llvm::Value *value = CGF.EmitScalarExpr(e);
+ return CGF.EmitObjCConsumeObject(e->getType(), value);
+ }
+
+ /// No special logic for block extensions. (This probably can't
+ /// actually happen in this emitter, though.)
+ llvm::Value *visitExtendBlockObject(const Expr *e) {
+ return CGF.EmitARCExtendBlockObject(e);
+ }
+
+ /// For reclaims, perform an unsafeClaim if that's enabled.
+ llvm::Value *visitReclaimReturnedObject(const Expr *e) {
+ return CGF.EmitARCReclaimReturnedObject(e, /*unsafe*/ true);
+ }
+
+ /// When we have an undecorated call, just emit it without adding
+ /// the unsafeClaim.
+ llvm::Value *visitCall(const Expr *e) {
+ return CGF.EmitScalarExpr(e);
+ }
+
+ /// Just do normal scalar emission in the default case.
+ llvm::Value *visitExpr(const Expr *e) {
+ return CGF.EmitScalarExpr(e);
+ }
+};
+}
+
+static llvm::Value *emitARCUnsafeUnretainedScalarExpr(CodeGenFunction &CGF,
+ const Expr *e) {
+ return ARCUnsafeUnretainedExprEmitter(CGF).visit(e);
+}
+
+/// EmitARCUnsafeUnretainedScalarExpr - Semantically equivalent to
+/// immediately releasing the resut of EmitARCRetainScalarExpr, but
+/// avoiding any spurious retains, including by performing reclaims
+/// with objc_unsafeClaimAutoreleasedReturnValue.
+llvm::Value *CodeGenFunction::EmitARCUnsafeUnretainedScalarExpr(const Expr *e) {
+ // Look through full-expressions.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ enterFullExpression(cleanups);
+ RunCleanupsScope scope(*this);
+ return emitARCUnsafeUnretainedScalarExpr(*this, cleanups->getSubExpr());
+ }
+
+ return emitARCUnsafeUnretainedScalarExpr(*this, e);
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreUnsafeUnretained(const BinaryOperator *e,
+ bool ignored) {
+ // Evaluate the RHS first. If we're ignoring the result, assume
+ // that we can emit at an unsafe +0.
+ llvm::Value *value;
+ if (ignored) {
+ value = EmitARCUnsafeUnretainedScalarExpr(e->getRHS());
+ } else {
+ value = EmitScalarExpr(e->getRHS());
+ }
+
+ // Emit the LHS and perform the store.
+ LValue lvalue = EmitLValue(e->getLHS());
+ EmitStoreOfScalar(value, lvalue);
+
+ return std::pair<LValue,llvm::Value*>(std::move(lvalue), value);
+}
+
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
bool ignored) {
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index c9588e6..e4074a7 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1328,8 +1328,8 @@
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
- &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
+ CGCalleeInfo(), &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
}
@@ -1441,8 +1441,8 @@
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
- &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
+ CGCalleeInfo(), &call);
call->setMetadata(msgSendMDKind, node);
@@ -1850,7 +1850,7 @@
// Add all of the property methods need adding to the method list and to the
// property metadata list.
- for (auto *property : PD->properties()) {
+ for (auto *property : PD->instance_properties()) {
std::vector<llvm::Constant*> Fields;
Fields.push_back(MakePropertyEncodingString(property, nullptr));
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index cff3a77..fdbc983 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -833,7 +833,7 @@
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
/// DefinedCategoryNames - list of category names in form Class_Category.
- llvm::SetVector<std::string> DefinedCategoryNames;
+ llvm::SmallSetVector<std::string, 16> DefinedCategoryNames;
/// MethodVarTypes - uniqued method type signatures. We have to use
/// a StringMap here because have no other unique reference.
@@ -967,7 +967,8 @@
llvm::Constant *EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
- const ObjCCommonTypesHelper &ObjCTypes);
+ const ObjCCommonTypesHelper &ObjCTypes,
+ bool IsClassProperty);
/// EmitProtocolMethodTypes - Generate the array of extended method type
/// strings. The return value has type Int8PtrPtrTy.
@@ -981,7 +982,8 @@
SmallVectorImpl<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *Proto,
- const ObjCCommonTypesHelper &ObjCTypes);
+ const ObjCCommonTypesHelper &ObjCTypes,
+ bool IsClassProperty);
/// GetProtocolRef - Return a reference to the internal protocol
/// description, creating an empty one if it has not been
@@ -1079,7 +1081,8 @@
/// has type ClassExtensionPtrTy.
llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID,
CharUnits instanceSize,
- bool hasMRCWeakIvars);
+ bool hasMRCWeakIvars,
+ bool isClassProperty);
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
@@ -1949,7 +1952,7 @@
llvm::Instruction *CallSite;
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs,
- nullptr, &CallSite);
+ CGCalleeInfo(), &CallSite);
// Mark the call as noreturn if the method is marked noreturn and the
// receiver cannot be null.
@@ -2642,6 +2645,8 @@
if (const RecordType *record = T->getAs<RecordType>()) {
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
llvm::Constant *Result = getBitmapBlockLayout(true);
+ if (isa<llvm::ConstantInt>(Result))
+ Result = llvm::ConstantExpr::getIntToPtr(Result, CGM.Int8PtrTy);
return Result;
}
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
@@ -2798,6 +2803,7 @@
struct objc_method_description_list *optional_class_methods;
struct objc_property_list *instance_properties;
const char ** extendedMethodTypes;
+ struct objc_property_list *class_properties;
};
*/
llvm::Constant *
@@ -2816,13 +2822,16 @@
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
OptClassMethods),
EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD,
- ObjCTypes),
+ ObjCTypes, false),
EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
- MethodTypesExt, ObjCTypes)};
+ MethodTypesExt, ObjCTypes),
+ EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr,
+ PD, ObjCTypes, true)};
// Return null if no extension bits are used.
if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
- Values[3]->isNullValue() && Values[4]->isNullValue())
+ Values[3]->isNullValue() && Values[4]->isNullValue() &&
+ Values[5]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
llvm::Constant *Init =
@@ -2878,10 +2887,15 @@
SmallVectorImpl<llvm::Constant *> &Properties,
const Decl *Container,
const ObjCProtocolDecl *Proto,
- const ObjCCommonTypesHelper &ObjCTypes) {
+ const ObjCCommonTypesHelper &ObjCTypes,
+ bool IsClassProperty) {
for (const auto *P : Proto->protocols())
- PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes,
+ IsClassProperty);
+
for (const auto *PD : Proto->properties()) {
+ if (IsClassProperty != PD->isClassProperty())
+ continue;
if (!PropertySet.insert(PD->getIdentifier()).second)
continue;
llvm::Constant *Prop[] = {
@@ -2907,25 +2921,44 @@
llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
- const ObjCCommonTypesHelper &ObjCTypes) {
+ const ObjCCommonTypesHelper &ObjCTypes,
+ bool IsClassProperty) {
SmallVector<llvm::Constant *, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
+
+ auto AddProperty = [&](const ObjCPropertyDecl *PD) {
+ llvm::Constant *Prop[] = {GetPropertyName(PD->getIdentifier()),
+ GetPropertyTypeString(PD, Container)};
+ Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
+ };
+ if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
+ for (auto *PD : ClassExt->properties()) {
+ if (IsClassProperty != PD->isClassProperty())
+ continue;
+ PropertySet.insert(PD->getIdentifier());
+ AddProperty(PD);
+ }
+
for (const auto *PD : OCD->properties()) {
- PropertySet.insert(PD->getIdentifier());
- llvm::Constant *Prop[] = {
- GetPropertyName(PD->getIdentifier()),
- GetPropertyTypeString(PD, Container)
- };
- Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
- Prop));
+ if (IsClassProperty != PD->isClassProperty())
+ continue;
+ // Don't emit duplicate metadata for properties that were already in a
+ // class extension.
+ if (!PropertySet.insert(PD->getIdentifier()).second)
+ continue;
+ AddProperty(PD);
}
+
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
for (const auto *P : OID->all_referenced_protocols())
- PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes,
+ IsClassProperty);
}
else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
for (const auto *P : CD->protocols())
- PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes,
+ IsClassProperty);
}
// Return null for empty list.
@@ -3018,6 +3051,7 @@
struct _objc_protocol_list *protocols;
uint32_t size; // <rdar://4585769>
struct _objc_property_list *instance_properties;
+ struct _objc_property_list *class_properties;
};
*/
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
@@ -3044,7 +3078,7 @@
// Class methods should always be defined.
ClassMethods.push_back(GetMethodConstant(I));
- llvm::Constant *Values[7];
+ llvm::Constant *Values[8];
Values[0] = GetClassName(OCD->getName());
Values[1] = GetClassName(Interface->getObjCRuntimeNameAsString());
LazySymbols.insert(Interface->getIdentifier());
@@ -3066,9 +3100,12 @@
// If there is no category @interface then there can be no properties.
if (Category) {
Values[6] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes);
+ OCD, Category, ObjCTypes, false);
+ Values[7] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
+ OCD, Category, ObjCTypes, true);
} else {
Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ Values[7] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
}
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy,
@@ -3263,7 +3300,8 @@
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
Values[10] = BuildStrongIvarLayout(ID, CharUnits::Zero(), Size);
- Values[11] = EmitClassExtension(ID, Size, hasMRCWeak);
+ Values[11] = EmitClassExtension(ID, Size, hasMRCWeak,
+ false/*isClassProperty*/);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
std::string Name("OBJC_CLASS_");
@@ -3327,8 +3365,9 @@
Values[ 9] = Protocols;
// ivar_layout for metaclass is always NULL.
Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
- // The class extension is always unused for metaclasses.
- Values[11] = llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
+ // The class extension is used to store class properties for metaclasses.
+ Values[11] = EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/,
+ true/*isClassProperty*/);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
@@ -3402,19 +3441,26 @@
*/
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID,
- CharUnits InstanceSize, bool hasMRCWeakIvars) {
+ CharUnits InstanceSize, bool hasMRCWeakIvars,
+ bool isClassProperty) {
uint64_t Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
- Values[1] = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
- hasMRCWeakIvars);
- Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
- ID, ID->getClassInterface(), ObjCTypes);
+ Values[1] = nullptr;
+ if (!isClassProperty)
+ Values[1] = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
+ hasMRCWeakIvars);
+ if (isClassProperty)
+ Values[2] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ID->getName(),
+ ID, ID->getClassInterface(), ObjCTypes, true);
+ else
+ Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
+ ID, ID->getClassInterface(), ObjCTypes, false);
// Return null if no extension bits are used.
- if (Values[1]->isNullValue() && Values[2]->isNullValue())
+ if ((!Values[1] || Values[1]->isNullValue()) && Values[2]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
llvm::Constant *Init =
@@ -4444,7 +4490,8 @@
// A flag indicating that the module has no instances of a @synthesize of a
// superclass variable. <rdar://problem/6803242>
eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang.
- eImageInfo_ImageIsSimulated = (1 << 5)
+ eImageInfo_ImageIsSimulated = (1 << 5),
+ eImageInfo_ClassProperties = (1 << 6)
};
void CGObjCCommonMac::EmitImageInfo() {
@@ -4496,6 +4543,10 @@
Triple.getArch() == llvm::Triple::x86_64))
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
eImageInfo_ImageIsSimulated);
+
+ // Indicate whether we are generating class properties.
+ Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
+ eImageInfo_ClassProperties);
}
// struct objc_module {
@@ -4759,11 +4810,7 @@
// This isn't a stable sort, but our algorithm should handle it fine.
llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
} else {
-#ifndef NDEBUG
- for (unsigned i = 1; i != IvarsInfo.size(); ++i) {
- assert(IvarsInfo[i - 1].Offset <= IvarsInfo[i].Offset);
- }
-#endif
+ assert(std::is_sorted(IvarsInfo.begin(), IvarsInfo.end()));
}
assert(IvarsInfo.back().Offset < InstanceEnd);
@@ -4929,7 +4976,7 @@
// ARC layout strings only include the class's ivars. In non-fragile
// runtimes, that means starting at InstanceStart, rounded up to word
// alignment. In fragile runtimes, there's no InstanceStart, so it means
- // starting at the end of the superclass, rounded up to word alignment.
+ // starting at the offset of the first ivar, rounded up to word alignment.
//
// MRC weak layout strings follow the ARC style.
CharUnits baseOffset;
@@ -4940,15 +4987,14 @@
if (isNonFragileABI()) {
baseOffset = beginOffset; // InstanceStart
- } else if (auto superClass = OI->getSuperClass()) {
- auto startOffset =
- CGM.getContext().getASTObjCInterfaceLayout(superClass).getSize();
- baseOffset = startOffset;
+ } else if (!ivars.empty()) {
+ baseOffset =
+ CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivars[0]));
} else {
baseOffset = CharUnits::Zero();
}
- baseOffset = baseOffset.RoundUpToAlignment(CGM.getPointerAlign());
+ baseOffset = baseOffset.alignTo(CGM.getPointerAlign());
}
else {
CGM.getContext().DeepCollectObjCIvars(OI, true, ivars);
@@ -5250,12 +5296,13 @@
// struct _objc_method_description_list *optional_class_methods;
// struct _objc_property_list *instance_properties;
// const char ** extendedMethodTypes;
+ // struct _objc_property_list *class_properties;
// }
ProtocolExtensionTy =
llvm::StructType::create("struct._objc_protocol_extension",
IntTy, MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy, PropertyListPtrTy,
- Int8PtrPtrTy, nullptr);
+ Int8PtrPtrTy, PropertyListPtrTy, nullptr);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -5353,14 +5400,17 @@
// char *class_name;
// struct _objc_method_list *instance_method;
// struct _objc_method_list *class_method;
+ // struct _objc_protocol_list *protocols;
// uint32_t size; // sizeof(struct _objc_category)
// struct _objc_property_list *instance_properties;// category's @property
+ // struct _objc_property_list *class_properties;
// }
CategoryTy =
llvm::StructType::create("struct._objc_category",
Int8PtrTy, Int8PtrTy, MethodListPtrTy,
MethodListPtrTy, ProtocolListPtrTy,
- IntTy, PropertyListPtrTy, nullptr);
+ IntTy, PropertyListPtrTy, PropertyListPtrTy,
+ nullptr);
// Global metadata structures
@@ -5428,6 +5478,7 @@
// const uint32_t flags; // = 0
// const char ** extendedMethodTypes;
// const char *demangledName;
+ // const struct _prop_list_t * class_properties;
// }
// Holder for struct _protocol_list_t *
@@ -5440,7 +5491,7 @@
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
- Int8PtrTy,
+ Int8PtrTy, PropertyListPtrTy,
nullptr);
// struct _protocol_t*
@@ -5533,6 +5584,7 @@
// const struct _method_list_t * const class_methods;
// const struct _protocol_list_t * const protocols;
// const struct _prop_list_t * const properties;
+ // const struct _prop_list_t * const class_properties;
// }
CategorynfABITy = llvm::StructType::create("struct._category_t",
Int8PtrTy, ClassnfABIPtrTy,
@@ -5540,6 +5592,7 @@
MethodListnfABIPtrTy,
ProtocolListnfABIPtrTy,
PropertyListPtrTy,
+ PropertyListPtrTy,
nullptr);
// New types for nonfragile abi messaging.
@@ -5808,13 +5861,16 @@
if (flags & NonFragileABI_Class_Meta) {
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
Values[ 8] = GetIvarLayoutName(nullptr, ObjCTypes);
- Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ Values[ 9] = EmitPropertyList(
+ "\01l_OBJC_$_CLASS_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
+ ID, ID->getClassInterface(), ObjCTypes, true);
} else {
Values[ 7] = EmitIvarList(ID);
Values[ 8] = BuildWeakIvarLayout(ID, beginInstance, endInstance,
hasMRCWeak);
- Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
- ID, ID->getClassInterface(), ObjCTypes);
+ Values[ 9] = EmitPropertyList(
+ "\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
+ ID, ID->getClassInterface(), ObjCTypes, false);
}
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
@@ -6097,6 +6153,7 @@
/// const struct _method_list_t * const class_methods;
/// const struct _protocol_list_t * const protocols;
/// const struct _prop_list_t * const properties;
+/// const struct _prop_list_t * const class_properties;
/// }
///
void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
@@ -6111,7 +6168,7 @@
llvm::SmallString<64> ExtClassName(getClassSymbolPrefix());
ExtClassName += Interface->getObjCRuntimeNameAsString();
- llvm::Constant *Values[6];
+ llvm::Constant *Values[7];
Values[0] = GetClassName(OCD->getIdentifier()->getName());
// meta-class entry symbol
llvm::Constant *ClassGV = GetClassGlobal(ExtClassName.str(),
@@ -6161,10 +6218,13 @@
Category->protocol_begin(),
Category->protocol_end());
Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
- OCD, Category, ObjCTypes);
+ OCD, Category, ObjCTypes, false);
+ Values[6] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
+ OCD, Category, ObjCTypes, true);
} else {
Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
}
llvm::Constant *Init =
@@ -6396,6 +6456,7 @@
/// const uint32_t flags; // = 0
/// const char ** extendedMethodTypes;
/// const char *demangledName;
+/// const struct _prop_list_t * class_properties;
/// }
/// @endcode
///
@@ -6447,7 +6508,7 @@
MethodTypesExt.insert(MethodTypesExt.end(),
OptMethodTypesExt.begin(), OptMethodTypesExt.end());
- llvm::Constant *Values[12];
+ llvm::Constant *Values[13];
// isa is NULL
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
Values[1] = GetClassName(PD->getObjCRuntimeNameAsString());
@@ -6471,8 +6532,9 @@
+ PD->getObjCRuntimeNameAsString(),
"__DATA, __objc_const",
OptClassMethods);
- Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
- nullptr, PD, ObjCTypes);
+ Values[7] = EmitPropertyList(
+ "\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
+ nullptr, PD, ObjCTypes, false);
uint32_t Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
@@ -6482,6 +6544,10 @@
MethodTypesExt, ObjCTypes);
// const char *demangledName;
Values[11] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+
+ Values[12] = EmitPropertyList(
+ "\01l_OBJC_$_CLASS_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
+ nullptr, PD, ObjCTypes, true);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
Values);
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 7be9ae9..0104253 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -120,9 +120,8 @@
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
- CharUnits StorageSize =
- CGF.CGM.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(BitOffset + BitFieldSize, AlignmentBits));
+ CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits(
+ llvm::alignTo(BitOffset + BitFieldSize, AlignmentBits));
CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits);
// Allocate a new CGBitFieldInfo object to describe this access.
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 2c81f49..40a167f 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -275,8 +275,11 @@
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+
+ /// Returns an i8* which points to the byref layout information.
virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
QualType T) = 0;
+
virtual llvm::Constant *GetClassGlobal(const std::string &Name,
bool ForDefinition,
bool Weak) = 0;
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 8af39ce..6866789 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -99,3 +99,14 @@
llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0);
}
}
+
+llvm::Type *CGOpenCLRuntime::getPipeType() {
+ if (!PipeTy){
+ uint32_t PipeAddrSpc =
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+ PipeTy = llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc);
+ }
+
+ return PipeTy;
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 0c50b92..f1a7a31 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -32,9 +32,10 @@
class CGOpenCLRuntime {
protected:
CodeGenModule &CGM;
+ llvm::Type *PipeTy;
public:
- CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
+ CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr) {}
virtual ~CGOpenCLRuntime();
/// Emit the IR required for a work-group-local variable declaration, and add
@@ -44,6 +45,8 @@
const VarDecl &D);
virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
+
+ virtual llvm::Type *getPipeType();
};
}
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index ea4300c..3b97ba2 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -11,16 +11,19 @@
//
//===----------------------------------------------------------------------===//
+#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
-#include "CGCleanup.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtOpenMP.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Value.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -81,7 +84,7 @@
protected:
CGOpenMPRegionKind RegionKind;
- const RegionCodeGenTy &CodeGen;
+ RegionCodeGenTy CodeGen;
OpenMPDirectiveKind Kind;
bool HasCancel;
};
@@ -215,25 +218,31 @@
/// \brief API for captured statement code generation in OpenMP target
/// constructs. For this captures, implicit parameters are used instead of the
-/// captured fields.
+/// captured fields. The name of the target region has to be unique in a given
+/// application so it is provided by the client, because only the client has
+/// the information to generate that.
class CGOpenMPTargetRegionInfo : public CGOpenMPRegionInfo {
public:
CGOpenMPTargetRegionInfo(const CapturedStmt &CS,
- const RegionCodeGenTy &CodeGen)
+ const RegionCodeGenTy &CodeGen, StringRef HelperName)
: CGOpenMPRegionInfo(CS, TargetRegion, CodeGen, OMPD_target,
- /*HasCancel = */ false) {}
+ /*HasCancel=*/false),
+ HelperName(HelperName) {}
/// \brief This is unused for target regions because each starts executing
/// with a single thread.
const VarDecl *getThreadIDVariable() const override { return nullptr; }
/// \brief Get the name of the capture helper.
- StringRef getHelperName() const override { return ".omp_offloading."; }
+ StringRef getHelperName() const override { return HelperName; }
static bool classof(const CGCapturedStmtInfo *Info) {
return CGOpenMPRegionInfo::classof(Info) &&
cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == TargetRegion;
}
+
+private:
+ StringRef HelperName;
};
/// \brief RAII for emitting code of OpenMP constructs.
@@ -278,6 +287,8 @@
}
void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt * /*S*/) {
+ if (!CGF.HaveInsertPoint())
+ return;
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
@@ -299,7 +310,8 @@
}
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
- : CGM(CGM), DefaultOpenMPPSource(nullptr), KmpRoutineEntryPtrTy(nullptr) {
+ : CGM(CGM), DefaultOpenMPPSource(nullptr), KmpRoutineEntryPtrTy(nullptr),
+ OffloadEntriesInfoManager(CGM) {
IdentTy = llvm::StructType::create(
"ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
@@ -309,6 +321,8 @@
llvm::PointerType::getUnqual(CGM.Int32Ty)};
Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
+
+ loadOffloadInfoMetadata();
}
void CGOpenMPRuntime::clear() {
@@ -557,6 +571,17 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical");
break;
}
+ case OMPRTL__kmpc_critical_with_hint: {
+ // Build void __kmpc_critical_with_hint(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *crit, uintptr_t hint);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
+ llvm::PointerType::getUnqual(KmpCriticalNameTy),
+ CGM.IntPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical_with_hint");
+ break;
+ }
case OMPRTL__kmpc_threadprivate_register: {
// Build void __kmpc_threadprivate_register(ident_t *, void *data,
// kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
@@ -918,6 +943,26 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target");
break;
}
+ case OMPRTL__tgt_register_lib: {
+ // Build void __tgt_register_lib(__tgt_bin_desc *desc);
+ QualType ParamTy =
+ CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
+ llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_lib");
+ break;
+ }
+ case OMPRTL__tgt_unregister_lib: {
+ // Build void __tgt_unregister_lib(__tgt_bin_desc *desc);
+ QualType ParamTy =
+ CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy());
+ llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_unregister_lib");
+ break;
+ }
}
return RTLFn;
}
@@ -1252,6 +1297,8 @@
llvm::Value *OutlinedFn,
ArrayRef<llvm::Value *> CapturedVars,
const Expr *IfCond) {
+ if (!CGF.HaveInsertPoint())
+ return;
auto *RTLoc = emitUpdateLocation(CGF, Loc);
auto &&ThenGen = [this, OutlinedFn, CapturedVars,
RTLoc](CodeGenFunction &CGF) {
@@ -1361,6 +1408,8 @@
std::copy(CleanupArgs.begin(), CleanupArgs.end(), std::begin(Args));
}
void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
+ if (!CGF.HaveInsertPoint())
+ return;
CGF.EmitRuntimeCall(Callee, Args);
}
};
@@ -1369,22 +1418,31 @@
void CGOpenMPRuntime::emitCriticalRegion(CodeGenFunction &CGF,
StringRef CriticalName,
const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc) {
- // __kmpc_critical(ident_t *, gtid, Lock);
+ SourceLocation Loc, const Expr *Hint) {
+ // __kmpc_critical[_with_hint](ident_t *, gtid, Lock[, hint]);
// CriticalOpGen();
// __kmpc_end_critical(ident_t *, gtid, Lock);
// Prepare arguments and build a call to __kmpc_critical
- {
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- getCriticalRegionLock(CriticalName)};
+ if (!CGF.HaveInsertPoint())
+ return;
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
+ getCriticalRegionLock(CriticalName)};
+ if (Hint) {
+ llvm::SmallVector<llvm::Value *, 8> ArgsWithHint(std::begin(Args),
+ std::end(Args));
+ auto *HintVal = CGF.EmitScalarExpr(Hint);
+ ArgsWithHint.push_back(
+ CGF.Builder.CreateIntCast(HintVal, CGM.IntPtrTy, /*isSigned=*/false));
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_critical_with_hint),
+ ArgsWithHint);
+ } else
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_critical), Args);
- // Build a call to __kmpc_end_critical
- CGF.EHStack.pushCleanup<CallEndCleanup<std::extent<decltype(Args)>::value>>(
- NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_critical),
- llvm::makeArrayRef(Args));
- emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
- }
+ // Build a call to __kmpc_end_critical
+ CGF.EHStack.pushCleanup<CallEndCleanup<std::extent<decltype(Args)>::value>>(
+ NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_critical),
+ llvm::makeArrayRef(Args));
+ emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
}
static void emitIfStmt(CodeGenFunction &CGF, llvm::Value *IfCond,
@@ -1409,6 +1467,8 @@
void CGOpenMPRuntime::emitMasterRegion(CodeGenFunction &CGF,
const RegionCodeGenTy &MasterOpGen,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// if(__kmpc_master(ident_t *, gtid)) {
// MasterOpGen();
// __kmpc_end_master(ident_t *, gtid);
@@ -1431,6 +1491,8 @@
void CGOpenMPRuntime::emitTaskyieldCall(CodeGenFunction &CGF,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call __kmpc_omp_taskyield(loc, thread_id, 0);
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
@@ -1441,6 +1503,8 @@
void CGOpenMPRuntime::emitTaskgroupRegion(CodeGenFunction &CGF,
const RegionCodeGenTy &TaskgroupOpGen,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// __kmpc_taskgroup(ident_t *, gtid);
// TaskgroupOpGen();
// __kmpc_end_taskgroup(ident_t *, gtid);
@@ -1528,6 +1592,8 @@
ArrayRef<const Expr *> SrcExprs,
ArrayRef<const Expr *> DstExprs,
ArrayRef<const Expr *> AssignmentOps) {
+ if (!CGF.HaveInsertPoint())
+ return;
assert(CopyprivateVars.size() == SrcExprs.size() &&
CopyprivateVars.size() == DstExprs.size() &&
CopyprivateVars.size() == AssignmentOps.size());
@@ -1609,6 +1675,8 @@
void CGOpenMPRuntime::emitOrderedRegion(CodeGenFunction &CGF,
const RegionCodeGenTy &OrderedOpGen,
SourceLocation Loc, bool IsThreads) {
+ if (!CGF.HaveInsertPoint())
+ return;
// __kmpc_ordered(ident_t *, gtid);
// OrderedOpGen();
// __kmpc_end_ordered(ident_t *, gtid);
@@ -1628,6 +1696,8 @@
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
OpenMPDirectiveKind Kind, bool EmitChecks,
bool ForceSimpleCall) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call __kmpc_cancel_barrier(loc, thread_id);
// Build call __kmpc_barrier(loc, thread_id);
OpenMPLocationFlags Flags = OMP_IDENT_KMPC;
@@ -1743,6 +1813,8 @@
unsigned IVSize, bool IVSigned,
bool Ordered, llvm::Value *UB,
llvm::Value *Chunk) {
+ if (!CGF.HaveInsertPoint())
+ return;
OpenMPSchedType Schedule =
getRuntimeSchedule(ScheduleKind, Chunk != nullptr, Ordered);
assert(Ordered ||
@@ -1775,6 +1847,8 @@
bool Ordered, Address IL, Address LB,
Address UB, Address ST,
llvm::Value *Chunk) {
+ if (!CGF.HaveInsertPoint())
+ return;
OpenMPSchedType Schedule =
getRuntimeSchedule(ScheduleKind, Chunk != nullptr, Ordered);
assert(!Ordered);
@@ -1812,6 +1886,8 @@
void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
getThreadID(CGF, Loc)};
@@ -1823,6 +1899,8 @@
SourceLocation Loc,
unsigned IVSize,
bool IVSigned) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
getThreadID(CGF, Loc)};
@@ -1855,6 +1933,8 @@
void CGOpenMPRuntime::emitNumThreadsClause(CodeGenFunction &CGF,
llvm::Value *NumThreads,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
@@ -1866,6 +1946,8 @@
void CGOpenMPRuntime::emitProcBindClause(CodeGenFunction &CGF,
OpenMPProcBindClauseKind ProcBind,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Constants for proc bind value accepted by the runtime.
enum ProcBindTy {
ProcBindFalse = 0,
@@ -1898,6 +1980,8 @@
void CGOpenMPRuntime::emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *>,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call void __kmpc_flush(ident_t *loc)
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_flush),
emitUpdateLocation(CGF, Loc));
@@ -1917,6 +2001,381 @@
};
} // anonymous namespace
+bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::empty() const {
+ // FIXME: Add other entries type when they become supported.
+ return OffloadEntriesTargetRegion.empty();
+}
+
+/// \brief Initialize target region entry.
+void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
+ initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
+ StringRef ParentName, unsigned LineNum,
+ unsigned ColNum, unsigned Order) {
+ assert(CGM.getLangOpts().OpenMPIsDevice && "Initialization of entries is "
+ "only required for the device "
+ "code generation.");
+ OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum][ColNum] =
+ OffloadEntryInfoTargetRegion(Order, /*Addr=*/nullptr, /*ID=*/nullptr);
+ ++OffloadingEntriesNum;
+}
+
+void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
+ registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
+ StringRef ParentName, unsigned LineNum,
+ unsigned ColNum, llvm::Constant *Addr,
+ llvm::Constant *ID) {
+ // If we are emitting code for a target, the entry is already initialized,
+ // only has to be registered.
+ if (CGM.getLangOpts().OpenMPIsDevice) {
+ assert(hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum,
+ ColNum) &&
+ "Entry must exist.");
+ auto &Entry = OffloadEntriesTargetRegion[DeviceID][FileID][ParentName]
+ [LineNum][ColNum];
+ assert(Entry.isValid() && "Entry not initialized!");
+ Entry.setAddress(Addr);
+ Entry.setID(ID);
+ return;
+ } else {
+ OffloadEntryInfoTargetRegion Entry(OffloadingEntriesNum++, Addr, ID);
+ OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum][ColNum] =
+ Entry;
+ }
+}
+
+bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::hasTargetRegionEntryInfo(
+ unsigned DeviceID, unsigned FileID, StringRef ParentName, unsigned LineNum,
+ unsigned ColNum) const {
+ auto PerDevice = OffloadEntriesTargetRegion.find(DeviceID);
+ if (PerDevice == OffloadEntriesTargetRegion.end())
+ return false;
+ auto PerFile = PerDevice->second.find(FileID);
+ if (PerFile == PerDevice->second.end())
+ return false;
+ auto PerParentName = PerFile->second.find(ParentName);
+ if (PerParentName == PerFile->second.end())
+ return false;
+ auto PerLine = PerParentName->second.find(LineNum);
+ if (PerLine == PerParentName->second.end())
+ return false;
+ auto PerColumn = PerLine->second.find(ColNum);
+ if (PerColumn == PerLine->second.end())
+ return false;
+ // Fail if this entry is already registered.
+ if (PerColumn->second.getAddress() || PerColumn->second.getID())
+ return false;
+ return true;
+}
+
+void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::actOnTargetRegionEntriesInfo(
+ const OffloadTargetRegionEntryInfoActTy &Action) {
+ // Scan all target region entries and perform the provided action.
+ for (auto &D : OffloadEntriesTargetRegion)
+ for (auto &F : D.second)
+ for (auto &P : F.second)
+ for (auto &L : P.second)
+ for (auto &C : L.second)
+ Action(D.first, F.first, P.first(), L.first, C.first, C.second);
+}
+
+/// \brief Create a Ctor/Dtor-like function whose body is emitted through
+/// \a Codegen. This is used to emit the two functions that register and
+/// unregister the descriptor of the current compilation unit.
+static llvm::Function *
+createOffloadingBinaryDescriptorFunction(CodeGenModule &CGM, StringRef Name,
+ const RegionCodeGenTy &Codegen) {
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl DummyPtr(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ Args.push_back(&DummyPtr);
+
+ CodeGenFunction CGF(CGM);
+ GlobalDecl();
+ auto &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, Args, FunctionType::ExtInfo(),
+ /*isVariadic=*/false);
+ auto FTy = CGM.getTypes().GetFunctionType(FI);
+ auto *Fn =
+ CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, SourceLocation());
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FI, Args, SourceLocation());
+ Codegen(CGF);
+ CGF.FinishFunction();
+ return Fn;
+}
+
+llvm::Function *
+CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
+
+ // If we don't have entries or if we are emitting code for the device, we
+ // don't need to do anything.
+ if (CGM.getLangOpts().OpenMPIsDevice || OffloadEntriesInfoManager.empty())
+ return nullptr;
+
+ auto &M = CGM.getModule();
+ auto &C = CGM.getContext();
+
+ // Get list of devices we care about
+ auto &Devices = CGM.getLangOpts().OMPTargetTriples;
+
+ // We should be creating an offloading descriptor only if there are devices
+ // specified.
+ assert(!Devices.empty() && "No OpenMP offloading devices??");
+
+ // Create the external variables that will point to the begin and end of the
+ // host entries section. These will be defined by the linker.
+ auto *OffloadEntryTy =
+ CGM.getTypes().ConvertTypeForMem(getTgtOffloadEntryQTy());
+ llvm::GlobalVariable *HostEntriesBegin = new llvm::GlobalVariable(
+ M, OffloadEntryTy, /*isConstant=*/true,
+ llvm::GlobalValue::ExternalLinkage, /*Initializer=*/0,
+ ".omp_offloading.entries_begin");
+ llvm::GlobalVariable *HostEntriesEnd = new llvm::GlobalVariable(
+ M, OffloadEntryTy, /*isConstant=*/true,
+ llvm::GlobalValue::ExternalLinkage, /*Initializer=*/0,
+ ".omp_offloading.entries_end");
+
+ // Create all device images
+ llvm::SmallVector<llvm::Constant *, 4> DeviceImagesEntires;
+ auto *DeviceImageTy = cast<llvm::StructType>(
+ CGM.getTypes().ConvertTypeForMem(getTgtDeviceImageQTy()));
+
+ for (unsigned i = 0; i < Devices.size(); ++i) {
+ StringRef T = Devices[i].getTriple();
+ auto *ImgBegin = new llvm::GlobalVariable(
+ M, CGM.Int8Ty, /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage,
+ /*Initializer=*/0, Twine(".omp_offloading.img_start.") + Twine(T));
+ auto *ImgEnd = new llvm::GlobalVariable(
+ M, CGM.Int8Ty, /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage,
+ /*Initializer=*/0, Twine(".omp_offloading.img_end.") + Twine(T));
+
+ llvm::Constant *Dev =
+ llvm::ConstantStruct::get(DeviceImageTy, ImgBegin, ImgEnd,
+ HostEntriesBegin, HostEntriesEnd, nullptr);
+ DeviceImagesEntires.push_back(Dev);
+ }
+
+ // Create device images global array.
+ llvm::ArrayType *DeviceImagesInitTy =
+ llvm::ArrayType::get(DeviceImageTy, DeviceImagesEntires.size());
+ llvm::Constant *DeviceImagesInit =
+ llvm::ConstantArray::get(DeviceImagesInitTy, DeviceImagesEntires);
+
+ llvm::GlobalVariable *DeviceImages = new llvm::GlobalVariable(
+ M, DeviceImagesInitTy, /*isConstant=*/true,
+ llvm::GlobalValue::InternalLinkage, DeviceImagesInit,
+ ".omp_offloading.device_images");
+ DeviceImages->setUnnamedAddr(true);
+
+ // This is a Zero array to be used in the creation of the constant expressions
+ llvm::Constant *Index[] = {llvm::Constant::getNullValue(CGM.Int32Ty),
+ llvm::Constant::getNullValue(CGM.Int32Ty)};
+
+ // Create the target region descriptor.
+ auto *BinaryDescriptorTy = cast<llvm::StructType>(
+ CGM.getTypes().ConvertTypeForMem(getTgtBinaryDescriptorQTy()));
+ llvm::Constant *TargetRegionsDescriptorInit = llvm::ConstantStruct::get(
+ BinaryDescriptorTy, llvm::ConstantInt::get(CGM.Int32Ty, Devices.size()),
+ llvm::ConstantExpr::getGetElementPtr(DeviceImagesInitTy, DeviceImages,
+ Index),
+ HostEntriesBegin, HostEntriesEnd, nullptr);
+
+ auto *Desc = new llvm::GlobalVariable(
+ M, BinaryDescriptorTy, /*isConstant=*/true,
+ llvm::GlobalValue::InternalLinkage, TargetRegionsDescriptorInit,
+ ".omp_offloading.descriptor");
+
+ // Emit code to register or unregister the descriptor at execution
+ // startup or closing, respectively.
+
+ // Create a variable to drive the registration and unregistration of the
+ // descriptor, so we can reuse the logic that emits Ctors and Dtors.
+ auto *IdentInfo = &C.Idents.get(".omp_offloading.reg_unreg_var");
+ ImplicitParamDecl RegUnregVar(C, C.getTranslationUnitDecl(), SourceLocation(),
+ IdentInfo, C.CharTy);
+
+ auto *UnRegFn = createOffloadingBinaryDescriptorFunction(
+ CGM, ".omp_offloading.descriptor_unreg", [&](CodeGenFunction &CGF) {
+ CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_unregister_lib),
+ Desc);
+ });
+ auto *RegFn = createOffloadingBinaryDescriptorFunction(
+ CGM, ".omp_offloading.descriptor_reg", [&](CodeGenFunction &CGF) {
+ CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_register_lib),
+ Desc);
+ CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
+ });
+ return RegFn;
+}
+
+void CGOpenMPRuntime::createOffloadEntry(llvm::Constant *Addr, StringRef Name,
+ uint64_t Size) {
+ auto *TgtOffloadEntryType = cast<llvm::StructType>(
+ CGM.getTypes().ConvertTypeForMem(getTgtOffloadEntryQTy()));
+ llvm::LLVMContext &C = CGM.getModule().getContext();
+ llvm::Module &M = CGM.getModule();
+
+ // Make sure the address has the right type.
+ llvm::Constant *AddrPtr = llvm::ConstantExpr::getBitCast(Addr, CGM.VoidPtrTy);
+
+ // Create constant string with the name.
+ llvm::Constant *StrPtrInit = llvm::ConstantDataArray::getString(C, Name);
+
+ llvm::GlobalVariable *Str =
+ new llvm::GlobalVariable(M, StrPtrInit->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::InternalLinkage, StrPtrInit,
+ ".omp_offloading.entry_name");
+ Str->setUnnamedAddr(true);
+ llvm::Constant *StrPtr = llvm::ConstantExpr::getBitCast(Str, CGM.Int8PtrTy);
+
+ // Create the entry struct.
+ llvm::Constant *EntryInit = llvm::ConstantStruct::get(
+ TgtOffloadEntryType, AddrPtr, StrPtr,
+ llvm::ConstantInt::get(CGM.SizeTy, Size), nullptr);
+ llvm::GlobalVariable *Entry = new llvm::GlobalVariable(
+ M, TgtOffloadEntryType, true, llvm::GlobalValue::ExternalLinkage,
+ EntryInit, ".omp_offloading.entry");
+
+ // The entry has to be created in the section the linker expects it to be.
+ Entry->setSection(".omp_offloading.entries");
+ // We can't have any padding between symbols, so we need to have 1-byte
+ // alignment.
+ Entry->setAlignment(1);
+ return;
+}
+
+void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
+ // Emit the offloading entries and metadata so that the device codegen side
+ // can
+ // easily figure out what to emit. The produced metadata looks like this:
+ //
+ // !omp_offload.info = !{!1, ...}
+ //
+ // Right now we only generate metadata for function that contain target
+ // regions.
+
+ // If we do not have entries, we dont need to do anything.
+ if (OffloadEntriesInfoManager.empty())
+ return;
+
+ llvm::Module &M = CGM.getModule();
+ llvm::LLVMContext &C = M.getContext();
+ SmallVector<OffloadEntriesInfoManagerTy::OffloadEntryInfo *, 16>
+ OrderedEntries(OffloadEntriesInfoManager.size());
+
+ // Create the offloading info metadata node.
+ llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("omp_offload.info");
+
+ // Auxiliar methods to create metadata values and strings.
+ auto getMDInt = [&](unsigned v) {
+ return llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(C), v));
+ };
+
+ auto getMDString = [&](StringRef v) { return llvm::MDString::get(C, v); };
+
+ // Create function that emits metadata for each target region entry;
+ auto &&TargetRegionMetadataEmitter = [&](
+ unsigned DeviceID, unsigned FileID, StringRef ParentName, unsigned Line,
+ unsigned Column,
+ OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion &E) {
+ llvm::SmallVector<llvm::Metadata *, 32> Ops;
+ // Generate metadata for target regions. Each entry of this metadata
+ // contains:
+ // - Entry 0 -> Kind of this type of metadata (0).
+ // - Entry 1 -> Device ID of the file where the entry was identified.
+ // - Entry 2 -> File ID of the file where the entry was identified.
+ // - Entry 3 -> Mangled name of the function where the entry was identified.
+ // - Entry 4 -> Line in the file where the entry was identified.
+ // - Entry 5 -> Column in the file where the entry was identified.
+ // - Entry 6 -> Order the entry was created.
+ // The first element of the metadata node is the kind.
+ Ops.push_back(getMDInt(E.getKind()));
+ Ops.push_back(getMDInt(DeviceID));
+ Ops.push_back(getMDInt(FileID));
+ Ops.push_back(getMDString(ParentName));
+ Ops.push_back(getMDInt(Line));
+ Ops.push_back(getMDInt(Column));
+ Ops.push_back(getMDInt(E.getOrder()));
+
+ // Save this entry in the right position of the ordered entries array.
+ OrderedEntries[E.getOrder()] = &E;
+
+ // Add metadata to the named metadata node.
+ MD->addOperand(llvm::MDNode::get(C, Ops));
+ };
+
+ OffloadEntriesInfoManager.actOnTargetRegionEntriesInfo(
+ TargetRegionMetadataEmitter);
+
+ for (auto *E : OrderedEntries) {
+ assert(E && "All ordered entries must exist!");
+ if (auto *CE =
+ dyn_cast<OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion>(
+ E)) {
+ assert(CE->getID() && CE->getAddress() &&
+ "Entry ID and Addr are invalid!");
+ createOffloadEntry(CE->getID(), CE->getAddress()->getName(), /*Size=*/0);
+ } else
+ llvm_unreachable("Unsupported entry kind.");
+ }
+}
+
+/// \brief Loads all the offload entries information from the host IR
+/// metadata.
+void CGOpenMPRuntime::loadOffloadInfoMetadata() {
+ // If we are in target mode, load the metadata from the host IR. This code has
+ // to match the metadaata creation in createOffloadEntriesAndInfoMetadata().
+
+ if (!CGM.getLangOpts().OpenMPIsDevice)
+ return;
+
+ if (CGM.getLangOpts().OMPHostIRFile.empty())
+ return;
+
+ auto Buf = llvm::MemoryBuffer::getFile(CGM.getLangOpts().OMPHostIRFile);
+ if (Buf.getError())
+ return;
+
+ llvm::LLVMContext C;
+ auto ME = llvm::parseBitcodeFile(Buf.get()->getMemBufferRef(), C);
+
+ if (ME.getError())
+ return;
+
+ llvm::NamedMDNode *MD = ME.get()->getNamedMetadata("omp_offload.info");
+ if (!MD)
+ return;
+
+ for (auto I : MD->operands()) {
+ llvm::MDNode *MN = cast<llvm::MDNode>(I);
+
+ auto getMDInt = [&](unsigned Idx) {
+ llvm::ConstantAsMetadata *V =
+ cast<llvm::ConstantAsMetadata>(MN->getOperand(Idx));
+ return cast<llvm::ConstantInt>(V->getValue())->getZExtValue();
+ };
+
+ auto getMDString = [&](unsigned Idx) {
+ llvm::MDString *V = cast<llvm::MDString>(MN->getOperand(Idx));
+ return V->getString();
+ };
+
+ switch (getMDInt(0)) {
+ default:
+ llvm_unreachable("Unexpected metadata!");
+ break;
+ case OffloadEntriesInfoManagerTy::OffloadEntryInfo::
+ OFFLOAD_ENTRY_INFO_TARGET_REGION:
+ OffloadEntriesInfoManager.initializeTargetRegionEntryInfo(
+ /*DeviceID=*/getMDInt(1), /*FileID=*/getMDInt(2),
+ /*ParentName=*/getMDString(3), /*Line=*/getMDInt(4),
+ /*Column=*/getMDInt(5), /*Order=*/getMDInt(6));
+ break;
+ }
+ }
+}
+
void CGOpenMPRuntime::emitKmpRoutineEntryT(QualType KmpInt32Ty) {
if (!KmpRoutineEntryPtrTy) {
// Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
@@ -1940,6 +2399,80 @@
return Field;
}
+QualType CGOpenMPRuntime::getTgtOffloadEntryQTy() {
+
+ // Make sure the type of the entry is already created. This is the type we
+ // have to create:
+ // struct __tgt_offload_entry{
+ // void *addr; // Pointer to the offload entry info.
+ // // (function or global)
+ // char *name; // Name of the function or global.
+ // size_t size; // Size of the entry info (0 if it a function).
+ // };
+ if (TgtOffloadEntryQTy.isNull()) {
+ ASTContext &C = CGM.getContext();
+ auto *RD = C.buildImplicitRecord("__tgt_offload_entry");
+ RD->startDefinition();
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ addFieldToRecordDecl(C, RD, C.getPointerType(C.CharTy));
+ addFieldToRecordDecl(C, RD, C.getSizeType());
+ RD->completeDefinition();
+ TgtOffloadEntryQTy = C.getRecordType(RD);
+ }
+ return TgtOffloadEntryQTy;
+}
+
+QualType CGOpenMPRuntime::getTgtDeviceImageQTy() {
+ // These are the types we need to build:
+ // struct __tgt_device_image{
+ // void *ImageStart; // Pointer to the target code start.
+ // void *ImageEnd; // Pointer to the target code end.
+ // // We also add the host entries to the device image, as it may be useful
+ // // for the target runtime to have access to that information.
+ // __tgt_offload_entry *EntriesBegin; // Begin of the table with all
+ // // the entries.
+ // __tgt_offload_entry *EntriesEnd; // End of the table with all the
+ // // entries (non inclusive).
+ // };
+ if (TgtDeviceImageQTy.isNull()) {
+ ASTContext &C = CGM.getContext();
+ auto *RD = C.buildImplicitRecord("__tgt_device_image");
+ RD->startDefinition();
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
+ addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
+ RD->completeDefinition();
+ TgtDeviceImageQTy = C.getRecordType(RD);
+ }
+ return TgtDeviceImageQTy;
+}
+
+QualType CGOpenMPRuntime::getTgtBinaryDescriptorQTy() {
+ // struct __tgt_bin_desc{
+ // int32_t NumDevices; // Number of devices supported.
+ // __tgt_device_image *DeviceImages; // Arrays of device images
+ // // (one per device).
+ // __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
+ // // entries.
+ // __tgt_offload_entry *EntriesEnd; // End of the table with all the
+ // // entries (non inclusive).
+ // };
+ if (TgtBinaryDescriptorQTy.isNull()) {
+ ASTContext &C = CGM.getContext();
+ auto *RD = C.buildImplicitRecord("__tgt_bin_desc");
+ RD->startDefinition();
+ addFieldToRecordDecl(
+ C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true));
+ addFieldToRecordDecl(C, RD, C.getPointerType(getTgtDeviceImageQTy()));
+ addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
+ addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy()));
+ RD->completeDefinition();
+ TgtBinaryDescriptorQTy = C.getRecordType(RD);
+ }
+ return TgtBinaryDescriptorQTy;
+}
+
namespace {
struct PrivateHelpersTy {
PrivateHelpersTy(const VarDecl *Original, const VarDecl *PrivateCopy,
@@ -2234,6 +2767,8 @@
ArrayRef<const Expr *> FirstprivateCopies,
ArrayRef<const Expr *> FirstprivateInits,
ArrayRef<std::pair<OpenMPDependClauseKind, const Expr *>> Dependences) {
+ if (!CGF.HaveInsertPoint())
+ return;
auto &C = CGM.getContext();
llvm::SmallVector<PrivateDataTy, 8> Privates;
// Aggregate privates and sort them by the alignment.
@@ -2317,7 +2852,7 @@
CGF.Builder.getInt32(/*C=*/0))
: CGF.Builder.getInt32(Final.getInt() ? FinalFlag : 0);
TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
- auto *SharedsSize = getTypeSize(CGF, SharedsTy);
+ auto *SharedsSize = CGM.getSize(C.getTypeSizeInChars(SharedsTy));
llvm::Value *AllocArgs[] = {emitUpdateLocation(CGF, Loc),
getThreadID(CGF, Loc), TaskFlags,
KmpTaskTWithPrivatesTySize, SharedsSize,
@@ -2437,7 +2972,7 @@
unsigned NumDependencies = Dependences.size();
if (NumDependencies) {
// Dependence kind for RTL.
- enum RTLDependenceKindTy { DepIn = 1, DepOut = 2, DepInOut = 3 };
+ enum RTLDependenceKindTy { DepIn = 0x01, DepInOut = 0x3 };
enum RTLDependInfoFieldsTy { BaseAddr, Len, Flags };
RecordDecl *KmpDependInfoRD;
QualType FlagsTy =
@@ -2496,12 +3031,13 @@
case OMPC_DEPEND_in:
DepKind = DepIn;
break;
+ // Out and InOut dependencies must use the same code.
case OMPC_DEPEND_out:
- DepKind = DepOut;
- break;
case OMPC_DEPEND_inout:
DepKind = DepInOut;
break;
+ case OMPC_DEPEND_source:
+ case OMPC_DEPEND_sink:
case OMPC_DEPEND_unknown:
llvm_unreachable("Unknown task dependence type");
}
@@ -2767,6 +3303,8 @@
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
bool WithNowait, bool SimpleReduction) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Next code should be emitted for reduction:
//
// static kmp_critical_name lock = { 0 };
@@ -3056,6 +3594,8 @@
void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
SourceLocation Loc) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
// global_tid);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
@@ -3067,6 +3607,8 @@
OpenMPDirectiveKind InnerKind,
const RegionCodeGenTy &CodeGen,
bool HasCancel) {
+ if (!CGF.HaveInsertPoint())
+ return;
InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel);
CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
}
@@ -3099,6 +3641,8 @@
void CGOpenMPRuntime::emitCancellationPointCall(
CodeGenFunction &CGF, SourceLocation Loc,
OpenMPDirectiveKind CancelRegion) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
// global_tid, kmp_int32 cncl_kind);
if (auto *OMPRegionInfo =
@@ -3135,6 +3679,8 @@
void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
const Expr *IfCond,
OpenMPDirectiveKind CancelRegion) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
// kmp_int32 cncl_kind);
if (auto *OMPRegionInfo =
@@ -3173,22 +3719,119 @@
}
}
-llvm::Value *
-CGOpenMPRuntime::emitTargetOutlinedFunction(const OMPExecutableDirective &D,
- const RegionCodeGenTy &CodeGen) {
+/// \brief Obtain information that uniquely identifies a target entry. This
+/// consists of the file and device IDs as well as line and column numbers
+/// associated with the relevant entry source location.
+static void getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
+ unsigned &DeviceID, unsigned &FileID,
+ unsigned &LineNum, unsigned &ColumnNum) {
+
+ auto &SM = C.getSourceManager();
+
+ // The loc should be always valid and have a file ID (the user cannot use
+ // #pragma directives in macros)
+
+ assert(Loc.isValid() && "Source location is expected to be always valid.");
+ assert(Loc.isFileID() && "Source location is expected to refer to a file.");
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ assert(PLoc.isValid() && "Source location is expected to be always valid.");
+
+ llvm::sys::fs::UniqueID ID;
+ if (llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
+ llvm_unreachable("Source file with target region no longer exists!");
+
+ DeviceID = ID.getDevice();
+ FileID = ID.getFile();
+ LineNum = PLoc.getLine();
+ ColumnNum = PLoc.getColumn();
+ return;
+}
+
+void CGOpenMPRuntime::emitTargetOutlinedFunction(
+ const OMPExecutableDirective &D, StringRef ParentName,
+ llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
+ bool IsOffloadEntry) {
+
+ assert(!ParentName.empty() && "Invalid target region parent name!");
+
const CapturedStmt &CS = *cast<CapturedStmt>(D.getAssociatedStmt());
+ // Emit target region as a standalone region.
+ auto &&CodeGen = [&CS](CodeGenFunction &CGF) {
+ CGF.EmitStmt(CS.getCapturedStmt());
+ };
+
+ // Create a unique name for the proxy/entry function that using the source
+ // location information of the current target region. The name will be
+ // something like:
+ //
+ // .omp_offloading.DD_FFFF.PP.lBB.cCC
+ //
+ // where DD_FFFF is an ID unique to the file (device and file IDs), PP is the
+ // mangled name of the function that encloses the target region, BB is the
+ // line number of the target region, and CC is the column number of the target
+ // region.
+
+ unsigned DeviceID;
+ unsigned FileID;
+ unsigned Line;
+ unsigned Column;
+ getTargetEntryUniqueInfo(CGM.getContext(), D.getLocStart(), DeviceID, FileID,
+ Line, Column);
+ SmallString<64> EntryFnName;
+ {
+ llvm::raw_svector_ostream OS(EntryFnName);
+ OS << ".omp_offloading" << llvm::format(".%x", DeviceID)
+ << llvm::format(".%x.", FileID) << ParentName << ".l" << Line << ".c"
+ << Column;
+ }
+
CodeGenFunction CGF(CGM, true);
- CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen);
+ CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- return CGF.GenerateOpenMPCapturedStmtFunction(CS, /*UseOnlyReferences=*/true);
+
+ OutlinedFn = CGF.GenerateOpenMPCapturedStmtFunction(CS);
+
+ // If this target outline function is not an offload entry, we don't need to
+ // register it.
+ if (!IsOffloadEntry)
+ return;
+
+ // The target region ID is used by the runtime library to identify the current
+ // target region, so it only has to be unique and not necessarily point to
+ // anything. It could be the pointer to the outlined function that implements
+ // the target region, but we aren't using that so that the compiler doesn't
+ // need to keep that, and could therefore inline the host function if proven
+ // worthwhile during optimization. In the other hand, if emitting code for the
+ // device, the ID has to be the function address so that it can retrieved from
+ // the offloading entry and launched by the runtime library. We also mark the
+ // outlined function to have external linkage in case we are emitting code for
+ // the device, because these functions will be entry points to the device.
+
+ if (CGM.getLangOpts().OpenMPIsDevice) {
+ OutlinedFnID = llvm::ConstantExpr::getBitCast(OutlinedFn, CGM.Int8PtrTy);
+ OutlinedFn->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ } else
+ OutlinedFnID = new llvm::GlobalVariable(
+ CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage,
+ llvm::Constant::getNullValue(CGM.Int8Ty), ".omp_offload.region_id");
+
+ // Register the information for the entry associated with this target region.
+ OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
+ DeviceID, FileID, ParentName, Line, Column, OutlinedFn, OutlinedFnID);
+ return;
}
void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
const OMPExecutableDirective &D,
llvm::Value *OutlinedFn,
+ llvm::Value *OutlinedFnID,
const Expr *IfCond, const Expr *Device,
ArrayRef<llvm::Value *> CapturedVars) {
+ if (!CGF.HaveInsertPoint())
+ return;
/// \brief Values for bit flags used to specify the mapping type for
/// offloading.
enum OpenMPOffloadMappingFlags {
@@ -3196,6 +3839,10 @@
OMP_MAP_TO = 0x01,
/// \brief Allocate memory on the device and move data from device to host.
OMP_MAP_FROM = 0x02,
+ /// \brief The element passed to the device is a pointer.
+ OMP_MAP_PTR = 0x20,
+ /// \brief Pass the element to the device by value.
+ OMP_MAP_BYCOPY = 0x80,
};
enum OpenMPOffloadingReservedDeviceIDs {
@@ -3204,6 +3851,10 @@
OMP_DEVICEID_UNDEF = -1,
};
+ assert(OutlinedFn && "Invalid outlined function!");
+
+ auto &Ctx = CGF.getContext();
+
// Fill up the arrays with the all the captured variables.
SmallVector<llvm::Value *, 16> BasePointers;
SmallVector<llvm::Value *, 16> Pointers;
@@ -3226,27 +3877,61 @@
llvm::Value *Size;
unsigned MapType;
+ // VLA sizes are passed to the outlined region by copy.
if (CI->capturesVariableArrayType()) {
BasePointer = Pointer = *CV;
Size = getTypeSize(CGF, RI->getType());
+ // Copy to the device as an argument. No need to retrieve it.
+ MapType = OMP_MAP_BYCOPY;
hasVLACaptures = true;
- // VLA sizes don't need to be copied back from the device.
- MapType = OMP_MAP_TO;
} else if (CI->capturesThis()) {
BasePointer = Pointer = *CV;
const PointerType *PtrTy = cast<PointerType>(RI->getType().getTypePtr());
Size = getTypeSize(CGF, PtrTy->getPointeeType());
// Default map type.
MapType = OMP_MAP_TO | OMP_MAP_FROM;
+ } else if (CI->capturesVariableByCopy()) {
+ MapType = OMP_MAP_BYCOPY;
+ if (!RI->getType()->isAnyPointerType()) {
+ // If the field is not a pointer, we need to save the actual value and
+ // load it as a void pointer.
+ auto DstAddr = CGF.CreateMemTemp(
+ Ctx.getUIntPtrType(),
+ Twine(CI->getCapturedVar()->getName()) + ".casted");
+ LValue DstLV = CGF.MakeAddrLValue(DstAddr, Ctx.getUIntPtrType());
+
+ auto *SrcAddrVal = CGF.EmitScalarConversion(
+ DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()),
+ Ctx.getPointerType(RI->getType()), SourceLocation());
+ LValue SrcLV =
+ CGF.MakeNaturalAlignAddrLValue(SrcAddrVal, RI->getType());
+
+ // Store the value using the source type pointer.
+ CGF.EmitStoreThroughLValue(RValue::get(*CV), SrcLV);
+
+ // Load the value using the destination type pointer.
+ BasePointer = Pointer =
+ CGF.EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
+ } else {
+ MapType |= OMP_MAP_PTR;
+ BasePointer = Pointer = *CV;
+ }
+ Size = getTypeSize(CGF, RI->getType());
} else {
+ assert(CI->capturesVariable() && "Expected captured reference.");
BasePointer = Pointer = *CV;
const ReferenceType *PtrTy =
cast<ReferenceType>(RI->getType().getTypePtr());
QualType ElementType = PtrTy->getPointeeType();
Size = getTypeSize(CGF, ElementType);
- // Default map type.
- MapType = OMP_MAP_TO | OMP_MAP_FROM;
+ // The default map type for a scalar/complex type is 'to' because by
+ // default the value doesn't have to be retrieved. For an aggregate type,
+ // the default is 'tofrom'.
+ MapType = ElementType->isAggregateType() ? (OMP_MAP_TO | OMP_MAP_FROM)
+ : OMP_MAP_TO;
+ if (ElementType->isAnyPointerType())
+ MapType |= OMP_MAP_PTR;
}
BasePointers.push_back(BasePointer);
@@ -3257,7 +3942,7 @@
// Keep track on whether the host function has to be executed.
auto OffloadErrorQType =
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true);
+ Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true);
auto OffloadError = CGF.MakeAddrLValue(
CGF.CreateMemTemp(OffloadErrorQType, ".run_host_version"),
OffloadErrorQType);
@@ -3265,8 +3950,8 @@
OffloadError);
// Fill up the pointer arrays and transfer execution to the device.
- auto &&ThenGen = [this, &BasePointers, &Pointers, &Sizes, &MapTypes,
- hasVLACaptures, Device, OffloadError,
+ auto &&ThenGen = [this, &Ctx, &BasePointers, &Pointers, &Sizes, &MapTypes,
+ hasVLACaptures, Device, OutlinedFnID, OffloadError,
OffloadErrorQType](CodeGenFunction &CGF) {
unsigned PointerNumVal = BasePointers.size();
llvm::Value *PointerNum = CGF.Builder.getInt32(PointerNumVal);
@@ -3277,8 +3962,8 @@
if (PointerNumVal) {
llvm::APInt PointerNumAP(32, PointerNumVal, /*isSigned=*/true);
- QualType PointerArrayType = CGF.getContext().getConstantArrayType(
- CGF.getContext().VoidPtrTy, PointerNumAP, ArrayType::Normal,
+ QualType PointerArrayType = Ctx.getConstantArrayType(
+ Ctx.VoidPtrTy, PointerNumAP, ArrayType::Normal,
/*IndexTypeQuals=*/0);
BasePointersArray =
@@ -3290,8 +3975,8 @@
// sizes, otherwise we need to fill up the arrays as we do for the
// pointers.
if (hasVLACaptures) {
- QualType SizeArrayType = CGF.getContext().getConstantArrayType(
- CGF.getContext().getSizeType(), PointerNumAP, ArrayType::Normal,
+ QualType SizeArrayType = Ctx.getConstantArrayType(
+ Ctx.getSizeType(), PointerNumAP, ArrayType::Normal,
/*IndexTypeQuals=*/0);
SizesArray =
CGF.CreateMemTemp(SizeArrayType, ".offload_sizes").getPointer();
@@ -3324,29 +4009,41 @@
MapTypesArray = MapTypesArrayGbl;
for (unsigned i = 0; i < PointerNumVal; ++i) {
+
+ llvm::Value *BPVal = BasePointers[i];
+ if (BPVal->getType()->isPointerTy())
+ BPVal = CGF.Builder.CreateBitCast(BPVal, CGM.VoidPtrTy);
+ else {
+ assert(BPVal->getType()->isIntegerTy() &&
+ "If not a pointer, the value type must be an integer.");
+ BPVal = CGF.Builder.CreateIntToPtr(BPVal, CGM.VoidPtrTy);
+ }
llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, PointerNumVal),
BasePointersArray, 0, i);
- Address BPAddr(BP, CGM.getContext().getTypeAlignInChars(
- CGM.getContext().VoidPtrTy));
- CGF.Builder.CreateStore(
- CGF.Builder.CreateBitCast(BasePointers[i], CGM.VoidPtrTy), BPAddr);
+ Address BPAddr(BP, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
+ CGF.Builder.CreateStore(BPVal, BPAddr);
+ llvm::Value *PVal = Pointers[i];
+ if (PVal->getType()->isPointerTy())
+ PVal = CGF.Builder.CreateBitCast(PVal, CGM.VoidPtrTy);
+ else {
+ assert(PVal->getType()->isIntegerTy() &&
+ "If not a pointer, the value type must be an integer.");
+ PVal = CGF.Builder.CreateIntToPtr(PVal, CGM.VoidPtrTy);
+ }
llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, PointerNumVal), PointersArray,
0, i);
- Address PAddr(P, CGM.getContext().getTypeAlignInChars(
- CGM.getContext().VoidPtrTy));
- CGF.Builder.CreateStore(
- CGF.Builder.CreateBitCast(Pointers[i], CGM.VoidPtrTy), PAddr);
+ Address PAddr(P, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
+ CGF.Builder.CreateStore(PVal, PAddr);
if (hasVLACaptures) {
llvm::Value *S = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.SizeTy, PointerNumVal), SizesArray,
/*Idx0=*/0,
/*Idx1=*/i);
- Address SAddr(S, CGM.getContext().getTypeAlignInChars(
- CGM.getContext().getSizeType()));
+ Address SAddr(S, Ctx.getTypeAlignInChars(Ctx.getSizeType()));
CGF.Builder.CreateStore(CGF.Builder.CreateIntCast(
Sizes[i], CGM.SizeTy, /*isSigned=*/true),
SAddr);
@@ -3385,10 +4082,8 @@
// compiler doesn't need to keep that, and could therefore inline the host
// function if proven worthwhile during optimization.
- llvm::Value *HostPtr = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), ".offload_hstptr");
+ // From this point on, we need to have an ID of the target region defined.
+ assert(OutlinedFnID && "Invalid outlined function ID!");
// Emit device ID if any.
llvm::Value *DeviceID;
@@ -3399,25 +4094,35 @@
DeviceID = CGF.Builder.getInt32(OMP_DEVICEID_UNDEF);
llvm::Value *OffloadingArgs[] = {
- DeviceID, HostPtr, PointerNum, BasePointersArray,
- PointersArray, SizesArray, MapTypesArray};
+ DeviceID, OutlinedFnID, PointerNum, BasePointersArray,
+ PointersArray, SizesArray, MapTypesArray};
auto Return = CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_target),
OffloadingArgs);
CGF.EmitStoreOfScalar(Return, OffloadError);
};
- if (IfCond) {
- // Notify that the host version must be executed.
- auto &&ElseGen = [this, OffloadError,
- OffloadErrorQType](CodeGenFunction &CGF) {
- CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/-1u),
- OffloadError);
- };
- emitOMPIfClause(CGF, IfCond, ThenGen, ElseGen);
+ // Notify that the host version must be executed.
+ auto &&ElseGen = [this, OffloadError,
+ OffloadErrorQType](CodeGenFunction &CGF) {
+ CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/-1u),
+ OffloadError);
+ };
+
+ // If we have a target function ID it means that we need to support
+ // offloading, otherwise, just execute on the host. We need to execute on host
+ // regardless of the conditional in the if clause if, e.g., the user do not
+ // specify target triples.
+ if (OutlinedFnID) {
+ if (IfCond) {
+ emitOMPIfClause(CGF, IfCond, ThenGen, ElseGen);
+ } else {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ ThenGen(CGF);
+ }
} else {
CodeGenFunction::RunCleanupsScope Scope(CGF);
- ThenGen(CGF);
+ ElseGen(CGF);
}
// Check the error code and execute the host version if required.
@@ -3434,3 +4139,120 @@
CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true);
return;
}
+
+void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
+ StringRef ParentName) {
+ if (!S)
+ return;
+
+ // If we find a OMP target directive, codegen the outline function and
+ // register the result.
+ // FIXME: Add other directives with target when they become supported.
+ bool isTargetDirective = isa<OMPTargetDirective>(S);
+
+ if (isTargetDirective) {
+ auto *E = cast<OMPExecutableDirective>(S);
+ unsigned DeviceID;
+ unsigned FileID;
+ unsigned Line;
+ unsigned Column;
+ getTargetEntryUniqueInfo(CGM.getContext(), E->getLocStart(), DeviceID,
+ FileID, Line, Column);
+
+ // Is this a target region that should not be emitted as an entry point? If
+ // so just signal we are done with this target region.
+ if (!OffloadEntriesInfoManager.hasTargetRegionEntryInfo(
+ DeviceID, FileID, ParentName, Line, Column))
+ return;
+
+ llvm::Function *Fn;
+ llvm::Constant *Addr;
+ emitTargetOutlinedFunction(*E, ParentName, Fn, Addr,
+ /*isOffloadEntry=*/true);
+ assert(Fn && Addr && "Target region emission failed.");
+ return;
+ }
+
+ if (const OMPExecutableDirective *E = dyn_cast<OMPExecutableDirective>(S)) {
+ if (!E->getAssociatedStmt())
+ return;
+
+ scanForTargetRegionsFunctions(
+ cast<CapturedStmt>(E->getAssociatedStmt())->getCapturedStmt(),
+ ParentName);
+ return;
+ }
+
+ // If this is a lambda function, look into its body.
+ if (auto *L = dyn_cast<LambdaExpr>(S))
+ S = L->getBody();
+
+ // Keep looking for target regions recursively.
+ for (auto *II : S->children())
+ scanForTargetRegionsFunctions(II, ParentName);
+
+ return;
+}
+
+bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
+ auto &FD = *cast<FunctionDecl>(GD.getDecl());
+
+ // If emitting code for the host, we do not process FD here. Instead we do
+ // the normal code generation.
+ if (!CGM.getLangOpts().OpenMPIsDevice)
+ return false;
+
+ // Try to detect target regions in the function.
+ scanForTargetRegionsFunctions(FD.getBody(), CGM.getMangledName(GD));
+
+ // We should not emit any function othen that the ones created during the
+ // scanning. Therefore, we signal that this function is completely dealt
+ // with.
+ return true;
+}
+
+bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
+ if (!CGM.getLangOpts().OpenMPIsDevice)
+ return false;
+
+ // Check if there are Ctors/Dtors in this declaration and look for target
+ // regions in it. We use the complete variant to produce the kernel name
+ // mangling.
+ QualType RDTy = cast<VarDecl>(GD.getDecl())->getType();
+ if (auto *RD = RDTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
+ for (auto *Ctor : RD->ctors()) {
+ StringRef ParentName =
+ CGM.getMangledName(GlobalDecl(Ctor, Ctor_Complete));
+ scanForTargetRegionsFunctions(Ctor->getBody(), ParentName);
+ }
+ auto *Dtor = RD->getDestructor();
+ if (Dtor) {
+ StringRef ParentName =
+ CGM.getMangledName(GlobalDecl(Dtor, Dtor_Complete));
+ scanForTargetRegionsFunctions(Dtor->getBody(), ParentName);
+ }
+ }
+
+ // If we are in target mode we do not emit any global (declare target is not
+ // implemented yet). Therefore we signal that GD was processed in this case.
+ return true;
+}
+
+bool CGOpenMPRuntime::emitTargetGlobal(GlobalDecl GD) {
+ auto *VD = GD.getDecl();
+ if (isa<FunctionDecl>(VD))
+ return emitTargetFunctions(GD);
+
+ return emitTargetGlobalVariable(GD);
+}
+
+llvm::Function *CGOpenMPRuntime::emitRegistrationFunction() {
+ // If we have offloading in the current module, we need to emit the entries
+ // now and register the offloading descriptor.
+ createOffloadEntriesAndInfoMetadata();
+
+ // Create and register the offloading binary descriptors. This is the main
+ // entity that captures all the information about offloading in the current
+ // compilation unit.
+ return createOffloadingBinaryDescriptorRegistration();
+}
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index dc4238c..b325637 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -35,6 +35,7 @@
namespace clang {
class Expr;
+class GlobalDecl;
class OMPExecutableDirective;
class VarDecl;
@@ -62,6 +63,9 @@
// Call to void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
// kmp_critical_name *crit);
OMPRTL__kmpc_critical,
+ // Call to void __kmpc_critical_with_hint(ident_t *loc, kmp_int32
+ // global_tid, kmp_critical_name *crit, uintptr_t hint);
+ OMPRTL__kmpc_critical_with_hint,
// Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
// kmp_critical_name *crit);
OMPRTL__kmpc_end_critical,
@@ -162,6 +166,10 @@
// arg_num, void** args_base, void **args, size_t *arg_sizes, int32_t
// *arg_types);
OMPRTL__tgt_target,
+ // Call to void __tgt_register_lib(__tgt_bin_desc *desc);
+ OMPRTL__tgt_register_lib,
+ // Call to void __tgt_unregister_lib(__tgt_bin_desc *desc);
+ OMPRTL__tgt_unregister_lib,
};
/// \brief Values for bit flags used in the ident_t to describe the fields.
@@ -285,7 +293,181 @@
/// } flags;
/// } kmp_depend_info_t;
QualType KmpDependInfoTy;
+ /// \brief Type struct __tgt_offload_entry{
+ /// void *addr; // Pointer to the offload entry info.
+ /// // (function or global)
+ /// char *name; // Name of the function or global.
+ /// size_t size; // Size of the entry info (0 if it a function).
+ /// };
+ QualType TgtOffloadEntryQTy;
+ /// struct __tgt_device_image{
+ /// void *ImageStart; // Pointer to the target code start.
+ /// void *ImageEnd; // Pointer to the target code end.
+ /// // We also add the host entries to the device image, as it may be useful
+ /// // for the target runtime to have access to that information.
+ /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all
+ /// // the entries.
+ /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
+ /// // entries (non inclusive).
+ /// };
+ QualType TgtDeviceImageQTy;
+ /// struct __tgt_bin_desc{
+ /// int32_t NumDevices; // Number of devices supported.
+ /// __tgt_device_image *DeviceImages; // Arrays of device images
+ /// // (one per device).
+ /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all the
+ /// // entries.
+ /// __tgt_offload_entry *EntriesEnd; // End of the table with all the
+ /// // entries (non inclusive).
+ /// };
+ QualType TgtBinaryDescriptorQTy;
+ /// \brief Entity that registers the offloading constants that were emitted so
+ /// far.
+ class OffloadEntriesInfoManagerTy {
+ CodeGenModule &CGM;
+ /// \brief Number of entries registered so far.
+ unsigned OffloadingEntriesNum;
+
+ public:
+ /// \brief Base class of the entries info.
+ class OffloadEntryInfo {
+ public:
+ /// \brief Kind of a given entry. Currently, only target regions are
+ /// supported.
+ enum OffloadingEntryInfoKinds : unsigned {
+ // Entry is a target region.
+ OFFLOAD_ENTRY_INFO_TARGET_REGION = 0,
+ // Invalid entry info.
+ OFFLOAD_ENTRY_INFO_INVALID = ~0u
+ };
+
+ OffloadEntryInfo() : Order(~0u), Kind(OFFLOAD_ENTRY_INFO_INVALID) {}
+ explicit OffloadEntryInfo(OffloadingEntryInfoKinds Kind, unsigned Order)
+ : Order(Order), Kind(Kind) {}
+
+ bool isValid() const { return Order != ~0u; }
+ unsigned getOrder() const { return Order; }
+ OffloadingEntryInfoKinds getKind() const { return Kind; }
+ static bool classof(const OffloadEntryInfo *Info) { return true; }
+
+ protected:
+ // \brief Order this entry was emitted.
+ unsigned Order;
+
+ OffloadingEntryInfoKinds Kind;
+ };
+
+ /// \brief Return true if a there are no entries defined.
+ bool empty() const;
+ /// \brief Return number of entries defined so far.
+ unsigned size() const { return OffloadingEntriesNum; }
+ OffloadEntriesInfoManagerTy(CodeGenModule &CGM)
+ : CGM(CGM), OffloadingEntriesNum(0) {}
+
+ ///
+ /// Target region entries related.
+ ///
+ /// \brief Target region entries info.
+ class OffloadEntryInfoTargetRegion : public OffloadEntryInfo {
+ // \brief Address of the entity that has to be mapped for offloading.
+ llvm::Constant *Addr;
+ // \brief Address that can be used as the ID of the entry.
+ llvm::Constant *ID;
+
+ public:
+ OffloadEntryInfoTargetRegion()
+ : OffloadEntryInfo(OFFLOAD_ENTRY_INFO_TARGET_REGION, ~0u),
+ Addr(nullptr), ID(nullptr) {}
+ explicit OffloadEntryInfoTargetRegion(unsigned Order,
+ llvm::Constant *Addr,
+ llvm::Constant *ID)
+ : OffloadEntryInfo(OFFLOAD_ENTRY_INFO_TARGET_REGION, Order),
+ Addr(Addr), ID(ID) {}
+
+ llvm::Constant *getAddress() const { return Addr; }
+ llvm::Constant *getID() const { return ID; }
+ void setAddress(llvm::Constant *V) {
+ assert(!Addr && "Address as been set before!");
+ Addr = V;
+ }
+ void setID(llvm::Constant *V) {
+ assert(!ID && "ID as been set before!");
+ ID = V;
+ }
+ static bool classof(const OffloadEntryInfo *Info) {
+ return Info->getKind() == OFFLOAD_ENTRY_INFO_TARGET_REGION;
+ }
+ };
+ /// \brief Initialize target region entry.
+ void initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
+ StringRef ParentName, unsigned LineNum,
+ unsigned ColNum, unsigned Order);
+ /// \brief Register target region entry.
+ void registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
+ StringRef ParentName, unsigned LineNum,
+ unsigned ColNum, llvm::Constant *Addr,
+ llvm::Constant *ID);
+ /// \brief Return true if a target region entry with the provided
+ /// information exists.
+ bool hasTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
+ StringRef ParentName, unsigned LineNum,
+ unsigned ColNum) const;
+ /// brief Applies action \a Action on all registered entries.
+ typedef llvm::function_ref<void(unsigned, unsigned, StringRef, unsigned,
+ unsigned, OffloadEntryInfoTargetRegion &)>
+ OffloadTargetRegionEntryInfoActTy;
+ void actOnTargetRegionEntriesInfo(
+ const OffloadTargetRegionEntryInfoActTy &Action);
+
+ private:
+ // Storage for target region entries kind. The storage is to be indexed by
+ // file ID, device ID, parent function name, lane number, and column number.
+ typedef llvm::DenseMap<unsigned, OffloadEntryInfoTargetRegion>
+ OffloadEntriesTargetRegionPerColumn;
+ typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerColumn>
+ OffloadEntriesTargetRegionPerLine;
+ typedef llvm::StringMap<OffloadEntriesTargetRegionPerLine>
+ OffloadEntriesTargetRegionPerParentName;
+ typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerParentName>
+ OffloadEntriesTargetRegionPerFile;
+ typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerFile>
+ OffloadEntriesTargetRegionPerDevice;
+ typedef OffloadEntriesTargetRegionPerDevice OffloadEntriesTargetRegionTy;
+ OffloadEntriesTargetRegionTy OffloadEntriesTargetRegion;
+ };
+ OffloadEntriesInfoManagerTy OffloadEntriesInfoManager;
+
+ /// \brief Creates and registers offloading binary descriptor for the current
+ /// compilation unit. The function that does the registration is returned.
+ llvm::Function *createOffloadingBinaryDescriptorRegistration();
+
+ /// \brief Creates offloading entry for the provided address \a Addr,
+ /// name \a Name and size \a Size.
+ void createOffloadEntry(llvm::Constant *Addr, StringRef Name, uint64_t Size);
+
+ /// \brief Creates all the offload entries in the current compilation unit
+ /// along with the associated metadata.
+ void createOffloadEntriesAndInfoMetadata();
+
+ /// \brief Loads all the offload entries information from the host IR
+ /// metadata.
+ void loadOffloadInfoMetadata();
+
+ /// \brief Returns __tgt_offload_entry type.
+ QualType getTgtOffloadEntryQTy();
+
+ /// \brief Returns __tgt_device_image type.
+ QualType getTgtDeviceImageQTy();
+
+ /// \brief Returns __tgt_bin_desc type.
+ QualType getTgtBinaryDescriptorQTy();
+
+ /// \brief Start scanning from statement \a S and and emit all target regions
+ /// found along the way.
+ /// \param S Starting statement.
+ /// \param ParentName Name of the function declaration that is being scanned.
+ void scanForTargetRegionsFunctions(const Stmt *S, StringRef ParentName);
/// \brief Build type kmp_routine_entry_t (if not built yet).
void emitKmpRoutineEntryT(QualType KmpInt32Ty);
@@ -420,9 +602,11 @@
/// \param CriticalName Name of the critical region.
/// \param CriticalOpGen Generator for the statement associated with the given
/// critical region.
+ /// \param Hint Value of the 'hint' clause (optional).
virtual void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName,
const RegionCodeGenTy &CriticalOpGen,
- SourceLocation Loc);
+ SourceLocation Loc,
+ const Expr *Hint = nullptr);
/// \brief Emits a master region.
/// \param MasterOpGen Generator for the statement associated with the given
@@ -738,16 +922,24 @@
/// \brief Emit outilined function for 'target' directive.
/// \param D Directive to emit.
- /// \param CodeGen Code generation sequence for the \a D directive.
- virtual llvm::Value *
- emitTargetOutlinedFunction(const OMPExecutableDirective &D,
- const RegionCodeGenTy &CodeGen);
+ /// \param ParentName Name of the function that encloses the target region.
+ /// \param OutlinedFn Outlined function value to be defined by this call.
+ /// \param OutlinedFnID Outlined function ID value to be defined by this call.
+ /// \param IsOffloadEntry True if the outlined function is an offload entry.
+ /// An oulined function may not be an entry if, e.g. the if clause always
+ /// evaluates to false.
+ virtual void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
+ StringRef ParentName,
+ llvm::Function *&OutlinedFn,
+ llvm::Constant *&OutlinedFnID,
+ bool IsOffloadEntry);
/// \brief Emit the target offloading code associated with \a D. The emitted
/// code attempts offloading the execution to the device, an the event of
/// a failure it executes the host version outlined in \a OutlinedFn.
/// \param D Directive to emit.
/// \param OutlinedFn Host version of the code to be offloaded.
+ /// \param OutlinedFnID ID of host version of the code to be offloaded.
/// \param IfCond Expression evaluated in if clause associated with the target
/// directive, or null if no if clause is used.
/// \param Device Expression evaluated in device clause associated with the
@@ -755,9 +947,31 @@
/// \param CapturedVars Values captured in the current region.
virtual void emitTargetCall(CodeGenFunction &CGF,
const OMPExecutableDirective &D,
- llvm::Value *OutlinedFn, const Expr *IfCond,
+ llvm::Value *OutlinedFn,
+ llvm::Value *OutlinedFnID, const Expr *IfCond,
const Expr *Device,
ArrayRef<llvm::Value *> CapturedVars);
+
+ /// \brief Emit the target regions enclosed in \a GD function definition or
+ /// the function itself in case it is a valid device function. Returns true if
+ /// \a GD was dealt with successfully.
+ /// \param GD Function to scan.
+ virtual bool emitTargetFunctions(GlobalDecl GD);
+
+ /// \brief Emit the global variable if it is a valid device global variable.
+ /// Returns true if \a GD was dealt with successfully.
+ /// \param GD Variable declaration to emit.
+ virtual bool emitTargetGlobalVariable(GlobalDecl GD);
+
+ /// \brief Emit the global \a GD if it is meaningful for the target. Returns
+ /// if it was emitted succesfully.
+ /// \param GD Global to scan.
+ virtual bool emitTargetGlobal(GlobalDecl GD);
+
+ /// \brief Creates the offloading descriptor in the event any target region
+ /// was emitted in the current module and return the function that registers
+ /// it.
+ virtual llvm::Function *emitRegistrationFunction();
};
} // namespace CodeGen
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 375b59c..d0381ef 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -121,7 +121,7 @@
/// \brief Wraps llvm::Type::getIntNTy with some implicit arguments.
llvm::Type *getIntNType(uint64_t NumBits) {
return llvm::Type::getIntNTy(Types.getLLVMContext(),
- (unsigned)llvm::RoundUpToAlignment(NumBits, 8));
+ (unsigned)llvm::alignTo(NumBits, 8));
}
/// \brief Gets an llvm type of size NumBytes and alignment 1.
llvm::Type *getByteArrayType(CharUnits NumBytes) {
@@ -555,7 +555,7 @@
if (Member->Offset < Tail) {
assert(Prior->Kind == MemberInfo::Field && !Prior->FD &&
"Only storage fields have tail padding!");
- Prior->Data = getByteArrayType(bitsToCharUnits(llvm::RoundUpToAlignment(
+ Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
}
if (Member->Data)
@@ -609,8 +609,8 @@
CharUnits Offset = Member->Offset;
assert(Offset >= Size);
// Insert padding if we need to.
- if (Offset != Size.RoundUpToAlignment(Packed ? CharUnits::One() :
- getAlignment(Member->Data)))
+ if (Offset !=
+ Size.alignTo(Packed ? CharUnits::One() : getAlignment(Member->Data)))
Padding.push_back(std::make_pair(Size, Offset - Size));
Size = Offset + getSize(Member->Data);
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 7c4fb41..cc4fa2e 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -256,6 +256,15 @@
case Stmt::OMPTargetDataDirectiveClass:
EmitOMPTargetDataDirective(cast<OMPTargetDataDirective>(*S));
break;
+ case Stmt::OMPTaskLoopDirectiveClass:
+ EmitOMPTaskLoopDirective(cast<OMPTaskLoopDirective>(*S));
+ break;
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
+ break;
+case Stmt::OMPDistributeDirectiveClass:
+ EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
+ break;
}
}
@@ -1687,7 +1696,8 @@
if (Info.allowsRegister() || !Info.allowsMemory())
if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return EmitScalarExpr(InputExpr);
-
+ if (InputExpr->getStmtClass() == Expr::CXXThisExprClass)
+ return EmitScalarExpr(InputExpr);
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
@@ -1708,13 +1718,15 @@
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
const LangOptions &LangOpts = CGF.CGM.getLangOpts();
+ unsigned StartToken = 0;
+ unsigned ByteOffset = 0;
// Add the location of the start of each subsequent line of the asm to the
// MDNode.
- for (unsigned i = 0, e = StrVal.size()-1; i != e; ++i) {
+ for (unsigned i = 0, e = StrVal.size() - 1; i != e; ++i) {
if (StrVal[i] != '\n') continue;
- SourceLocation LineLoc = Str->getLocationOfByte(i+1, SM, LangOpts,
- CGF.getTarget());
+ SourceLocation LineLoc = Str->getLocationOfByte(
+ i + 1, SM, LangOpts, CGF.getTarget(), &StartToken, &ByteOffset);
Locs.push_back(llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(CGF.Int32Ty, LineLoc.getRawEncoding())));
}
@@ -1991,6 +2003,15 @@
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoUnwind);
+ if (isa<MSAsmStmt>(&S)) {
+ // If the assembly contains any labels, mark the call noduplicate to prevent
+ // defining the same ASM label twice (PR23715). This is pretty hacky, but it
+ // works.
+ if (AsmString.find("__MSASMLABEL_") != std::string::npos)
+ Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoDuplicate);
+ }
+
// Attach readnone and readonly attributes.
if (!HasSideEffect) {
if (ReadNone)
@@ -2164,7 +2185,7 @@
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
- PGO.assignRegionCounters(CD, F);
+ PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 557fe10..bf00b04 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -21,8 +21,7 @@
using namespace CodeGen;
void CodeGenFunction::GenerateOpenMPCapturedVars(
- const CapturedStmt &S, SmallVectorImpl<llvm::Value *> &CapturedVars,
- bool UseOnlyReferences) {
+ const CapturedStmt &S, SmallVectorImpl<llvm::Value *> &CapturedVars) {
const RecordDecl *RD = S.getCapturedRecordDecl();
auto CurField = RD->field_begin();
auto CurCap = S.captures().begin();
@@ -32,26 +31,46 @@
if (CurField->hasCapturedVLAType()) {
auto VAT = CurField->getCapturedVLAType();
auto *Val = VLASizeMap[VAT->getSizeExpr()];
- // If we need to use only references, create a temporary location for the
- // size of the VAT.
- if (UseOnlyReferences) {
- LValue LV =
- MakeAddrLValue(CreateMemTemp(CurField->getType(), "__vla_size_ref"),
- CurField->getType());
- EmitStoreThroughLValue(RValue::get(Val), LV);
- Val = LV.getAddress().getPointer();
- }
CapturedVars.push_back(Val);
} else if (CurCap->capturesThis())
CapturedVars.push_back(CXXThisValue);
- else
+ else if (CurCap->capturesVariableByCopy())
+ CapturedVars.push_back(
+ EmitLoadOfLValue(EmitLValue(*I), SourceLocation()).getScalarVal());
+ else {
+ assert(CurCap->capturesVariable() && "Expected capture by reference.");
CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer());
+ }
}
}
+static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType,
+ StringRef Name, LValue AddrLV,
+ bool isReferenceType = false) {
+ ASTContext &Ctx = CGF.getContext();
+
+ auto *CastedPtr = CGF.EmitScalarConversion(
+ AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(),
+ Ctx.getPointerType(DstType), SourceLocation());
+ auto TmpAddr =
+ CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType))
+ .getAddress();
+
+ // If we are dealing with references we need to return the address of the
+ // reference instead of the reference of the value.
+ if (isReferenceType) {
+ QualType RefType = Ctx.getLValueReferenceType(DstType);
+ auto *RefVal = TmpAddr.getPointer();
+ TmpAddr = CGF.CreateMemTemp(RefType, Twine(Name) + ".ref");
+ auto TmpLVal = CGF.MakeAddrLValue(TmpAddr, RefType);
+ CGF.EmitScalarInit(RefVal, TmpLVal);
+ }
+
+ return TmpAddr;
+}
+
llvm::Function *
-CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S,
- bool UseOnlyReferences) {
+CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
assert(
CapturedStmtInfo &&
"CapturedStmtInfo should be set when generating the captured function");
@@ -69,7 +88,17 @@
QualType ArgType = FD->getType();
IdentifierInfo *II = nullptr;
VarDecl *CapVar = nullptr;
- if (I->capturesVariable()) {
+
+ // If this is a capture by copy and the type is not a pointer, the outlined
+ // function argument type should be uintptr and the value properly casted to
+ // uintptr. This is necessary given that the runtime library is only able to
+ // deal with pointers. We can pass in the same way the VLA type sizes to the
+ // outlined function.
+ if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
+ I->capturesVariableArrayType())
+ ArgType = Ctx.getUIntPtrType();
+
+ if (I->capturesVariable() || I->capturesVariableByCopy()) {
CapVar = I->getCapturedVar();
II = CapVar->getIdentifier();
} else if (I->capturesThis())
@@ -77,9 +106,6 @@
else {
assert(I->capturesVariableArrayType());
II = &getContext().Idents.get("vla");
- if (UseOnlyReferences)
- ArgType = getContext().getLValueReferenceType(
- ArgType, /*SpelledAsLValue=*/false);
}
if (ArgType->isVariablyModifiedType())
ArgType = getContext().getVariableArrayDecayedType(ArgType);
@@ -111,15 +137,24 @@
unsigned Cnt = CD->getContextParamPosition();
I = S.captures().begin();
for (auto *FD : RD->fields()) {
+ // If we are capturing a pointer by copy we don't need to do anything, just
+ // use the value that we get from the arguments.
+ if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
+ setAddrOfLocalVar(I->getCapturedVar(), GetAddrOfLocalVar(Args[Cnt]));
+ ++Cnt, ++I;
+ continue;
+ }
+
LValue ArgLVal =
MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(),
AlignmentSource::Decl);
if (FD->hasCapturedVLAType()) {
- if (UseOnlyReferences)
- ArgLVal = EmitLoadOfReferenceLValue(
- ArgLVal.getAddress(), ArgLVal.getType()->castAs<ReferenceType>());
+ LValue CastedArgLVal =
+ MakeAddrLValue(castValueFromUintptr(*this, FD->getType(),
+ Args[Cnt]->getName(), ArgLVal),
+ FD->getType(), AlignmentSource::Decl);
auto *ExprArg =
- EmitLoadOfLValue(ArgLVal, SourceLocation()).getScalarVal();
+ EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal();
auto VAT = FD->getCapturedVLAType();
VLASizeMap[VAT->getSizeExpr()] = ExprArg;
} else if (I->capturesVariable()) {
@@ -132,6 +167,15 @@
}
setAddrOfLocalVar(
Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var)));
+ } else if (I->capturesVariableByCopy()) {
+ assert(!FD->getType()->isAnyPointerType() &&
+ "Not expecting a captured pointer.");
+ auto *Var = I->getCapturedVar();
+ QualType VarTy = Var->getType();
+ setAddrOfLocalVar(I->getCapturedVar(),
+ castValueFromUintptr(*this, FD->getType(),
+ Args[Cnt]->getName(), ArgLVal,
+ VarTy->isReferenceType()));
} else {
// If 'this' is captured, load it into CXXThisValue.
assert(I->capturesThis());
@@ -141,7 +185,7 @@
++Cnt, ++I;
}
- PGO.assignRegionCounters(CD, F);
+ PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
@@ -310,6 +354,8 @@
bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
OMPPrivateScope &PrivateScope) {
+ if (!HaveInsertPoint())
+ return false;
llvm::DenseSet<const VarDecl *> EmittedAsFirstprivate;
for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
auto IRef = C->varlist_begin();
@@ -383,6 +429,8 @@
void CodeGenFunction::EmitOMPPrivateClause(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ if (!HaveInsertPoint())
+ return;
llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
for (const auto *C : D.getClausesOfKind<OMPPrivateClause>()) {
auto IRef = C->varlist_begin();
@@ -406,6 +454,8 @@
}
bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
+ if (!HaveInsertPoint())
+ return false;
// threadprivate_var1 = master_threadprivate_var1;
// operator=(threadprivate_var2, master_threadprivate_var2);
// ...
@@ -472,6 +522,8 @@
bool CodeGenFunction::EmitOMPLastprivateClauseInit(
const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) {
+ if (!HaveInsertPoint())
+ return false;
bool HasAtLeastOneLastprivate = false;
llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
@@ -516,6 +568,8 @@
void CodeGenFunction::EmitOMPLastprivateClauseFinal(
const OMPExecutableDirective &D, llvm::Value *IsLastIterCond) {
+ if (!HaveInsertPoint())
+ return;
// Emit following code:
// if (<IsLastIterCond>) {
// orig_var1 = private_orig_var1;
@@ -601,6 +655,8 @@
void CodeGenFunction::EmitOMPReductionClauseInit(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ if (!HaveInsertPoint())
+ return;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
@@ -757,6 +813,8 @@
void CodeGenFunction::EmitOMPReductionClauseFinal(
const OMPExecutableDirective &D) {
+ if (!HaveInsertPoint())
+ return;
llvm::SmallVector<const Expr *, 8> Privates;
llvm::SmallVector<const Expr *, 8> LHSExprs;
llvm::SmallVector<const Expr *, 8> RHSExprs;
@@ -835,10 +893,6 @@
(void)PrivateScope.Privatize();
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S);
- // Emit implicit barrier at the end of the 'parallel' directive.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
};
emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen);
}
@@ -919,6 +973,8 @@
}
void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
+ if (!HaveInsertPoint())
+ return;
// Emit inits for the linear variables.
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
for (auto Init : C->inits()) {
@@ -948,6 +1004,8 @@
static void emitLinearClauseFinal(CodeGenFunction &CGF,
const OMPLoopDirective &D) {
+ if (!CGF.HaveInsertPoint())
+ return;
// Emit the final values of the linear variables.
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
auto IC = C->varlist_begin();
@@ -969,6 +1027,8 @@
static void emitAlignedClause(CodeGenFunction &CGF,
const OMPExecutableDirective &D) {
+ if (!CGF.HaveInsertPoint())
+ return;
for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
unsigned ClauseAlignment = 0;
if (auto AlignmentExpr = Clause->getAlignment()) {
@@ -1002,6 +1062,8 @@
CodeGenFunction::OMPPrivateScope &LoopScope,
ArrayRef<Expr *> Counters,
ArrayRef<Expr *> PrivateCounters) {
+ if (!CGF.HaveInsertPoint())
+ return;
auto I = PrivateCounters.begin();
for (auto *E : Counters) {
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
@@ -1022,6 +1084,8 @@
static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock, uint64_t TrueCount) {
+ if (!CGF.HaveInsertPoint())
+ return;
{
CodeGenFunction::OMPPrivateScope PreCondScope(CGF);
emitPrivateLoopCounters(CGF, PreCondScope, S.counters(),
@@ -1039,6 +1103,8 @@
static void
emitPrivateLinearVars(CodeGenFunction &CGF, const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ if (!CGF.HaveInsertPoint())
+ return;
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
auto CurPrivate = C->privates().begin();
for (auto *E : C->varlists()) {
@@ -1059,7 +1125,10 @@
}
static void emitSimdlenSafelenClause(CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
+ const OMPExecutableDirective &D,
+ bool IsMonotonic) {
+ if (!CGF.HaveInsertPoint())
+ return;
if (const auto *C = D.getSingleClause<OMPSimdlenClause>()) {
RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
/*ignoreResult=*/true);
@@ -1068,7 +1137,8 @@
// In presence of finite 'safelen', it may be unsafe to mark all
// the memory instructions parallel, because loop-carried
// dependences of 'safelen' iterations are possible.
- CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
+ if (!IsMonotonic)
+ CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
} else if (const auto *C = D.getSingleClause<OMPSafelenClause>()) {
RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
/*ignoreResult=*/true);
@@ -1081,14 +1151,17 @@
}
}
-void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D) {
+void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D,
+ bool IsMonotonic) {
// Walk clauses and process safelen/lastprivate.
- LoopStack.setParallel();
+ LoopStack.setParallel(!IsMonotonic);
LoopStack.setVectorizeEnable(true);
- emitSimdlenSafelenClause(*this, D);
+ emitSimdlenSafelenClause(*this, D, IsMonotonic);
}
void CodeGenFunction::EmitOMPSimdFinal(const OMPLoopDirective &D) {
+ if (!HaveInsertPoint())
+ return;
auto IC = D.counters().begin();
for (auto F : D.finals()) {
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>((*IC))->getDecl());
@@ -1185,12 +1258,10 @@
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
-void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
- const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope,
- bool Ordered, Address LB,
- Address UB, Address ST,
- Address IL, llvm::Value *Chunk) {
+void CodeGenFunction::EmitOMPForOuterLoop(
+ OpenMPScheduleClauseKind ScheduleKind, bool IsMonotonic,
+ const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
+ Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
auto &RT = CGM.getOpenMPRuntime();
// Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
@@ -1308,13 +1379,10 @@
// Generate !llvm.loop.parallel metadata for loads and stores for loops
// with dynamic/guided scheduling and without ordered clause.
- if (!isOpenMPSimdDirective(S.getDirectiveKind())) {
- LoopStack.setParallel((ScheduleKind == OMPC_SCHEDULE_dynamic ||
- ScheduleKind == OMPC_SCHEDULE_guided) &&
- !Ordered);
- } else {
- EmitOMPSimdInit(S);
- }
+ if (!isOpenMPSimdDirective(S.getDirectiveKind()))
+ LoopStack.setParallel(!IsMonotonic);
+ else
+ EmitOMPSimdInit(S, IsMonotonic);
SourceLocation Loc = S.getLocStart();
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
@@ -1355,14 +1423,30 @@
return CGF.EmitLValue(Helper);
}
-static std::pair<llvm::Value * /*Chunk*/, OpenMPScheduleClauseKind>
+namespace {
+ struct ScheduleKindModifiersTy {
+ OpenMPScheduleClauseKind Kind;
+ OpenMPScheduleClauseModifier M1;
+ OpenMPScheduleClauseModifier M2;
+ ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind,
+ OpenMPScheduleClauseModifier M1,
+ OpenMPScheduleClauseModifier M2)
+ : Kind(Kind), M1(M1), M2(M2) {}
+ };
+} // namespace
+
+static std::pair<llvm::Value * /*Chunk*/, ScheduleKindModifiersTy>
emitScheduleClause(CodeGenFunction &CGF, const OMPLoopDirective &S,
bool OuterRegion) {
// Detect the loop schedule kind and chunk.
auto ScheduleKind = OMPC_SCHEDULE_unknown;
+ OpenMPScheduleClauseModifier M1 = OMPC_SCHEDULE_MODIFIER_unknown;
+ OpenMPScheduleClauseModifier M2 = OMPC_SCHEDULE_MODIFIER_unknown;
llvm::Value *Chunk = nullptr;
if (const auto *C = S.getSingleClause<OMPScheduleClause>()) {
ScheduleKind = C->getScheduleKind();
+ M1 = C->getFirstScheduleModifier();
+ M2 = C->getSecondScheduleModifier();
if (const auto *Ch = C->getChunkSize()) {
if (auto *ImpRef = cast_or_null<DeclRefExpr>(C->getHelperChunkSize())) {
if (OuterRegion) {
@@ -1384,7 +1468,7 @@
}
}
}
- return std::make_pair(Chunk, ScheduleKind);
+ return std::make_pair(Chunk, ScheduleKindModifiersTy(ScheduleKind, M1, M2));
}
bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
@@ -1460,16 +1544,21 @@
auto ScheduleInfo =
emitScheduleClause(*this, S, /*OuterRegion=*/false);
Chunk = ScheduleInfo.first;
- ScheduleKind = ScheduleInfo.second;
+ ScheduleKind = ScheduleInfo.second.Kind;
+ const OpenMPScheduleClauseModifier M1 = ScheduleInfo.second.M1;
+ const OpenMPScheduleClauseModifier M2 = ScheduleInfo.second.M2;
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
const bool Ordered = S.getSingleClause<OMPOrderedClause>() != nullptr;
+ // OpenMP 4.5, 2.7.1 Loop Construct, Description.
+ // If the static schedule kind is specified or if the ordered clause is
+ // specified, and if no monotonic modifier is specified, the effect will
+ // be as if the monotonic modifier was specified.
if (RT.isStaticNonchunked(ScheduleKind,
/* Chunked */ Chunk != nullptr) &&
!Ordered) {
- if (isOpenMPSimdDirective(S.getDirectiveKind())) {
- EmitOMPSimdInit(S);
- }
+ if (isOpenMPSimdDirective(S.getDirectiveKind()))
+ EmitOMPSimdInit(S, /*IsMonotonic=*/true);
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
// When no chunk_size is specified, the iteration space is divided into
// chunks that are approximately equal in size, and at most one chunk is
@@ -1479,7 +1568,8 @@
IVSize, IVSigned, Ordered,
IL.getAddress(), LB.getAddress(),
UB.getAddress(), ST.getAddress());
- auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
+ auto LoopExit =
+ getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
EmitIgnoredExpr(S.getEnsureUpperBound());
// IV = LB;
@@ -1496,9 +1586,14 @@
// Tell the runtime we are done.
RT.emitForStaticFinish(*this, S.getLocStart());
} else {
+ const bool IsMonotonic = Ordered ||
+ ScheduleKind == OMPC_SCHEDULE_static ||
+ ScheduleKind == OMPC_SCHEDULE_unknown ||
+ M1 == OMPC_SCHEDULE_MODIFIER_monotonic ||
+ M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
- EmitOMPForOuterLoop(ScheduleKind, S, LoopScope, Ordered,
+ EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
LB.getAddress(), UB.getAddress(), ST.getAddress(),
IL.getAddress(), Chunk);
}
@@ -1723,7 +1818,6 @@
LexicalScope Scope(*this, S.getSourceRange());
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EnsureInsertPoint();
};
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_section, CodeGen,
S.hasCancel());
@@ -1757,7 +1851,6 @@
(void)SingleScope.Privatize();
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EnsureInsertPoint();
};
CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(),
CopyprivateVars, DestExprs, SrcExprs,
@@ -1776,7 +1869,6 @@
LexicalScope Scope(*this, S.getSourceRange());
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EnsureInsertPoint();
};
CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getLocStart());
}
@@ -1785,10 +1877,13 @@
LexicalScope Scope(*this, S.getSourceRange());
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EnsureInsertPoint();
};
- CGM.getOpenMPRuntime().emitCriticalRegion(
- *this, S.getDirectiveName().getAsString(), CodeGen, S.getLocStart());
+ Expr *Hint = nullptr;
+ if (auto *HintClause = S.getSingleClause<OMPHintClause>())
+ Hint = HintClause->getHint();
+ CGM.getOpenMPRuntime().emitCriticalRegion(*this,
+ S.getDirectiveName().getAsString(),
+ CodeGen, S.getLocStart(), Hint);
}
void CodeGenFunction::EmitOMPParallelForDirective(
@@ -1799,12 +1894,6 @@
(void)emitScheduleClause(*this, S, /*OuterRegion=*/true);
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitOMPWorksharingLoop(S);
- // Emit implicit barrier at the end of parallel region, but this barrier
- // is at the end of 'for' directive, so emit it as the implicit barrier for
- // this 'for' directive.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getLocStart(), OMPD_parallel, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
};
emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen);
}
@@ -1817,12 +1906,6 @@
(void)emitScheduleClause(*this, S, /*OuterRegion=*/true);
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitOMPWorksharingLoop(S);
- // Emit implicit barrier at the end of parallel region, but this barrier
- // is at the end of 'for' directive, so emit it as the implicit barrier for
- // this 'for' directive.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getLocStart(), OMPD_parallel, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
};
emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen);
}
@@ -1834,10 +1917,6 @@
LexicalScope Scope(*this, S.getSourceRange());
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
(void)CGF.EmitSections(S);
- // Emit implicit barrier at the end of parallel region.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getLocStart(), OMPD_parallel, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
};
emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen);
}
@@ -1986,7 +2065,6 @@
LexicalScope Scope(*this, S.getSourceRange());
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EnsureInsertPoint();
};
CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getLocStart());
}
@@ -2001,6 +2079,11 @@
}(), S.getLocStart());
}
+void CodeGenFunction::EmitOMPDistributeDirective(
+ const OMPDistributeDirective &S) {
+ llvm_unreachable("CodeGen for 'omp distribute' is not supported yet.");
+}
+
static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM,
const CapturedStmt *S) {
CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
@@ -2012,6 +2095,8 @@
}
void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
+ if (!S.getAssociatedStmt())
+ return;
LexicalScope Scope(*this, S.getSourceRange());
auto *C = S.getSingleClause<OMPSIMDClause>();
auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF) {
@@ -2025,7 +2110,6 @@
CGF.EmitStmt(
cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
}
- CGF.EnsureInsertPoint();
};
CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getLocStart(), !C);
}
@@ -2433,6 +2517,15 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_map:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_dist_schedule:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
@@ -2463,7 +2556,8 @@
}
LexicalScope Scope(*this, S.getSourceRange());
- auto &&CodeGen = [&S, Kind, IsSeqCst](CodeGenFunction &CGF) {
+ auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF) {
+ CGF.EmitStopPoint(CS);
EmitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(),
S.getV(), S.getExpr(), S.getUpdateExpr(),
S.isXLHSInRHSPart(), S.getLocStart());
@@ -2476,16 +2570,10 @@
const CapturedStmt &CS = *cast<CapturedStmt>(S.getAssociatedStmt());
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- GenerateOpenMPCapturedVars(CS, CapturedVars, /*UseOnlyReferences=*/true);
+ GenerateOpenMPCapturedVars(CS, CapturedVars);
- // Emit target region as a standalone region.
- auto &&CodeGen = [&CS](CodeGenFunction &CGF) {
- CGF.EmitStmt(CS.getCapturedStmt());
- };
-
- // Obtain the target region outlined function.
- llvm::Value *Fn =
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, CodeGen);
+ llvm::Function *Fn = nullptr;
+ llvm::Constant *FnID = nullptr;
// Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
@@ -2500,7 +2588,34 @@
Device = C->getDevice();
}
- CGM.getOpenMPRuntime().emitTargetCall(*this, S, Fn, IfCond, Device,
+ // Check if we have an if clause whose conditional always evaluates to false
+ // or if we do not have any targets specified. If so the target region is not
+ // an offload entry point.
+ bool IsOffloadEntry = true;
+ if (IfCond) {
+ bool Val;
+ if (ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
+ IsOffloadEntry = false;
+ }
+ if (CGM.getLangOpts().OMPTargetTriples.empty())
+ IsOffloadEntry = false;
+
+ assert(CurFuncDecl && "No parent declaration for target region!");
+ StringRef ParentName;
+ // In case we have Ctors/Dtors we use the complete type variant to produce
+ // the mangling of the device outlined kernel.
+ if (auto *D = dyn_cast<CXXConstructorDecl>(CurFuncDecl))
+ ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
+ else if (auto *D = dyn_cast<CXXDestructorDecl>(CurFuncDecl))
+ ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
+ else
+ ParentName =
+ CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CurFuncDecl)));
+
+ CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
+ IsOffloadEntry);
+
+ CGM.getOpenMPRuntime().emitTargetCall(*this, S, Fn, FnID, IfCond, Device,
CapturedVars);
}
@@ -2539,10 +2654,27 @@
// Generate the instructions for '#pragma omp target data' directive.
void CodeGenFunction::EmitOMPTargetDataDirective(
const OMPTargetDataDirective &S) {
-
// emit the code inside the construct for now
auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
CGM.getOpenMPRuntime().emitInlinedDirective(
*this, OMPD_target_data,
[&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); });
}
+
+void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
+ // emit the code inside the construct for now
+ auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ CGM.getOpenMPRuntime().emitInlinedDirective(
+ *this, OMPD_taskloop,
+ [&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); });
+}
+
+void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
+ const OMPTaskLoopSimdDirective &S) {
+ // emit the code inside the construct for now
+ auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ CGM.getOpenMPRuntime().emitInlinedDirective(
+ *this, OMPD_taskloop_simd,
+ [&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); });
+}
+
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 3d8c41c..a40aab2 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -378,8 +378,8 @@
// Apply the standard set of call attributes.
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(*CurFnInfo, MD, AttributeList, CallingConv,
- /*AttrOnCallSite=*/true);
+ CGM.ConstructAttributeList(Callee->getName(), *CurFnInfo, MD, AttributeList,
+ CallingConv, /*AttrOnCallSite=*/true);
llvm::AttributeSet Attrs =
llvm::AttributeSet::get(getLLVMContext(), AttributeList);
Call->setAttributes(Attrs);
@@ -582,6 +582,24 @@
break;
}
+ if (CGM.getLangOpts().CUDA) {
+ // Emit NULL for methods we can't codegen on this
+ // side. Otherwise we'd end up with vtable with unresolved
+ // references.
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ // OK on device side: functions w/ __device__ attribute
+ // OK on host side: anything except __device__-only functions.
+ bool CanEmitMethod = CGM.getLangOpts().CUDAIsDevice
+ ? MD->hasAttr<CUDADeviceAttr>()
+ : (MD->hasAttr<CUDAHostAttr>() ||
+ !MD->hasAttr<CUDADeviceAttr>());
+ if (!CanEmitMethod) {
+ Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
+ break;
+ }
+ // Method is acceptable, continue processing as usual.
+ }
+
if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
// We have a pure virtual member function.
if (!PureVirtualFn) {
@@ -934,6 +952,7 @@
llvm::NamedMDNode *BitsetsMD =
getModule().getOrInsertNamedMetadata("llvm.bitsets");
for (auto BitsetEntry : BitsetEntries)
- BitsetsMD->addOperand(CreateVTableBitSetEntry(
- VTable, PointerWidth * BitsetEntry.second, BitsetEntry.first));
+ CreateVTableBitSetEntry(BitsetsMD, VTable,
+ PointerWidth * BitsetEntry.second,
+ BitsetEntry.first);
}
diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp
index 85495ee..643c996 100644
--- a/lib/CodeGen/CodeGenABITypes.cpp
+++ b/lib/CodeGen/CodeGenABITypes.cpp
@@ -44,8 +44,9 @@
}
const CGFunctionInfo &
-CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty) {
- return CGM->getTypes().arrangeFreeFunctionType(Ty);
+CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
+ const FunctionDecl *FD) {
+ return CGM->getTypes().arrangeFreeFunctionType(Ty, FD);
}
const CGFunctionInfo &
@@ -55,8 +56,9 @@
const CGFunctionInfo &
CodeGenABITypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP) {
- return CGM->getTypes().arrangeCXXMethodType(RD, FTP);
+ const FunctionProtoType *FTP,
+ const CXXMethodDecl *MD) {
+ return CGM->getTypes().arrangeCXXMethodType(RD, FTP, MD);
}
const CGFunctionInfo &CodeGenABITypes::arrangeFreeFunctionCall(
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 10e5cbb..cdd9d09 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -57,6 +57,10 @@
SmallVector<std::pair<unsigned, std::unique_ptr<llvm::Module>>, 4>
LinkModules;
+ // This is here so that the diagnostic printer knows the module a diagnostic
+ // refers to.
+ llvm::Module *CurLinkModule = nullptr;
+
public:
BackendConsumer(
BackendAction Action, DiagnosticsEngine &Diags,
@@ -161,18 +165,6 @@
assert(TheModule.get() == M &&
"Unexpected module change during IR generation");
- // Link LinkModule into this module if present, preserving its validity.
- for (auto &I : LinkModules) {
- unsigned LinkFlags = I.first;
- llvm::Module *LinkModule = I.second.get();
- if (Linker::LinkModules(M, LinkModule,
- [=](const DiagnosticInfo &DI) {
- linkerDiagnosticHandler(DI, LinkModule);
- },
- LinkFlags))
- return;
- }
-
// Install an inline asm handler so that diagnostics get printed through
// our diagnostics hooks.
LLVMContext &Ctx = TheModule->getContext();
@@ -186,6 +178,14 @@
void *OldDiagnosticContext = Ctx.getDiagnosticContext();
Ctx.setDiagnosticHandler(DiagnosticHandler, this);
+ // Link LinkModule into this module if present, preserving its validity.
+ for (auto &I : LinkModules) {
+ unsigned LinkFlags = I.first;
+ CurLinkModule = I.second.get();
+ if (Linker::linkModules(*M, std::move(I.second), LinkFlags))
+ return;
+ }
+
EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts,
C.getTargetInfo().getDataLayoutString(),
TheModule.get(), Action, AsmOutStream);
@@ -214,8 +214,8 @@
Gen->HandleVTable(RD);
}
- void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
- Gen->HandleLinkerOptionPragma(Opts);
+ void HandleLinkerOption(llvm::StringRef Opts) override {
+ Gen->HandleLinkerOption(Opts);
}
void HandleDetectMismatch(llvm::StringRef Name,
@@ -233,9 +233,6 @@
((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
}
- void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI,
- const llvm::Module *LinkModule);
-
static void DiagnosticHandler(const llvm::DiagnosticInfo &DI,
void *Context) {
((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI);
@@ -545,22 +542,6 @@
EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure);
}
-void BackendConsumer::linkerDiagnosticHandler(const DiagnosticInfo &DI,
- const llvm::Module *LinkModule) {
- if (DI.getSeverity() != DS_Error)
- return;
-
- std::string MsgStorage;
- {
- raw_string_ostream Stream(MsgStorage);
- DiagnosticPrinterRawOStream DP(Stream);
- DI.print(DP);
- }
-
- Diags.Report(diag::err_fe_cannot_link_module)
- << LinkModule->getModuleIdentifier() << MsgStorage;
-}
-
/// \brief This function is invoked when the backend needs
/// to report something to the user.
void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
@@ -578,6 +559,13 @@
return;
ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
break;
+ case DK_Linker:
+ assert(CurLinkModule);
+ // FIXME: stop eating the warnings and notes.
+ if (Severity != DS_Error)
+ return;
+ DiagID = diag::err_fe_cannot_link_module;
+ break;
case llvm::DK_OptimizationRemark:
// Optimization remarks are always handled completely by this
// handler. There is no generic way of emitting them.
@@ -623,6 +611,12 @@
DI.print(DP);
}
+ if (DiagID == diag::err_fe_cannot_link_module) {
+ Diags.Report(diag::err_fe_cannot_link_module)
+ << CurLinkModule->getModuleIdentifier() << MsgStorage;
+ return;
+ }
+
// Report the backend message using the usual diagnostic mechanism.
FullSourceLoc Loc;
Diags.Report(Loc, DiagID).AddString(MsgStorage);
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 6c08812..e41aa81 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -29,6 +29,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
@@ -78,7 +79,7 @@
if (CGM.getCodeGenOpts().ReciprocalMath) {
FMF.setAllowReciprocal();
}
- Builder.SetFastMathFlags(FMF);
+ Builder.setFastMathFlags(FMF);
}
CodeGenFunction::~CodeGenFunction() {
@@ -194,6 +195,7 @@
case Type::FunctionNoProto:
case Type::Enum:
case Type::ObjCObjectPointer:
+ case Type::Pipe:
return TEK_Scalar;
// Complexes.
@@ -510,7 +512,8 @@
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
} else {
uint32_t AddrSpc = 0;
- if (ty->isImageType())
+ bool isPipe = ty->isPipeType();
+ if (ty->isImageType() || isPipe)
AddrSpc =
CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
@@ -518,7 +521,11 @@
llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc)));
// Get argument type name.
- std::string typeName = ty.getUnqualifiedType().getAsString(Policy);
+ std::string typeName;
+ if (isPipe)
+ typeName = cast<PipeType>(ty)->getElementType().getAsString(Policy);
+ else
+ typeName = ty.getUnqualifiedType().getAsString(Policy);
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -527,7 +534,12 @@
argTypeNames.push_back(llvm::MDString::get(Context, typeName));
- std::string baseTypeName =
+ std::string baseTypeName;
+ if (isPipe)
+ baseTypeName =
+ cast<PipeType>(ty)->getElementType().getCanonicalType().getAsString(Policy);
+ else
+ baseTypeName =
ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
// Turn "unsigned type" to "utype"
@@ -542,12 +554,16 @@
typeQuals = "const";
if (ty.isVolatileQualified())
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ if (isPipe)
+ typeQuals = "pipe";
}
argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
- // Get image access qualifier:
- if (ty->isImageType()) {
+ // Get image and pipe access qualifier:
+ // FIXME: now image and pipe share the same access qualifier maybe we can
+ // refine it to OpenCL access qualifier and also handle write_read
+ if (ty->isImageType()|| ty->isPipeType()) {
const OpenCLImageAccessAttr *A = parm->getAttr<OpenCLImageAccessAttr>();
if (A && A->isWriteOnly())
accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
@@ -715,6 +731,14 @@
}
}
+ // If we're in C++ mode and the function name is "main", it is guaranteed
+ // to be norecurse by the standard (3.6.1.3 "The function main shall not be
+ // used within a program").
+ if (getLangOpts().CPlusPlus)
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ if (FD->isMain())
+ Fn->addFnAttr(llvm::Attribute::NoRecurse);
+
llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
// Create a marker to make it easy to insert allocas into the entryblock
@@ -911,7 +935,18 @@
CGM.getCXXABI().buildThisParam(*this, Args);
}
- Args.append(FD->param_begin(), FD->param_end());
+ for (auto *Param : FD->params()) {
+ Args.push_back(Param);
+ if (!Param->hasAttr<PassObjectSizeAttr>())
+ continue;
+
+ IdentifierInfo *NoID = nullptr;
+ auto *Implicit = ImplicitParamDecl::Create(
+ getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
+ getContext().getSizeType());
+ SizeArguments[Param] = Implicit;
+ Args.push_back(Implicit);
+ }
if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
@@ -937,8 +972,7 @@
StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
// Generate the body of the function.
- PGO.checkGlobalDecl(GD);
- PGO.assignRegionCounters(GD.getDecl(), CurFn);
+ PGO.assignRegionCounters(GD, CurFn);
if (isa<CXXDestructorDecl>(FD))
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
@@ -1708,6 +1742,10 @@
case Type::Atomic:
type = cast<AtomicType>(ty)->getValueType();
break;
+
+ case Type::Pipe:
+ type = cast<PipeType>(ty)->getElementType();
+ break;
}
} while (type->isVariablyModifiedType());
}
@@ -1841,3 +1879,89 @@
llvm::Instruction *I, const llvm::Twine &Name, llvm::BasicBlock *BB,
llvm::BasicBlock::iterator InsertPt) const;
#undef PreserveNames
+
+static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures,
+ CodeGenModule &CGM, const FunctionDecl *FD,
+ std::string &FirstMissing) {
+ // If there aren't any required features listed then go ahead and return.
+ if (ReqFeatures.empty())
+ return false;
+
+ // Now build up the set of caller features and verify that all the required
+ // features are there.
+ llvm::StringMap<bool> CallerFeatureMap;
+ CGM.getFunctionFeatureMap(CallerFeatureMap, FD);
+
+ // If we have at least one of the features in the feature list return
+ // true, otherwise return false.
+ return std::all_of(
+ ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef Feature) {
+ SmallVector<StringRef, 1> OrFeatures;
+ Feature.split(OrFeatures, "|");
+ return std::any_of(OrFeatures.begin(), OrFeatures.end(),
+ [&](StringRef Feature) {
+ if (!CallerFeatureMap.lookup(Feature)) {
+ FirstMissing = Feature.str();
+ return false;
+ }
+ return true;
+ });
+ });
+}
+
+// Emits an error if we don't have a valid set of target features for the
+// called function.
+void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
+ const FunctionDecl *TargetDecl) {
+ // Early exit if this is an indirect call.
+ if (!TargetDecl)
+ return;
+
+ // Get the current enclosing function if it exists. If it doesn't
+ // we can't check the target features anyhow.
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl);
+ if (!FD)
+ return;
+
+ // Grab the required features for the call. For a builtin this is listed in
+ // the td file with the default cpu, for an always_inline function this is any
+ // listed cpu and any listed features.
+ unsigned BuiltinID = TargetDecl->getBuiltinID();
+ std::string MissingFeature;
+ if (BuiltinID) {
+ SmallVector<StringRef, 1> ReqFeatures;
+ const char *FeatureList =
+ CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
+ // Return if the builtin doesn't have any required features.
+ if (!FeatureList || StringRef(FeatureList) == "")
+ return;
+ StringRef(FeatureList).split(ReqFeatures, ",");
+ if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
+ CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature)
+ << TargetDecl->getDeclName()
+ << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
+
+ } else if (TargetDecl->hasAttr<TargetAttr>()) {
+ // Get the required features for the callee.
+ SmallVector<StringRef, 1> ReqFeatures;
+ llvm::StringMap<bool> CalleeFeatureMap;
+ CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
+ for (const auto &F : CalleeFeatureMap) {
+ // Only positive features are "required".
+ if (F.getValue())
+ ReqFeatures.push_back(F.getKey());
+ }
+ if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
+ CGM.getDiags().Report(E->getLocStart(), diag::err_function_needs_feature)
+ << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
+ }
+}
+
+void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
+ if (!CGM.getCodeGenOpts().SanitizeStats)
+ return;
+
+ llvm::IRBuilder<> IRB(Builder.GetInsertBlock(), Builder.GetInsertPoint());
+ IRB.SetCurrentDebugLocation(Builder.getCurrentDebugLocation());
+ CGM.getSanStats().create(IRB, SSK);
+}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 4b0c490..961d6ae 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -36,6 +36,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/SanitizerStats.h"
namespace llvm {
class BasicBlock;
@@ -279,8 +280,6 @@
/// finally block or filter expression.
bool IsOutlinedSEHHelper;
- bool IsCleanupPadScope = false;
-
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -295,6 +294,8 @@
llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;
+ llvm::Instruction *CurrentFuncletPad = nullptr;
+
/// Header for data within LifetimeExtendedCleanupStack.
struct LifetimeExtendedCleanupHeader {
/// The size of the following cleanup object.
@@ -375,7 +376,9 @@
bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
/// Returns true while emitting a cleanuppad.
- bool isCleanupPadScope() const { return IsCleanupPadScope; }
+ bool isCleanupPadScope() const {
+ return CurrentFuncletPad && isa<llvm::CleanupPadInst>(CurrentFuncletPad);
+ }
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
@@ -914,6 +917,12 @@
/// decls.
DeclMapTy LocalDeclMap;
+ /// SizeArguments - If a ParmVarDecl had the pass_object_size attribute, this
+ /// will contain a mapping from said ParmVarDecl to its implicit "object_size"
+ /// parameter.
+ llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *, 2>
+ SizeArguments;
+
/// Track escaped local variables with auto storage. Used during SEH
/// outlining to produce a call to llvm.localescape.
llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals;
@@ -2200,12 +2209,9 @@
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
Address GenerateCapturedStmtArgument(const CapturedStmt &S);
- llvm::Function *
- GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S,
- bool UseOnlyReferences = false);
+ llvm::Function *GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S);
void GenerateOpenMPCapturedVars(const CapturedStmt &S,
- SmallVectorImpl<llvm::Value *> &CapturedVars,
- bool UseOnlyReferences = false);
+ SmallVectorImpl<llvm::Value *> &CapturedVars);
/// \brief Perform element by element copying of arrays with type \a
/// OriginalType from \a SrcAddr to \a DestAddr using copying procedure
/// generated by \a CopyGen.
@@ -2334,6 +2340,9 @@
void
EmitOMPCancellationPointDirective(const OMPCancellationPointDirective &S);
void EmitOMPCancelDirective(const OMPCancelDirective &S);
+ void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S);
+ void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S);
+ void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
/// \brief Emit inner loop of the worksharing/simd construct.
///
@@ -2357,17 +2366,17 @@
/// Helpers for the OpenMP loop directives.
void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
- void EmitOMPSimdInit(const OMPLoopDirective &D);
+ void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false);
void EmitOMPSimdFinal(const OMPLoopDirective &D);
/// \brief Emit code for the worksharing loop-based directive.
/// \return true, if this construct has any lastprivate clause, false -
/// otherwise.
bool EmitOMPWorksharingLoop(const OMPLoopDirective &S);
void EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
- const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST,
- Address IL, llvm::Value *Chunk);
+ bool IsMonotonic, const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope, bool Ordered, Address LB,
+ Address UB, Address ST, Address IL,
+ llvm::Value *Chunk);
/// \brief Emit code for sections directive.
OpenMPDirectiveKind EmitSections(const OMPExecutableDirective &S);
@@ -2621,24 +2630,19 @@
/// EmitCall - Generate a call of the given function, expecting the given
/// result type, and using the given argument list which specifies both the
/// LLVM arguments and the types they were derived from.
- ///
- /// \param TargetDecl - If given, the decl of the function in a direct call;
- /// used to set attributes on the call (noreturn, etc.).
- RValue EmitCall(const CGFunctionInfo &FnInfo,
- llvm::Value *Callee,
- ReturnValueSlot ReturnValue,
- const CallArgList &Args,
- const Decl *TargetDecl = nullptr,
+ RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee,
+ ReturnValueSlot ReturnValue, const CallArgList &Args,
+ CGCalleeInfo CalleeInfo = CGCalleeInfo(),
llvm::Instruction **callOrInvoke = nullptr);
RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E,
ReturnValueSlot ReturnValue,
- const Decl *TargetDecl = nullptr,
+ CGCalleeInfo CalleeInfo = CGCalleeInfo(),
llvm::Value *Chain = nullptr);
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
- bool checkBuiltinTargetFeatures(const FunctionDecl *TargetDecl);
+ void checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl);
llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
const Twine &name = "");
@@ -2793,19 +2797,25 @@
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
+ llvm::Value *EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value);
std::pair<LValue,llvm::Value*>
EmitARCStoreAutoreleasing(const BinaryOperator *e);
std::pair<LValue,llvm::Value*>
EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
+ std::pair<LValue,llvm::Value*>
+ EmitARCStoreUnsafeUnretained(const BinaryOperator *e, bool ignored);
llvm::Value *EmitObjCThrowOperand(const Expr *expr);
llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
llvm::Value *EmitARCExtendBlockObject(const Expr *expr);
+ llvm::Value *EmitARCReclaimReturnedObject(const Expr *e,
+ bool allowUnsafeClaim);
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+ llvm::Value *EmitARCUnsafeUnretainedScalarExpr(const Expr *expr);
void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
@@ -3006,6 +3016,11 @@
StringRef CheckName, ArrayRef<llvm::Constant *> StaticArgs,
ArrayRef<llvm::Value *> DynamicArgs);
+ /// \brief Emit a slow path cross-DSO CFI check which calls __cfi_slowpath
+ /// if Cond if false.
+ void EmitCfiSlowPathCheck(llvm::Value *Cond, llvm::ConstantInt *TypeId,
+ llvm::Value *Ptr);
+
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
void EmitTrapCheck(llvm::Value *Checked);
@@ -3069,6 +3084,18 @@
std::string &ConstraintStr,
SourceLocation Loc);
+ /// \brief Attempts to statically evaluate the object size of E. If that
+ /// fails, emits code to figure the size of E out for us. This is
+ /// pass_object_size aware.
+ llvm::Value *evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType);
+
+ /// \brief Emits the size of E, as required by __builtin_object_size. This
+ /// function is aware of pass_object_size parameters, and will act accordingly
+ /// if E is a parameter with the pass_object_size attribute.
+ llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type,
+ llvm::IntegerType *ResType);
+
public:
#ifndef NDEBUG
// Determine whether the given argument is an Objective-C method
@@ -3167,6 +3194,8 @@
Address EmitPointerWithAlignment(const Expr *Addr,
AlignmentSource *Source = nullptr);
+ void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
+
private:
QualType getVarArgType(const Expr *Arg);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 523985b..a89eb7d 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -53,6 +53,7 @@
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MD5.h"
using namespace clang;
using namespace CodeGen;
@@ -374,8 +375,15 @@
if (llvm::Function *CudaDtorFunction = CUDARuntime->makeModuleDtorFunction())
AddGlobalDtor(CudaDtorFunction);
}
- if (PGOReader && PGOStats.hasDiagnostics())
- PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
+ if (OpenMPRuntime)
+ if (llvm::Function *OpenMPRegistrationFunction =
+ OpenMPRuntime->emitRegistrationFunction())
+ AddGlobalCtor(OpenMPRegistrationFunction, 0);
+ if (PGOReader) {
+ getModule().setMaximumFunctionCount(PGOReader->getMaximumFunctionCount());
+ if (PGOStats.hasDiagnostics())
+ PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
+ }
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
@@ -384,6 +392,8 @@
if (CoverageMapping)
CoverageMapping->emit();
emitLLVMUsed();
+ if (SanStats)
+ SanStats->finish();
if (CodeGenOpts.Autolink &&
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
@@ -439,6 +449,11 @@
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
}
+ if (CodeGenOpts.SanitizeCfiCrossDso) {
+ // Indicate that we want cross-DSO control flow integrity checks.
+ getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1);
+ }
+
if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
llvm::PICLevel::Level PL = llvm::PICLevel::Default;
switch (PLevel) {
@@ -602,7 +617,20 @@
}
StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
- StringRef &FoundStr = MangledDeclNames[GD.getCanonicalDecl()];
+ GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+
+ // Some ABIs don't have constructor variants. Make sure that base and
+ // complete constructors get mangled the same.
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
+ if (!getTarget().getCXXABI().hasConstructorVariants()) {
+ CXXCtorType OrigCtorType = GD.getCtorType();
+ assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
+ if (OrigCtorType == Ctor_Base)
+ CanonicalGD = GlobalDecl(CD, Ctor_Complete);
+ }
+ }
+
+ StringRef &FoundStr = MangledDeclNames[CanonicalGD];
if (!FoundStr.empty())
return FoundStr;
@@ -736,6 +764,21 @@
F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
}
+llvm::ConstantInt *
+CodeGenModule::CreateCfiIdForTypeMetadata(llvm::Metadata *MD) {
+ llvm::MDString *MDS = dyn_cast<llvm::MDString>(MD);
+ if (!MDS) return nullptr;
+
+ llvm::MD5 md5;
+ llvm::MD5::MD5Result result;
+ md5.update(MDS->getString());
+ md5.final(result);
+ uint64_t id = 0;
+ for (int i = 0; i < 8; ++i)
+ id |= static_cast<uint64_t>(result[i]) << (i * 8);
+ return llvm::ConstantInt::get(Int64Ty, id);
+}
+
void CodeGenModule::setFunctionDefinitionAttributes(const FunctionDecl *D,
llvm::Function *F) {
setNonAliasAttributes(D, F);
@@ -746,7 +789,8 @@
llvm::Function *F) {
unsigned CallingConv;
AttributeListType AttributeList;
- ConstructAttributeList(Info, D, AttributeList, CallingConv, false);
+ ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
+ false);
F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -928,6 +972,49 @@
}
}
+void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD,
+ llvm::Function *F) {
+ // Only if we are checking indirect calls.
+ if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
+ return;
+
+ // Non-static class methods are handled via vtable pointer checks elsewhere.
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
+ return;
+
+ // Additionally, if building with cross-DSO support...
+ if (CodeGenOpts.SanitizeCfiCrossDso) {
+ // Don't emit entries for function declarations. In cross-DSO mode these are
+ // handled with better precision at run time.
+ if (!FD->hasBody())
+ return;
+ // Skip available_externally functions. They won't be codegen'ed in the
+ // current module anyway.
+ if (getContext().GetGVALinkageForFunction(FD) == GVA_AvailableExternally)
+ return;
+ }
+
+ llvm::NamedMDNode *BitsetsMD =
+ getModule().getOrInsertNamedMetadata("llvm.bitsets");
+
+ llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
+ llvm::Metadata *BitsetOps[] = {
+ MD, llvm::ConstantAsMetadata::get(F),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
+ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
+
+ // Emit a hash-based bit set entry for cross-DSO calls.
+ if (CodeGenOpts.SanitizeCfiCrossDso) {
+ if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
+ llvm::Metadata *BitsetOps2[] = {
+ llvm::ConstantAsMetadata::get(TypeId),
+ llvm::ConstantAsMetadata::get(F),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
+ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
+ }
+ }
+}
+
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
bool IsIncompleteFunction,
bool IsThunk) {
@@ -970,19 +1057,7 @@
F->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoBuiltin);
- // If we are checking indirect calls and this is not a non-static member
- // function, emit a bit set entry for the function type.
- if (LangOpts.Sanitize.has(SanitizerKind::CFIICall) &&
- !(isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())) {
- llvm::NamedMDNode *BitsetsMD =
- getModule().getOrInsertNamedMetadata("llvm.bitsets");
-
- llvm::Metadata *BitsetOps[] = {
- CreateMetadataIdentifierForType(FD->getType()),
- llvm::ConstantAsMetadata::get(F),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
- BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
- }
+ CreateFunctionBitSetEntry(FD, F);
}
void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
@@ -1171,19 +1246,23 @@
for (DeferredGlobal &G : CurDeclsToEmit) {
GlobalDecl D = G.GD;
- llvm::GlobalValue *GV = G.GV;
G.GV = nullptr;
// We should call GetAddrOfGlobal with IsForDefinition set to true in order
// to get GlobalValue with exactly the type we need, not something that
// might had been created for another decl with the same mangled name but
// different type.
- // FIXME: Support for variables is not implemented yet.
- if (isa<FunctionDecl>(D.getDecl()))
- GV = cast<llvm::GlobalValue>(GetAddrOfGlobal(D, /*IsForDefinition=*/true));
- else
- if (!GV)
- GV = GetGlobalValue(getMangledName(D));
+ llvm::GlobalValue *GV = dyn_cast<llvm::GlobalValue>(
+ GetAddrOfGlobal(D, /*IsForDefinition=*/true));
+
+ // In case of different address spaces, we may still get a cast, even with
+ // IsForDefinition equal to true. Query mangled names table to get
+ // GlobalValue.
+ if (!GV)
+ GV = GetGlobalValue(getMangledName(D));
+
+ // Make sure GetGlobalValue returned non-null.
+ assert(GV);
// Check to see if we've already emitted this. This is necessary
// for a couple of reasons: first, decls can end up in the
@@ -1191,7 +1270,7 @@
// up with definitions in unusual ways (e.g. by an extern inline
// function acquiring a strong function redefinition). Just
// ignore these cases.
- if (GV && !GV->isDeclaration())
+ if (!GV->isDeclaration())
continue;
// Otherwise, emit the definition and move on to the next one.
@@ -1435,6 +1514,11 @@
}
}
+ // If this is OpenMP device, check if it is legal to emit this global
+ // normally.
+ if (OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(GD))
+ return;
+
// Ignore declarations, they will be emitted on their first use.
if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
// Forward declarations are emitted lazily on first use.
@@ -1652,7 +1736,7 @@
}
if (const auto *VD = dyn_cast<VarDecl>(D))
- return EmitGlobalVarDefinition(VD);
+ return EmitGlobalVarDefinition(VD, !VD->hasDefinition());
llvm_unreachable("Invalid argument to EmitGlobalDefinition()");
}
@@ -1693,8 +1777,8 @@
// error.
if (IsForDefinition && !Entry->isDeclaration()) {
GlobalDecl OtherGD;
- // Check that GD is not yet in ExplicitDefinitions is required to make
- // sure that we issue an error only once.
+ // Check that GD is not yet in DiagnosedConflictingDefinitions is required
+ // to make sure that we issue an error only once.
if (lookupRepresentativeDecl(MangledName, OtherGD) &&
(GD.getCanonicalDecl().getDecl() !=
OtherGD.getCanonicalDecl().getDecl()) &&
@@ -1835,8 +1919,11 @@
bool DontDefer,
bool IsForDefinition) {
// If there was no specific requested type, just convert it now.
- if (!Ty)
- Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
+ if (!Ty) {
+ const auto *FD = cast<FunctionDecl>(GD.getDecl());
+ auto CanonTy = Context.getCanonicalType(FD->getType());
+ Ty = getTypes().ConvertFunctionType(CanonTy, FD);
+ }
StringRef MangledName = getMangledName(GD);
return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer,
@@ -1901,10 +1988,15 @@
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the global when it is first created.
+///
+/// If IsForDefinition is true, it is guranteed that an actual global with
+/// type Ty will be returned, not conversion of a variable with the same
+/// mangled name but some other type.
llvm::Constant *
CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *Ty,
- const VarDecl *D) {
+ const VarDecl *D,
+ bool IsForDefinition) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@@ -1920,11 +2012,34 @@
if (Entry->getType() == Ty)
return Entry;
+ // If there are two attempts to define the same mangled name, issue an
+ // error.
+ if (IsForDefinition && !Entry->isDeclaration()) {
+ GlobalDecl OtherGD;
+ const VarDecl *OtherD;
+
+ // Check that D is not yet in DiagnosedConflictingDefinitions is required
+ // to make sure that we issue an error only once.
+ if (lookupRepresentativeDecl(MangledName, OtherGD) &&
+ (D->getCanonicalDecl() != OtherGD.getCanonicalDecl().getDecl()) &&
+ (OtherD = dyn_cast<VarDecl>(OtherGD.getDecl())) &&
+ OtherD->hasInit() &&
+ DiagnosedConflictingDefinitions.insert(D).second) {
+ getDiags().Report(D->getLocation(),
+ diag::err_duplicate_mangled_name);
+ getDiags().Report(OtherGD.getDecl()->getLocation(),
+ diag::note_previous_definition);
+ }
+ }
+
// Make sure the result is of the correct type.
if (Entry->getType()->getAddressSpace() != Ty->getAddressSpace())
return llvm::ConstantExpr::getAddrSpaceCast(Entry, Ty);
- return llvm::ConstantExpr::getBitCast(Entry, Ty);
+ // (If global is requested for a definition, we always need to create a new
+ // global, not just return a bitcast.)
+ if (!IsForDefinition)
+ return llvm::ConstantExpr::getBitCast(Entry, Ty);
}
unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
@@ -1933,6 +2048,20 @@
llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
llvm::GlobalVariable::NotThreadLocal, AddrSpace);
+ // If we already created a global with the same mangled name (but different
+ // type) before, take its name and remove it from its parent.
+ if (Entry) {
+ GV->takeName(Entry);
+
+ if (!Entry->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, Entry->getType());
+ Entry->replaceAllUsesWith(NewPtrForOldDecl);
+ }
+
+ Entry->eraseFromParent();
+ }
+
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
@@ -1956,7 +2085,7 @@
if (D->getTLSKind()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic)
- CXXThreadLocals.push_back(std::make_pair(D, GV));
+ CXXThreadLocals.push_back(D);
setTLSMode(GV, *D);
}
@@ -2005,7 +2134,8 @@
return GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer=*/false,
IsForDefinition);
} else
- return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl()));
+ return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl()), /*Ty=*/nullptr,
+ IsForDefinition);
}
llvm::GlobalVariable *
@@ -2053,9 +2183,12 @@
/// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
/// given global variable. If Ty is non-null and if the global doesn't exist,
/// then it will be created with the specified type instead of whatever the
-/// normal requested type would be.
+/// normal requested type would be. If IsForDefinition is true, it is guranteed
+/// that an actual global with type Ty will be returned, not conversion of a
+/// variable with the same mangled name but some other type.
llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
- llvm::Type *Ty) {
+ llvm::Type *Ty,
+ bool IsForDefinition) {
assert(D->hasGlobalStorage() && "Not a global variable");
QualType ASTTy = D->getType();
if (!Ty)
@@ -2065,7 +2198,7 @@
llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
StringRef MangledName = getMangledName(D);
- return GetOrCreateLLVMGlobal(MangledName, PTy, D);
+ return GetOrCreateLLVMGlobal(MangledName, PTy, D, IsForDefinition);
}
/// CreateRuntimeVariable - Create a new runtime global variable with the
@@ -2079,15 +2212,20 @@
void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
assert(!D->getInit() && "Cannot emit definite definitions here!");
- if (!MustBeEmitted(D)) {
- // If we have not seen a reference to this variable yet, place it
- // into the deferred declarations table to be emitted if needed
- // later.
- StringRef MangledName = getMangledName(D);
- if (!GetGlobalValue(MangledName)) {
+ StringRef MangledName = getMangledName(D);
+ llvm::GlobalValue *GV = GetGlobalValue(MangledName);
+
+ // We already have a definition, not declaration, with the same mangled name.
+ // Emitting of declaration is not required (and actually overwrites emitted
+ // definition).
+ if (GV && !GV->isDeclaration())
+ return;
+
+ // If we have not seen a reference to this variable yet, place it into the
+ // deferred declarations table to be emitted if needed later.
+ if (!MustBeEmitted(D) && !GV) {
DeferredDecls[MangledName] = D;
return;
- }
}
// The tentative definition is the only definition.
@@ -2178,7 +2316,9 @@
GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
}
-void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
+/// Pass IsTentative as true if you want to create a tentative definition.
+void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
+ bool IsTentative) {
llvm::Constant *Init = nullptr;
QualType ASTTy = D->getType();
CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
@@ -2237,7 +2377,8 @@
}
llvm::Type* InitType = Init->getType();
- llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType);
+ llvm::Constant *Entry =
+ GetAddrOfGlobalVar(D, InitType, /*IsForDefinition=*/!IsTentative);
// Strip off a bitcast if we got one back.
if (auto *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
@@ -2269,7 +2410,8 @@
Entry->setName(StringRef());
// Make a new global with the correct type, this is now guaranteed to work.
- GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType));
+ GV = cast<llvm::GlobalVariable>(
+ GetAddrOfGlobalVar(D, InitType, /*IsForDefinition=*/!IsTentative));
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
@@ -2315,12 +2457,17 @@
llvm::GlobalValue::LinkageTypes Linkage =
getLLVMLinkageVarDefinition(D, GV->isConstant());
- // On Darwin, the backing variable for a C++11 thread_local variable always
- // has internal linkage; all accesses should just be calls to the
+ // On Darwin, if the normal linkage of a C++ thread_local variable is
+ // LinkOnce or Weak, we keep the normal linkage to prevent multiple
+ // copies within a linkage unit; otherwise, the backing variable has
+ // internal linkage and all accesses should just be calls to the
// Itanium-specified entry point, which has the normal linkage of the
- // variable.
+ // variable. This is to preserve the ability to change the implementation
+ // behind the scenes.
if (!D->isStaticLocal() && D->getTLSKind() == VarDecl::TLS_Dynamic &&
- Context.getTargetInfo().getTriple().isMacOSX())
+ Context.getTargetInfo().getTriple().isOSDarwin() &&
+ !llvm::GlobalVariable::isLinkOnceLinkage(Linkage) &&
+ !llvm::GlobalVariable::isWeakLinkage(Linkage))
Linkage = llvm::GlobalValue::InternalLinkage;
GV->setLinkage(Linkage);
@@ -2339,7 +2486,7 @@
if (D->getTLSKind() && !GV->isThreadLocal()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic)
- CXXThreadLocals.push_back(std::make_pair(D, GV));
+ CXXThreadLocals.push_back(D);
setTLSMode(GV, *D);
}
@@ -2487,6 +2634,7 @@
llvm::Type *newRetTy = newFn->getReturnType();
SmallVector<llvm::Value*, 4> newArgs;
+ SmallVector<llvm::OperandBundleDef, 1> newBundles;
for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end();
ui != ue; ) {
@@ -2554,16 +2702,19 @@
// over the required information.
newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo);
+ // Copy over any operand bundles.
+ callSite.getOperandBundlesAsDefs(newBundles);
+
llvm::CallSite newCall;
if (callSite.isCall()) {
- newCall = llvm::CallInst::Create(newFn, newArgs, "",
+ newCall = llvm::CallInst::Create(newFn, newArgs, newBundles, "",
callSite.getInstruction());
} else {
auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction());
newCall = llvm::InvokeInst::Create(newFn,
oldInvoke->getNormalDest(),
oldInvoke->getUnwindDest(),
- newArgs, "",
+ newArgs, newBundles, "",
callSite.getInstruction());
}
newArgs.clear(); // for the next iteration
@@ -2581,6 +2732,7 @@
// Copy debug location attached to CI.
if (callSite->getDebugLoc())
newCall->setDebugLoc(callSite->getDebugLoc());
+
callSite->eraseFromParent();
}
}
@@ -3530,6 +3682,9 @@
// File-scope asm is ignored during device-side CUDA compilation.
if (LangOpts.CUDA && LangOpts.CUDAIsDevice)
break;
+ // File-scope asm is ignored during device-side OpenMP compilation.
+ if (LangOpts.OpenMPIsDevice)
+ break;
auto *AD = cast<FileScopeAsmDecl>(D);
getModule().appendModuleInlineAsm(AD->getAsmString()->getString());
break;
@@ -3863,12 +4018,62 @@
return InternalId;
}
-llvm::MDTuple *CodeGenModule::CreateVTableBitSetEntry(
- llvm::GlobalVariable *VTable, CharUnits Offset, const CXXRecordDecl *RD) {
+void CodeGenModule::CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
+ llvm::GlobalVariable *VTable,
+ CharUnits Offset,
+ const CXXRecordDecl *RD) {
+ llvm::Metadata *MD =
+ CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Metadata *BitsetOps[] = {
- CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)),
- llvm::ConstantAsMetadata::get(VTable),
+ MD, llvm::ConstantAsMetadata::get(VTable),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
- return llvm::MDTuple::get(getLLVMContext(), BitsetOps);
+ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
+
+ if (CodeGenOpts.SanitizeCfiCrossDso) {
+ if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
+ llvm::Metadata *BitsetOps2[] = {
+ llvm::ConstantAsMetadata::get(TypeId),
+ llvm::ConstantAsMetadata::get(VTable),
+ llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
+ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
+ }
+ }
+}
+
+// Fills in the supplied string map with the set of target features for the
+// passed in function.
+void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ const FunctionDecl *FD) {
+ StringRef TargetCPU = Target.getTargetOpts().CPU;
+ if (const auto *TD = FD->getAttr<TargetAttr>()) {
+ // If we have a TargetAttr build up the feature map based on that.
+ TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
+
+ // Make a copy of the features as passed on the command line into the
+ // beginning of the additional features from the function to override.
+ ParsedAttr.first.insert(ParsedAttr.first.begin(),
+ Target.getTargetOpts().FeaturesAsWritten.begin(),
+ Target.getTargetOpts().FeaturesAsWritten.end());
+
+ if (ParsedAttr.second != "")
+ TargetCPU = ParsedAttr.second;
+
+ // Now populate the feature map, first with the TargetCPU which is either
+ // the default or a new one from the target attribute string. Then we'll use
+ // the passed in features (FeaturesAsWritten) along with the new ones from
+ // the attribute.
+ Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, ParsedAttr.first);
+ } else {
+ Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
+ Target.getTargetOpts().Features);
+ }
+}
+
+llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
+ if (!SanStats)
+ SanStats = llvm::make_unique<llvm::SanitizerStatReport>(&getModule());
+
+ return *SanStats;
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index d3f6e51..efebcda 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -33,6 +33,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueHandle.h"
+#include "llvm/Transforms/Utils/SanitizerStats.h"
namespace llvm {
class Module;
@@ -165,6 +166,9 @@
/// id objc_storeWeak(id*, id);
llvm::Constant *objc_storeWeak;
+ /// id objc_unsafeClaimAutoreleasedReturnValue(id);
+ llvm::Constant *objc_unsafeClaimAutoreleasedReturnValue;
+
/// A void(void) inline asm to use to mark that the return value of
/// a call will be immediately retain.
llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
@@ -289,6 +293,7 @@
llvm::MDNode *NoObjCARCExceptionsMetadata;
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
InstrProfStats PGOStats;
+ std::unique_ptr<llvm::SanitizerStatReport> SanStats;
// A set of references that have only been seen via a weakref so far. This is
// used to remove the weak of the reference if we ever see a direct reference
@@ -378,13 +383,12 @@
StaticExternCMap StaticExternCValues;
/// \brief thread_local variables defined or used in this TU.
- std::vector<std::pair<const VarDecl *, llvm::GlobalVariable *> >
- CXXThreadLocals;
+ std::vector<const VarDecl *> CXXThreadLocals;
/// \brief thread_local variables with initializers that need to run
/// before any thread_local variable in this TU is odr-used.
std::vector<llvm::Function *> CXXThreadLocalInits;
- std::vector<llvm::GlobalVariable *> CXXThreadLocalInitVars;
+ std::vector<const VarDecl *> CXXThreadLocalInitVars;
/// Global variables with initializers that need to run before main.
std::vector<llvm::Function *> CXXGlobalInits;
@@ -697,11 +701,14 @@
unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace);
/// Return the llvm::Constant for the address of the given global variable.
- /// If Ty is non-null and if the global doesn't exist, then it will be greated
+ /// If Ty is non-null and if the global doesn't exist, then it will be created
/// with the specified type instead of whatever the normal requested type
- /// would be.
+ /// would be. If IsForDefinition is true, it is guranteed that an actual
+ /// global with type Ty will be returned, not conversion of a variable with
+ /// the same mangled name but some other type.
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
- llvm::Type *Ty = nullptr);
+ llvm::Type *Ty = nullptr,
+ bool IsForDefinition = false);
/// Return the address of the given function. If Ty is non-null, then this
/// function will use the specified type if it has to create it.
@@ -967,17 +974,21 @@
/// Get the LLVM attributes and calling convention to use for a particular
/// function type.
///
+ /// \param Name - The function name.
/// \param Info - The function type information.
- /// \param TargetDecl - The decl these attributes are being constructed
- /// for. If supplied the attributes applied to this decl may contribute to the
- /// function attributes and calling convention.
+ /// \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 CallingConv [out] - On return, the LLVM calling convention to use.
- void ConstructAttributeList(const CGFunctionInfo &Info,
- const Decl *TargetDecl,
- AttributeListType &PAL,
- unsigned &CallingConv,
- bool AttrOnCallSite);
+ void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
+ CGCalleeInfo CalleeInfo, AttributeListType &PAL,
+ unsigned &CallingConv, bool AttrOnCallSite);
+
+ // Fills in the supplied string map with the set of target features for the
+ // passed in function.
+ void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ const FunctionDecl *FD);
StringRef getMangledName(GlobalDecl GD);
StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
@@ -1104,19 +1115,27 @@
void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
+ /// Generate a cross-DSO type identifier for type.
+ llvm::ConstantInt *CreateCfiIdForTypeMetadata(llvm::Metadata *MD);
+
/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
/// internal identifiers).
llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
- /// Create a bitset entry for the given vtable.
- llvm::MDTuple *CreateVTableBitSetEntry(llvm::GlobalVariable *VTable,
- CharUnits Offset,
- const CXXRecordDecl *RD);
+ /// Create a bitset entry for the given function and add it to BitsetsMD.
+ void CreateFunctionBitSetEntry(const FunctionDecl *FD, llvm::Function *F);
+
+ /// Create a bitset entry for the given vtable and add it to BitsetsMD.
+ void CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
+ llvm::GlobalVariable *VTable, CharUnits Offset,
+ const CXXRecordDecl *RD);
/// \breif Get the declaration of std::terminate for the platform.
llvm::Constant *getTerminateFn();
+ llvm::SanitizerStatReport &getSanStats();
+
private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
@@ -1127,7 +1146,8 @@
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
- const VarDecl *D);
+ const VarDecl *D,
+ bool IsForDefinition = false);
void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO);
@@ -1138,7 +1158,7 @@
void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
- void EmitGlobalVarDefinition(const VarDecl *D);
+ void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index 60bfae5..2c0d93b 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -28,7 +28,10 @@
void CodeGenPGO::setFuncName(StringRef Name,
llvm::GlobalValue::LinkageTypes Linkage) {
- FuncName = llvm::getPGOFuncName(Name, Linkage, CGM.getCodeGenOpts().MainFileName);
+ llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
+ FuncName = llvm::getPGOFuncName(
+ Name, Linkage, CGM.getCodeGenOpts().MainFileName,
+ PGOReader ? PGOReader->getVersion() : llvm::IndexedInstrProf::Version);
// If we're generating a profile, create a variable for the name.
if (CGM.getCodeGenOpts().ProfileInstrGenerate)
@@ -602,27 +605,24 @@
return endian::read<uint64_t, little, unaligned>(Result);
}
-void CodeGenPGO::checkGlobalDecl(GlobalDecl GD) {
- // Make sure we only emit coverage mapping for one constructor/destructor.
- // Clang emits several functions for the constructor and the destructor of
- // a class. Every function is instrumented, but we only want to provide
- // coverage for one of them. Because of that we only emit the coverage mapping
- // for the base constructor/destructor.
- if ((isa<CXXConstructorDecl>(GD.getDecl()) &&
- GD.getCtorType() != Ctor_Base) ||
- (isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Base)) {
- SkipCoverageMapping = true;
- }
-}
-
-void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
+void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
+ const Decl *D = GD.getDecl();
bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate;
llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
if (!InstrumentRegions && !PGOReader)
return;
if (D->isImplicit())
return;
+ // Constructors and destructors may be represented by several functions in IR.
+ // If so, instrument only base variant, others are implemented by delegation
+ // to the base one, it would be counted twice otherwise.
+ if (CGM.getTarget().getCXXABI().hasConstructorVariants() &&
+ ((isa<CXXConstructorDecl>(GD.getDecl()) &&
+ GD.getCtorType() != Ctor_Base) ||
+ (isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Base))) {
+ return;
+ }
CGM.ClearUnusedCoverageMapping(D);
setFuncName(Fn);
@@ -699,7 +699,7 @@
setFuncName(Name, Linkage);
CGM.getCoverageMapping()->addFunctionMappingRecord(
- FuncNameVar, FuncName, FunctionHash, CoverageMapping);
+ FuncNameVar, FuncName, FunctionHash, CoverageMapping, false);
}
void CodeGenPGO::computeRegionCounts(const Decl *D) {
@@ -721,17 +721,7 @@
if (!haveRegionCounts())
return;
- uint64_t MaxFunctionCount = PGOReader->getMaximumFunctionCount();
uint64_t FunctionCount = getRegionCount(nullptr);
- if (FunctionCount >= (uint64_t)(0.3 * (double)MaxFunctionCount))
- // Turn on InlineHint attribute for hot functions.
- // FIXME: 30% is from preliminary tuning on SPEC, it may not be optimal.
- Fn->addFnAttr(llvm::Attribute::InlineHint);
- else if (FunctionCount <= (uint64_t)(0.01 * (double)MaxFunctionCount))
- // Turn on Cold attribute for cold functions.
- // FIXME: 1% is from preliminary tuning on SPEC, it may not be optimal.
- Fn->addFnAttr(llvm::Attribute::Cold);
-
Fn->setEntryCount(FunctionCount);
}
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index dcd1c65..6bf29ec 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -78,13 +78,11 @@
setCurrentRegionCount(*Count);
}
- /// Check if we need to emit coverage mapping for a given declaration
- void checkGlobalDecl(GlobalDecl GD);
/// Assign counters to regions and configure them for PGO of a given
/// function. Does nothing if instrumentation is not enabled and either
/// generates global variables or associates PGO data with each of the
/// counters depending on whether we are generating or using instrumentation.
- void assignRegionCounters(const Decl *D, llvm::Function *Fn);
+ void assignRegionCounters(GlobalDecl GD, llvm::Function *Fn);
/// Emit a coverage mapping range with a counter zero
/// for an unused declaration.
void emitEmptyCounterMapping(const Decl *D, StringRef FuncName,
@@ -92,7 +90,6 @@
private:
void setFuncName(llvm::Function *Fn);
void setFuncName(StringRef Name, llvm::GlobalValue::LinkageTypes Linkage);
- void createFuncNameVar(llvm::GlobalValue::LinkageTypes Linkage);
void mapRegionCounters(const Decl *D);
void computeRegionCounts(const Decl *D);
void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index f0a25ba..09d9bf1 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -294,6 +294,76 @@
llvm_unreachable("Unknown float format!");
}
+llvm::Type *CodeGenTypes::ConvertFunctionType(QualType QFT,
+ const FunctionDecl *FD) {
+ assert(QFT.isCanonical());
+ const Type *Ty = QFT.getTypePtr();
+ const FunctionType *FT = cast<FunctionType>(QFT.getTypePtr());
+ // First, check whether we can build the full function type. If the
+ // function type depends on an incomplete type (e.g. a struct or enum), we
+ // cannot lower the function type.
+ if (!isFuncTypeConvertible(FT)) {
+ // This function's type depends on an incomplete tag type.
+
+ // Force conversion of all the relevant record types, to make sure
+ // we re-convert the FunctionType when appropriate.
+ if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
+ ConvertRecordDeclType(RT->getDecl());
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
+ for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
+ if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
+ ConvertRecordDeclType(RT->getDecl());
+
+ SkippedLayout = true;
+
+ // Return a placeholder type.
+ return llvm::StructType::get(getLLVMContext());
+ }
+
+ // While we're converting the parameter types for a function, we don't want
+ // to recursively convert any pointed-to structs. Converting directly-used
+ // structs is ok though.
+ if (!RecordsBeingLaidOut.insert(Ty).second) {
+ SkippedLayout = true;
+ return llvm::StructType::get(getLLVMContext());
+ }
+
+ // The function type can be built; call the appropriate routines to
+ // build it.
+ const CGFunctionInfo *FI;
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
+ FI = &arrangeFreeFunctionType(
+ CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)), FD);
+ } else {
+ const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
+ FI = &arrangeFreeFunctionType(
+ CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
+ }
+
+ llvm::Type *ResultType = nullptr;
+ // If there is something higher level prodding our CGFunctionInfo, then
+ // don't recurse into it again.
+ if (FunctionsBeingProcessed.count(FI)) {
+
+ ResultType = llvm::StructType::get(getLLVMContext());
+ SkippedLayout = true;
+ } else {
+
+ // Otherwise, we're good to go, go ahead and convert it.
+ ResultType = GetFunctionType(*FI);
+ }
+
+ RecordsBeingLaidOut.erase(Ty);
+
+ if (SkippedLayout)
+ TypeCache.clear();
+
+ if (RecordsBeingLaidOut.empty())
+ while (!DeferredRecords.empty())
+ ConvertRecordDeclType(DeferredRecords.pop_back_val());
+ return ResultType;
+}
+
/// ConvertType - Convert the specified type to its LLVM form.
llvm::Type *CodeGenTypes::ConvertType(QualType T) {
T = Context.getCanonicalType(T);
@@ -485,75 +555,9 @@
break;
}
case Type::FunctionNoProto:
- case Type::FunctionProto: {
- const FunctionType *FT = cast<FunctionType>(Ty);
- // First, check whether we can build the full function type. If the
- // function type depends on an incomplete type (e.g. a struct or enum), we
- // cannot lower the function type.
- if (!isFuncTypeConvertible(FT)) {
- // This function's type depends on an incomplete tag type.
-
- // Force conversion of all the relevant record types, to make sure
- // we re-convert the FunctionType when appropriate.
- if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
- ConvertRecordDeclType(RT->getDecl());
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
- for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
- if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
- ConvertRecordDeclType(RT->getDecl());
-
- // Return a placeholder type.
- ResultType = llvm::StructType::get(getLLVMContext());
-
- SkippedLayout = true;
- break;
- }
-
- // While we're converting the parameter types for a function, we don't want
- // to recursively convert any pointed-to structs. Converting directly-used
- // structs is ok though.
- if (!RecordsBeingLaidOut.insert(Ty).second) {
- ResultType = llvm::StructType::get(getLLVMContext());
-
- SkippedLayout = true;
- break;
- }
-
- // The function type can be built; call the appropriate routines to
- // build it.
- const CGFunctionInfo *FI;
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
- FI = &arrangeFreeFunctionType(
- CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
- } else {
- const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
- FI = &arrangeFreeFunctionType(
- CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
- }
-
- // If there is something higher level prodding our CGFunctionInfo, then
- // don't recurse into it again.
- if (FunctionsBeingProcessed.count(FI)) {
-
- ResultType = llvm::StructType::get(getLLVMContext());
- SkippedLayout = true;
- } else {
-
- // Otherwise, we're good to go, go ahead and convert it.
- ResultType = GetFunctionType(*FI);
- }
-
- RecordsBeingLaidOut.erase(Ty);
-
- if (SkippedLayout)
- TypeCache.clear();
-
- if (RecordsBeingLaidOut.empty())
- while (!DeferredRecords.empty())
- ConvertRecordDeclType(DeferredRecords.pop_back_val());
+ case Type::FunctionProto:
+ ResultType = ConvertFunctionType(T);
break;
- }
-
case Type::ObjCObject:
ResultType = ConvertType(cast<ObjCObjectType>(Ty)->getBaseType());
break;
@@ -624,6 +628,10 @@
}
break;
}
+ case Type::Pipe: {
+ ResultType = CGM.getOpenCLRuntime().getPipeType();
+ break;
+ }
}
assert(ResultType && "Didn't convert a type?");
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index c40c2b7..a96f23c 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -178,6 +178,14 @@
/// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T);
+ /// \brief Converts the GlobalDecl into an llvm::Type. This should be used
+ /// when we know the target of the function we want to convert. This is
+ /// because some functions (explicitly, those with pass_object_size
+ /// parameters) may not have the same signature as their type portrays, and
+ /// can only be called directly.
+ llvm::Type *ConvertFunctionType(QualType FT,
+ const FunctionDecl *FD = nullptr);
+
/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
@@ -264,11 +272,12 @@
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
CXXCtorType CT);
-
- const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
+ const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
+ const FunctionDecl *FD);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP);
+ const FunctionProtoType *FTP,
+ const CXXMethodDecl *MD);
/// "Arrange" the LLVM information for a call or type with the given
/// signature. This is largely an internal method; other clients
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 2486a49..7edd7ce 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -15,6 +15,8 @@
#include "CodeGenFunction.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ProfileData/CoverageMapping.h"
#include "llvm/ProfileData/CoverageMappingReader.h"
@@ -152,14 +154,13 @@
void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
FileIDMapping.clear();
- SmallVector<FileID, 8> Visited;
+ llvm::SmallSet<FileID, 8> Visited;
SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
for (const auto &Region : SourceRegions) {
SourceLocation Loc = Region.getStartLoc();
FileID File = SM.getFileID(Loc);
- if (std::find(Visited.begin(), Visited.end(), File) != Visited.end())
+ if (!Visited.insert(File).second)
continue;
- Visited.push_back(File);
unsigned Depth = 0;
for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
@@ -785,7 +786,7 @@
else
pushRegion(Count, getStart(S));
- if (const CaseStmt *CS = dyn_cast<CaseStmt>(S)) {
+ if (const auto *CS = dyn_cast<CaseStmt>(S)) {
Visit(CS->getLHS());
if (const Expr *RHS = CS->getRHS())
Visit(RHS);
@@ -910,11 +911,11 @@
}
void CoverageMappingModuleGen::addFunctionMappingRecord(
- llvm::GlobalVariable *NamePtr, StringRef NameValue,
- uint64_t FuncHash, const std::string &CoverageMapping) {
+ llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
+ const std::string &CoverageMapping, bool IsUsed) {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
if (!FunctionRecordTy) {
- #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
llvm::Type *FunctionRecordTypes[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
@@ -929,7 +930,10 @@
};
FunctionRecords.push_back(llvm::ConstantStruct::get(
FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
- CoverageMappings += CoverageMapping;
+ if (!IsUsed)
+ FunctionNames.push_back(
+ llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
+ CoverageMappings.push_back(CoverageMapping);
if (CGM.getCodeGenOpts().DumpCoverageMapping) {
// Dump the coverage mapping data for this function by decoding the
@@ -975,8 +979,10 @@
std::string FilenamesAndCoverageMappings;
llvm::raw_string_ostream OS(FilenamesAndCoverageMappings);
CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
- OS << CoverageMappings;
- size_t CoverageMappingSize = CoverageMappings.size();
+ std::string RawCoverageMappings =
+ llvm::join(CoverageMappings.begin(), CoverageMappings.end(), "");
+ OS << RawCoverageMappings;
+ size_t CoverageMappingSize = RawCoverageMappings.size();
size_t FilenamesSize = OS.str().size() - CoverageMappingSize;
// Append extra zeroes if necessary to ensure that the size of the filenames
// and coverage mappings is a multiple of 8.
@@ -993,30 +999,47 @@
llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size());
auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords);
+ llvm::Type *CovDataHeaderTypes[] = {
+#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
+#include "llvm/ProfileData/InstrProfData.inc"
+ };
+ auto CovDataHeaderTy =
+ llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
+ llvm::Constant *CovDataHeaderVals[] = {
+#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
+#include "llvm/ProfileData/InstrProfData.inc"
+ };
+ auto CovDataHeaderVal = llvm::ConstantStruct::get(
+ CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
+
// Create the coverage data record
- llvm::Type *CovDataTypes[] = {Int32Ty, Int32Ty,
- Int32Ty, Int32Ty,
- RecordsTy, FilenamesAndMappingsVal->getType()};
+ llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy,
+ FilenamesAndMappingsVal->getType()};
auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
- llvm::Constant *TUDataVals[] = {
- llvm::ConstantInt::get(Int32Ty, FunctionRecords.size()),
- llvm::ConstantInt::get(Int32Ty, FilenamesSize),
- llvm::ConstantInt::get(Int32Ty, CoverageMappingSize),
- llvm::ConstantInt::get(Int32Ty,
- /*Version=*/CoverageMappingVersion1),
- RecordsVal, FilenamesAndMappingsVal};
+ llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal,
+ FilenamesAndMappingsVal};
auto CovDataVal =
llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
- auto CovData = new llvm::GlobalVariable(CGM.getModule(), CovDataTy, true,
- llvm::GlobalValue::InternalLinkage,
- CovDataVal,
- llvm::getCoverageMappingVarName());
+ auto CovData = new llvm::GlobalVariable(
+ CGM.getModule(), CovDataTy, true, llvm::GlobalValue::InternalLinkage,
+ CovDataVal, llvm::getCoverageMappingVarName());
CovData->setSection(getCoverageSection(CGM));
CovData->setAlignment(8);
// Make sure the data doesn't get deleted.
CGM.addUsedGlobal(CovData);
+ // Create the deferred function records array
+ if (!FunctionNames.empty()) {
+ auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
+ FunctionNames.size());
+ auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
+ // This variable will *NOT* be emitted to the object file. It is used
+ // to pass the list of names referenced to codegen.
+ new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
+ llvm::GlobalValue::InternalLinkage, NamesArrVal,
+ llvm::getCoverageNamesVarName());
+ }
}
unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
diff --git a/lib/CodeGen/CoverageMappingGen.h b/lib/CodeGen/CoverageMappingGen.h
index 0d1bf6d..c202fe8 100644
--- a/lib/CodeGen/CoverageMappingGen.h
+++ b/lib/CodeGen/CoverageMappingGen.h
@@ -54,8 +54,9 @@
CoverageSourceInfo &SourceInfo;
llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries;
std::vector<llvm::Constant *> FunctionRecords;
+ std::vector<llvm::Constant *> FunctionNames;
llvm::StructType *FunctionRecordTy;
- std::string CoverageMappings;
+ std::vector<std::string> CoverageMappings;
public:
CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
@@ -70,7 +71,8 @@
void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName,
StringRef FunctionNameValue,
uint64_t FunctionHash,
- const std::string &CoverageMapping);
+ const std::string &CoverageMapping,
+ bool IsUsed = true);
/// \brief Emit the coverage mapping data for a translation unit.
void emit();
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index 9840afe..85cd154 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/lib/CodeGen/EHScopeStack.h
@@ -334,10 +334,6 @@
/// Pops a terminate handler off the stack.
void popTerminate();
- void pushPadEnd(llvm::BasicBlock *PadEndBB);
-
- void popPadEnd();
-
// Returns true iff the current scope is either empty or contains only
// lifetime markers, i.e. no real cleanup code
bool containsOnlyLifetimeMarkers(stable_iterator Old) const;
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0eea014..8b6322a 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -327,10 +327,9 @@
llvm::Value *Val);
void EmitThreadLocalInitFuncs(
CodeGenModule &CGM,
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
- CXXThreadLocals,
+ ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override;
+ ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction() const override { return true; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
@@ -535,9 +534,8 @@
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
- llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT));
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
@@ -2088,7 +2086,7 @@
const char *Name = "__cxa_atexit";
if (TLS) {
const llvm::Triple &T = CGF.getTarget().getTriple();
- Name = T.isMacOSX() ? "_tlv_atexit" : "__cxa_thread_atexit";
+ Name = T.isOSDarwin() ? "_tlv_atexit" : "__cxa_thread_atexit";
}
// We're assuming that the destructor function is something we can
@@ -2144,10 +2142,10 @@
static bool isThreadWrapperReplaceable(const VarDecl *VD,
CodeGen::CodeGenModule &CGM) {
assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
- // OS X prefers to have references to thread local variables to go through
+ // Darwin prefers to have references to thread local variables to go through
// the thread wrapper instead of directly referencing the backing variable.
return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- CGM.getTarget().getTriple().isMacOSX();
+ CGM.getTarget().getTriple().isOSDarwin();
}
/// Get the appropriate linkage for the wrapper function. This is essentially
@@ -2163,12 +2161,10 @@
return VarLinkage;
// If the thread wrapper is replaceable, give it appropriate linkage.
- if (isThreadWrapperReplaceable(VD, CGM)) {
- if (llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) ||
- llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
- return llvm::GlobalVariable::WeakAnyLinkage;
- return VarLinkage;
- }
+ if (isThreadWrapperReplaceable(VD, CGM))
+ if (!llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) &&
+ !llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
+ return VarLinkage;
return llvm::GlobalValue::WeakODRLinkage;
}
@@ -2182,28 +2178,46 @@
getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out);
}
+ // FIXME: If VD is a definition, we should regenerate the function attributes
+ // before returning.
if (llvm::Value *V = CGM.getModule().getNamedValue(WrapperName))
return cast<llvm::Function>(V);
- llvm::Type *RetTy = Val->getType();
- if (VD->getType()->isReferenceType())
- RetTy = RetTy->getPointerElementType();
+ QualType RetQT = VD->getType();
+ if (RetQT->isReferenceType())
+ RetQT = RetQT.getNonReferenceType();
- llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ getContext().getPointerType(RetQT), FunctionArgList(),
+ FunctionType::ExtInfo(), false);
+
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Wrapper =
llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
WrapperName.str(), &CGM.getModule());
+
+ CGM.SetLLVMFunctionAttributes(nullptr, FI, Wrapper);
+
+ if (VD->hasDefinition())
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
+
// Always resolve references to the wrapper at link time.
- if (!Wrapper->hasLocalLinkage() && !isThreadWrapperReplaceable(VD, CGM))
+ if (!Wrapper->hasLocalLinkage() && !(isThreadWrapperReplaceable(VD, CGM) &&
+ !llvm::GlobalVariable::isLinkOnceLinkage(Wrapper->getLinkage()) &&
+ !llvm::GlobalVariable::isWeakODRLinkage(Wrapper->getLinkage())))
Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
+
+ if (isThreadWrapperReplaceable(VD, CGM)) {
+ Wrapper->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
+ Wrapper->addFnAttr(llvm::Attribute::NoUnwind);
+ }
return Wrapper;
}
void ItaniumCXXABI::EmitThreadLocalInitFuncs(
- CodeGenModule &CGM,
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
- CXXThreadLocals, ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
+ CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
+ ArrayRef<llvm::Function *> CXXThreadLocalInits,
+ ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
llvm::Function *InitFunc = nullptr;
if (!CXXThreadLocalInits.empty()) {
// Generate a guarded initialization function.
@@ -2226,9 +2240,9 @@
.GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits,
Address(Guard, GuardAlign));
}
- for (auto &I : CXXThreadLocals) {
- const VarDecl *VD = I.first;
- llvm::GlobalVariable *Var = I.second;
+ for (const VarDecl *VD : CXXThreadLocals) {
+ llvm::GlobalVariable *Var =
+ cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
// Some targets require that all access to thread local variables go through
// the thread wrapper. This means that we cannot attempt to create a thread
@@ -2262,6 +2276,10 @@
Init = llvm::Function::Create(
FnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(),
&CGM.getModule());
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ CGM.getContext().VoidTy, FunctionArgList(), FunctionType::ExtInfo(),
+ false);
+ CGM.SetLLVMFunctionAttributes(nullptr, FI, cast<llvm::Function>(Init));
}
if (Init)
@@ -2305,18 +2323,19 @@
LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD,
QualType LValType) {
- QualType T = VD->getType();
- llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
- llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
+ llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD);
llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val);
- Val = CGF.Builder.CreateCall(Wrapper);
+ llvm::CallInst *CallVal = CGF.Builder.CreateCall(Wrapper);
+ if (isThreadWrapperReplaceable(VD, CGF.CGM))
+ CallVal->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
LValue LV;
if (VD->getType()->isReferenceType())
- LV = CGF.MakeNaturalAlignAddrLValue(Val, LValType);
+ LV = CGF.MakeNaturalAlignAddrLValue(CallVal, LValType);
else
- LV = CGF.MakeAddrLValue(Val, LValType, CGF.getContext().getDeclAlign(VD));
+ LV = CGF.MakeAddrLValue(CallVal, LValType,
+ CGF.getContext().getDeclAlign(VD));
// FIXME: need setObjCGCLValueClass?
return LV;
}
@@ -2712,6 +2731,9 @@
case Type::Auto:
llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::Pipe:
+ llvm_unreachable("Pipe types shouldn't get here");
+
case Type::Builtin:
// GCC treats vector and complex types as fundamental types.
case Type::Vector:
@@ -2936,6 +2958,9 @@
case Type::Auto:
llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::Pipe:
+ llvm_unreachable("Pipe type shouldn't get here");
+
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 8ef5331..93210d5 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -377,11 +377,9 @@
const ReturnAdjustment &RA) override;
void EmitThreadLocalInitFuncs(
- CodeGenModule &CGM,
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
- CXXThreadLocals,
+ CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override;
+ ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction() const override { return false; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
@@ -895,10 +893,10 @@
// In the MS ABI, the runtime handles the copy, and the catch handler is
// responsible for destruction.
VarDecl *CatchParam = S->getExceptionDecl();
- llvm::BasicBlock *CatchPadBB =
- CGF.Builder.GetInsertBlock()->getSinglePredecessor();
+ llvm::BasicBlock *CatchPadBB = CGF.Builder.GetInsertBlock();
llvm::CatchPadInst *CPI =
cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());
+ CGF.CurrentFuncletPad = CPI;
// If this is a catch-all or the catch parameter is unnamed, we don't need to
// emit an alloca to the object.
@@ -1525,15 +1523,14 @@
if (Info->PathToBaseWithVPtr.empty()) {
if (!CGM.IsCFIBlacklistedRecord(RD))
- BitsetsMD->addOperand(
- CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD));
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
return;
}
// Add a bitset entry for the least derived base belonging to this vftable.
if (!CGM.IsCFIBlacklistedRecord(Info->PathToBaseWithVPtr.back()))
- BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry(
- VTable, AddressPoint, Info->PathToBaseWithVPtr.back()));
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
+ Info->PathToBaseWithVPtr.back());
// Add a bitset entry for each derived class that is laid out at the same
// offset as the least derived base.
@@ -1552,14 +1549,12 @@
if (!Offset.isZero())
return;
if (!CGM.IsCFIBlacklistedRecord(DerivedRD))
- BitsetsMD->addOperand(
- CGM.CreateVTableBitSetEntry(VTable, AddressPoint, DerivedRD));
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
}
// Finally do the same for the most derived class.
if (Info->FullOffsetInMDC.isZero() && !CGM.IsCFIBlacklistedRecord(RD))
- BitsetsMD->addOperand(
- CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD));
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
}
void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -2197,11 +2192,9 @@
}
void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
- CodeGenModule &CGM,
- ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
- CXXThreadLocals,
+ CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits,
- ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
+ ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
// This will create a GV in the .CRT$XDU section. It will point to our
// initialization function. The CRT will call all of these function
// pointers at start-up time and, eventually, at thread-creation time.
@@ -2219,7 +2212,8 @@
std::vector<llvm::Function *> NonComdatInits;
for (size_t I = 0, E = CXXThreadLocalInitVars.size(); I != E; ++I) {
- llvm::GlobalVariable *GV = CXXThreadLocalInitVars[I];
+ llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
+ CGM.GetGlobalValue(CGM.getMangledName(CXXThreadLocalInitVars[I])));
llvm::Function *F = CXXThreadLocalInits[I];
// If the GV is already in a comdat group, then we have to join it.
@@ -3228,9 +3222,8 @@
const FunctionProtoType *FPT =
MPT->getPointeeType()->castAs<FunctionProtoType>();
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
- llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(
- CGM.getTypes().arrangeCXXMethodType(RD, FPT));
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
CGBuilderTy &Builder = CGF.Builder;
MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
@@ -3490,7 +3483,7 @@
auto Type = ABI.getClassHierarchyDescriptorType();
auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
/*Initializer=*/nullptr,
- StringRef(MangledName));
+ MangledName);
if (CHD->isWeakForLinker())
CHD->setComdat(CGM.getModule().getOrInsertComdat(CHD->getName()));
@@ -3528,7 +3521,7 @@
auto *BCA =
new llvm::GlobalVariable(Module, ArrType,
/*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, StringRef(MangledName));
+ /*Initializer=*/nullptr, MangledName);
if (BCA->isWeakForLinker())
BCA->setComdat(CGM.getModule().getOrInsertComdat(BCA->getName()));
@@ -3570,7 +3563,7 @@
auto Type = ABI.getBaseClassDescriptorType();
auto BCD =
new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, StringRef(MangledName));
+ /*Initializer=*/nullptr, MangledName);
if (BCD->isWeakForLinker())
BCD->setComdat(CGM.getModule().getOrInsertComdat(BCD->getName()));
@@ -3616,7 +3609,7 @@
// Forward-declare the complete object locator.
llvm::StructType *Type = ABI.getCompleteObjectLocatorType();
auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
- /*Initializer=*/nullptr, StringRef(MangledName));
+ /*Initializer=*/nullptr, MangledName);
// Initialize the CompleteObjectLocator.
llvm::Constant *Fields[] = {
@@ -3724,7 +3717,7 @@
CGM.getModule(), TypeDescriptorType, /*Constant=*/false,
getLinkageForRTTI(Type),
llvm::ConstantStruct::get(TypeDescriptorType, Fields),
- StringRef(MangledName));
+ MangledName);
if (Var->isWeakForLinker())
Var->setComdat(CGM.getModule().getOrInsertComdat(Var->getName()));
return llvm::ConstantExpr::getBitCast(Var, CGM.Int8PtrTy);
@@ -3967,7 +3960,7 @@
llvm::StructType *CTType = getCatchableTypeType();
auto *GV = new llvm::GlobalVariable(
CGM.getModule(), CTType, /*Constant=*/true, getLinkageForRTTI(T),
- llvm::ConstantStruct::get(CTType, Fields), StringRef(MangledName));
+ llvm::ConstantStruct::get(CTType, Fields), MangledName);
GV->setUnnamedAddr(true);
GV->setSection(".xdata");
if (GV->isWeakForLinker())
@@ -4085,7 +4078,7 @@
}
CTA = new llvm::GlobalVariable(
CGM.getModule(), CTAType, /*Constant=*/true, getLinkageForRTTI(T),
- llvm::ConstantStruct::get(CTAType, Fields), StringRef(MangledName));
+ llvm::ConstantStruct::get(CTAType, Fields), MangledName);
CTA->setUnnamedAddr(true);
CTA->setSection(".xdata");
if (CTA->isWeakForLinker())
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 0be5c55..82ad0db 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -103,8 +103,10 @@
PreprocessorOpts, CodeGenOpts,
*M, Diags, CoverageInfo));
- for (size_t i = 0, e = CodeGenOpts.DependentLibraries.size(); i < e; ++i)
- HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
+ for (auto &&Lib : CodeGenOpts.DependentLibraries)
+ HandleDependentLibrary(Lib);
+ for (auto &&Opt : CodeGenOpts.LinkerOptions)
+ HandleLinkerOption(Opt);
}
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
@@ -197,15 +199,18 @@
}
void HandleTranslationUnit(ASTContext &Ctx) override {
+ // Release the Builder when there is no error.
+ if (!Diags.hasErrorOccurred() && Builder)
+ Builder->Release();
+
+ // If there are errors before or when releasing the Builder, reset
+ // the module to stop here before invoking the backend.
if (Diags.hasErrorOccurred()) {
if (Builder)
Builder->clear();
M.reset();
return;
}
-
- if (Builder)
- Builder->Release();
}
void CompleteTentativeDefinition(VarDecl *D) override {
@@ -222,7 +227,7 @@
Builder->EmitVTable(RD);
}
- void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
+ void HandleLinkerOption(llvm::StringRef Opts) override {
Builder->AppendLinkerOptions(Opts);
}
diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index b397eb3..e3030a8 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -19,8 +19,8 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/BitstreamReader.h"
@@ -31,6 +31,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/TargetRegistry.h"
#include <memory>
@@ -42,6 +43,7 @@
class PCHContainerGenerator : public ASTConsumer {
DiagnosticsEngine &Diags;
const std::string MainFileName;
+ const std::string OutputFileName;
ASTContext *Ctx;
ModuleMap &MMap;
const HeaderSearchOptions &HeaderSearchOpts;
@@ -75,6 +77,13 @@
}
bool VisitTypeDecl(TypeDecl *D) {
+ // TagDecls may be deferred until after all decls have been merged and we
+ // know the complete type. Pure forward declarations will be skipped, but
+ // they don't need to be emitted into the module anyway.
+ if (auto *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isCompleteDefinition())
+ return true;
+
QualType QualTy = Ctx.getTypeDeclType(D);
if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
DI.getOrCreateStandaloneType(QualTy, D->getLocation());
@@ -130,7 +139,8 @@
const std::string &OutputFileName,
raw_pwrite_stream *OS,
std::shared_ptr<PCHBuffer> Buffer)
- : Diags(CI.getDiagnostics()), Ctx(nullptr),
+ : Diags(CI.getDiagnostics()), MainFileName(MainFileName),
+ OutputFileName(OutputFileName), Ctx(nullptr),
MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
HeaderSearchOpts(CI.getHeaderSearchOpts()),
PreprocessorOpts(CI.getPreprocessorOpts()),
@@ -155,7 +165,12 @@
M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
Builder.reset(new CodeGen::CodeGenModule(
*Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
- Builder->getModuleDebugInfo()->setModuleMap(MMap);
+
+ // Prepare CGDebugInfo to emit debug info for a clang module.
+ auto *DI = Builder->getModuleDebugInfo();
+ StringRef ModuleName = llvm::sys::path::filename(MainFileName);
+ DI->setPCHDescriptor({ModuleName, "", OutputFileName, ~1ULL});
+ DI->setModuleMap(MMap);
}
bool HandleTopLevelDecl(DeclGroupRef D) override {
@@ -179,6 +194,15 @@
if (Diags.hasErrorOccurred())
return;
+ if (D->isFromASTFile())
+ return;
+
+ // Anonymous tag decls are deferred until we are building their declcontext.
+ if (D->getName().empty())
+ return;
+
+ DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
+ DTV.TraverseDecl(D);
Builder->UpdateCompletedType(D);
}
@@ -203,7 +227,11 @@
M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx.getTargetInfo().getDataLayoutString());
- Builder->getModuleDebugInfo()->setDwoId(Buffer->Signature);
+
+ // PCH files don't have a signature field in the control block,
+ // but LLVM detects DWO CUs by looking for a non-zero DWO id.
+ uint64_t Signature = Buffer->Signature ? Buffer->Signature : ~1ULL;
+ Builder->getModuleDebugInfo()->setDwoId(Signature);
// Finalize the Builder.
if (Builder)
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 06a2e71..cdb0a6a 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -162,6 +162,23 @@
OS << ")\n";
}
+// Dynamically round a pointer up to a multiple of the given alignment.
+static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ CharUnits Align) {
+ llvm::Value *PtrAsInt = Ptr;
+ // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;
+ PtrAsInt = CGF.Builder.CreatePtrToInt(PtrAsInt, CGF.IntPtrTy);
+ PtrAsInt = CGF.Builder.CreateAdd(PtrAsInt,
+ llvm::ConstantInt::get(CGF.IntPtrTy, Align.getQuantity() - 1));
+ PtrAsInt = CGF.Builder.CreateAnd(PtrAsInt,
+ llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity()));
+ PtrAsInt = CGF.Builder.CreateIntToPtr(PtrAsInt,
+ Ptr->getType(),
+ Ptr->getName() + ".aligned");
+ return PtrAsInt;
+}
+
/// Emit va_arg for a platform using the common void* representation,
/// where arguments are simply emitted in an array of slots on the stack.
///
@@ -193,21 +210,14 @@
// If the CC aligns values higher than the slot size, do so if needed.
Address Addr = Address::invalid();
if (AllowHigherAlign && DirectAlign > SlotSize) {
- llvm::Value *PtrAsInt = Ptr;
- PtrAsInt = CGF.Builder.CreatePtrToInt(PtrAsInt, CGF.IntPtrTy);
- PtrAsInt = CGF.Builder.CreateAdd(PtrAsInt,
- llvm::ConstantInt::get(CGF.IntPtrTy, DirectAlign.getQuantity() - 1));
- PtrAsInt = CGF.Builder.CreateAnd(PtrAsInt,
- llvm::ConstantInt::get(CGF.IntPtrTy, -DirectAlign.getQuantity()));
- Addr = Address(CGF.Builder.CreateIntToPtr(PtrAsInt, Ptr->getType(),
- "argp.cur.aligned"),
- DirectAlign);
+ Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),
+ DirectAlign);
} else {
- Addr = Address(Ptr, SlotSize);
+ Addr = Address(Ptr, SlotSize);
}
// Advance the pointer past the argument, then store that back.
- CharUnits FullDirectSize = DirectSize.RoundUpToAlignment(SlotSize);
+ CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);
llvm::Value *NextPtr =
CGF.Builder.CreateConstInBoundsByteGEP(Addr.getPointer(), FullDirectSize,
"argp.next");
@@ -831,7 +841,13 @@
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
- bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
+ /// \brief Updates the number of available free registers, returns
+ /// true if any registers were allocated.
+ bool updateFreeRegs(QualType Ty, CCState &State) const;
+
+ bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg,
+ bool &NeedsPadding) const;
+ bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const;
/// \brief Rewrite the function info so that all memory arguments use
/// inalloca.
@@ -904,6 +920,11 @@
('T' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
+
+ StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
+ return "movl\t%ebp, %ebp"
+ "\t\t## marker for objc_retainAutoreleaseReturnValue";
+ }
};
}
@@ -993,9 +1014,10 @@
ASTContext &Context) const {
uint64_t Size = Context.getTypeSize(Ty);
- // Type must be register sized.
- if (!isRegisterSize(Size))
- return false;
+ // For i386, type must be register sized.
+ // For the MCU ABI, it only needs to be <= 8-byte
+ if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size)))
+ return false;
if (Ty->isVectorType()) {
// 64- and 128- bit vectors inside structures are not returned in
@@ -1042,7 +1064,8 @@
// integer register.
if (State.FreeRegs) {
--State.FreeRegs;
- return getNaturalAlignIndirectInReg(RetTy);
+ if (!IsMCUABI)
+ return getNaturalAlignIndirectInReg(RetTy);
}
return getNaturalAlignIndirect(RetTy, /*ByVal=*/false);
}
@@ -1182,7 +1205,8 @@
if (!ByVal) {
if (State.FreeRegs) {
--State.FreeRegs; // Non-byval indirects just use one pointer.
- return getNaturalAlignIndirectInReg(Ty);
+ if (!IsMCUABI)
+ return getNaturalAlignIndirectInReg(Ty);
}
return getNaturalAlignIndirect(Ty, false);
}
@@ -1213,9 +1237,7 @@
return Integer;
}
-bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
- bool &NeedsPadding) const {
- NeedsPadding = false;
+bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const {
if (!IsSoftFloatABI) {
Class C = classify(Ty);
if (C == Float)
@@ -1243,22 +1265,24 @@
}
State.FreeRegs -= SizeInRegs;
+ return true;
+}
+
+bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State,
+ bool &InReg,
+ bool &NeedsPadding) const {
+ NeedsPadding = false;
+ InReg = !IsMCUABI;
+
+ if (!updateFreeRegs(Ty, State))
+ return false;
+
+ if (IsMCUABI)
+ return true;
if (State.CC == llvm::CallingConv::X86_FastCall ||
State.CC == llvm::CallingConv::X86_VectorCall) {
- if (Size > 32)
- return false;
-
- if (Ty->isIntegralOrEnumerationType())
- return true;
-
- if (Ty->isPointerType())
- return true;
-
- if (Ty->isReferenceType())
- return true;
-
- if (State.FreeRegs)
+ if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs)
NeedsPadding = true;
return false;
@@ -1267,6 +1291,25 @@
return true;
}
+bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
+ if (!updateFreeRegs(Ty, State))
+ return false;
+
+ if (IsMCUABI)
+ return false;
+
+ if (State.CC == llvm::CallingConv::X86_FastCall ||
+ State.CC == llvm::CallingConv::X86_VectorCall) {
+ if (getContext().getTypeSize(Ty) > 32)
+ return false;
+
+ return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() ||
+ Ty->isReferenceType());
+ }
+
+ return true;
+}
+
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// FIXME: Set alignment on indirect arguments.
@@ -1317,12 +1360,15 @@
llvm::LLVMContext &LLVMContext = getVMContext();
llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- bool NeedsPadding;
- if (shouldUseInReg(Ty, State, NeedsPadding)) {
+ bool NeedsPadding, InReg;
+ if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) {
unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
- return ABIArgInfo::getDirectInReg(Result);
+ if (InReg)
+ return ABIArgInfo::getDirectInReg(Result);
+ else
+ return ABIArgInfo::getDirect(Result);
}
llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr;
@@ -1330,8 +1376,11 @@
// of those arguments will match the struct. This is important because the
// LLVM backend isn't smart enough to remove byval, which inhibits many
// optimizations.
+ // Don't do this for the MCU if there are still free integer registers
+ // (see X86_64 ABI for full explanation).
if (getContext().getTypeSize(Ty) <= 4*32 &&
- canExpandIndirectArgument(Ty, getContext()))
+ canExpandIndirectArgument(Ty, getContext()) &&
+ (!IsMCUABI || State.FreeRegs == 0))
return ABIArgInfo::getExpandWithPadding(
State.CC == llvm::CallingConv::X86_FastCall ||
State.CC == llvm::CallingConv::X86_VectorCall,
@@ -1361,14 +1410,14 @@
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- bool NeedsPadding;
- bool InReg = shouldUseInReg(Ty, State, NeedsPadding);
+ bool InReg = shouldPrimitiveUseInReg(Ty, State);
if (Ty->isPromotableIntegerType()) {
if (InReg)
return ABIArgInfo::getExtendInReg();
return ABIArgInfo::getExtend();
}
+
if (InReg)
return ABIArgInfo::getDirectInReg();
return ABIArgInfo::getDirect();
@@ -1376,15 +1425,15 @@
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
CCState State(FI.getCallingConvention());
- if (State.CC == llvm::CallingConv::X86_FastCall)
+ if (IsMCUABI)
+ State.FreeRegs = 3;
+ else if (State.CC == llvm::CallingConv::X86_FastCall)
State.FreeRegs = 2;
else if (State.CC == llvm::CallingConv::X86_VectorCall) {
State.FreeRegs = 2;
State.FreeSSERegs = 6;
} else if (FI.getHasRegParm())
State.FreeRegs = FI.getRegParm();
- else if (IsMCUABI)
- State.FreeRegs = 3;
else
State.FreeRegs = DefaultNumRegisterParameters;
@@ -1395,7 +1444,8 @@
// return value was sret and put it in a register ourselves if appropriate.
if (State.FreeRegs) {
--State.FreeRegs; // The sret parameter consumes a register.
- FI.getReturnInfo().setInReg(true);
+ if (!IsMCUABI)
+ FI.getReturnInfo().setInReg(true);
}
}
@@ -1429,7 +1479,7 @@
// Insert padding bytes to respect alignment.
CharUnits FieldEnd = StackOffset;
- StackOffset = FieldEnd.RoundUpToAlignment(FieldAlign);
+ StackOffset = FieldEnd.alignTo(FieldAlign);
if (StackOffset != FieldEnd) {
CharUnits NumBytes = StackOffset - FieldEnd;
llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext());
@@ -1564,6 +1614,10 @@
llvm::AttributeSet::FunctionIndex,
B));
}
+ if (FD->hasAttr<AnyX86InterruptAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+ }
}
}
@@ -1869,6 +1923,16 @@
('T' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
+
+ void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const override {
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (FD->hasAttr<AnyX86InterruptAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+ }
+ }
+ }
};
class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
@@ -1986,6 +2050,13 @@
CodeGen::CodeGenModule &CGM) const {
TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (FD->hasAttr<AnyX86InterruptAttr>()) {
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ Fn->setCallingConv(llvm::CallingConv::X86_INTR);
+ }
+ }
+
addStackProbeSizeTargetAttribute(D, GV, CGM);
}
}
@@ -2730,7 +2801,7 @@
// the second element at offset 8. Check for this:
unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
unsigned HiAlign = TD.getABITypeAlignment(Hi);
- unsigned HiStart = llvm::RoundUpToAlignment(LoSize, HiAlign);
+ unsigned HiStart = llvm::alignTo(LoSize, HiAlign);
assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
// To handle this, we have to increase the size of the low part so that the
@@ -3072,19 +3143,10 @@
// byte boundary if alignment needed by type exceeds 8 byte boundary.
// It isn't stated explicitly in the standard, but in practice we use
// alignment greater than 16 where necessary.
- uint64_t Align = CGF.getContext().getTypeAlignInChars(Ty).getQuantity();
- if (Align > 8) {
- // overflow_arg_area = (overflow_arg_area + align - 1) & -align;
- llvm::Value *Offset =
- llvm::ConstantInt::get(CGF.Int64Ty, Align - 1);
- overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
- llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
- CGF.Int64Ty);
- llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int64Ty, -(uint64_t)Align);
- overflow_arg_area =
- CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
- overflow_arg_area->getType(),
- "overflow_arg_area.align");
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty);
+ if (Align > CharUnits::fromQuantity(8)) {
+ overflow_arg_area = emitRoundPointerUpToAlignment(CGF, overflow_arg_area,
+ Align);
}
// AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
@@ -3106,7 +3168,7 @@
CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
// AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
- return Address(Res, CharUnits::fromQuantity(Align));
+ return Address(Res, Align);
}
Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -3412,8 +3474,10 @@
namespace {
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
+bool IsSoftFloatABI;
public:
- PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+ PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI)
+ : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {}
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
@@ -3421,8 +3485,8 @@
class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- PPC32TargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT)) {}
+ PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI)
+ : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI)) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
@@ -3454,6 +3518,7 @@
bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64;
bool isInt =
Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType();
+ bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64;
// All aggregates are passed indirectly? That doesn't seem consistent
// with the argument-lowering code.
@@ -3463,7 +3528,7 @@
// The calling convention either uses 1-2 GPRs or 1 FPR.
Address NumRegsAddr = Address::invalid();
- if (isInt) {
+ if (isInt || IsSoftFloatABI) {
NumRegsAddr = Builder.CreateStructGEP(VAList, 0, CharUnits::Zero(), "gpr");
} else {
NumRegsAddr = Builder.CreateStructGEP(VAList, 1, CharUnits::One(), "fpr");
@@ -3472,7 +3537,7 @@
llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs");
// "Align" the register count when TY is i64.
- if (isI64) {
+ if (isI64 || (isF64 && IsSoftFloatABI)) {
NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1));
NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U));
}
@@ -3501,14 +3566,14 @@
assert(RegAddr.getElementType() == CGF.Int8Ty);
// Floating-point registers start after the general-purpose registers.
- if (!isInt) {
+ if (!(isInt || IsSoftFloatABI)) {
RegAddr = Builder.CreateConstInBoundsByteGEP(RegAddr,
CharUnits::fromQuantity(32));
}
// Get the address of the saved value by scaling the number of
// registers we've used by the number of
- CharUnits RegSize = CharUnits::fromQuantity(isInt ? 4 : 8);
+ CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8);
llvm::Value *RegOffset =
Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity()));
RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty,
@@ -3517,7 +3582,9 @@
RegAddr = Builder.CreateElementBitCast(RegAddr, DirectTy);
// Increase the used-register count.
- NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(isI64 ? 2 : 1));
+ NumRegs =
+ Builder.CreateAdd(NumRegs,
+ Builder.getInt8((isI64 || (isF64 && IsSoftFloatABI)) ? 2 : 1));
Builder.CreateStore(NumRegs, NumRegsAddr);
CGF.EmitBranch(Cont);
@@ -3534,18 +3601,23 @@
CharUnits Size;
if (!isIndirect) {
auto TypeInfo = CGF.getContext().getTypeInfoInChars(Ty);
- Size = TypeInfo.first.RoundUpToAlignment(OverflowAreaAlign);
+ Size = TypeInfo.first.alignTo(OverflowAreaAlign);
} else {
Size = CGF.getPointerSize();
}
Address OverflowAreaAddr =
Builder.CreateStructGEP(VAList, 3, CharUnits::fromQuantity(4));
- Address OverflowArea(Builder.CreateLoad(OverflowAreaAddr),
+ Address OverflowArea(Builder.CreateLoad(OverflowAreaAddr, "argp.cur"),
OverflowAreaAlign);
-
- // The current address is the address of the varargs element.
- // FIXME: do we not need to round up to alignment?
+ // Round up address of argument to alignment
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty);
+ if (Align > OverflowAreaAlign) {
+ llvm::Value *Ptr = OverflowArea.getPointer();
+ OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align),
+ Align);
+ }
+
MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy);
// Increase the overflow area.
@@ -3980,13 +4052,13 @@
// Types up to 8 bytes are passed as integer type (which will be
// properly aligned in the argument save area doubleword).
if (Bits <= GPRBits)
- CoerceTy = llvm::IntegerType::get(getVMContext(),
- llvm::RoundUpToAlignment(Bits, 8));
+ CoerceTy =
+ llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
// Larger types are passed as arrays, with the base type selected
// according to the required alignment in the save area.
else {
uint64_t RegBits = ABIAlign * 8;
- uint64_t NumRegs = llvm::RoundUpToAlignment(Bits, RegBits) / RegBits;
+ uint64_t NumRegs = llvm::alignTo(Bits, RegBits) / RegBits;
llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits);
CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
}
@@ -4046,8 +4118,8 @@
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, nullptr);
} else
- CoerceTy = llvm::IntegerType::get(getVMContext(),
- llvm::RoundUpToAlignment(Bits, 8));
+ CoerceTy =
+ llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
return ABIArgInfo::getDirect(CoerceTy);
}
@@ -4440,7 +4512,7 @@
reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
reg_top_index = 1; // field number for __gr_top
reg_top_offset = CharUnits::fromQuantity(8);
- RegSize = llvm::RoundUpToAlignment(RegSize, 8);
+ RegSize = llvm::alignTo(RegSize, 8);
} else {
// 4 is the field number of __vr_offs.
reg_offs_p =
@@ -4610,7 +4682,7 @@
if (IsIndirect)
StackSize = StackSlotSize;
else
- StackSize = TyInfo.first.RoundUpToAlignment(StackSlotSize);
+ StackSize = TyInfo.first.alignTo(StackSlotSize);
llvm::Value *StackSizeC = CGF.Builder.getSize(StackSize);
llvm::Value *NewStack =
@@ -4724,6 +4796,11 @@
}
}
+ bool isAndroid() const {
+ return (getTarget().getTriple().getEnvironment() ==
+ llvm::Triple::Android);
+ }
+
ABIKind getABIKind() const { return Kind; }
private:
@@ -4867,7 +4944,7 @@
/// Return the default calling convention that LLVM will use.
llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
// The default calling convention that LLVM will infer.
- if (isEABIHF() || getTarget().getTriple().isWatchOS())
+ if (isEABIHF() || getTarget().getTriple().isWatchABI())
return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
return llvm::CallingConv::ARM_AAPCS;
@@ -5218,7 +5295,7 @@
} else if (Size <= 128 && getABIKind() == AAPCS16_VFP) {
llvm::Type *Int32Ty = llvm::Type::getInt32Ty(getVMContext());
llvm::Type *CoerceTy =
- llvm::ArrayType::get(Int32Ty, llvm::RoundUpToAlignment(Size, 32) / 32);
+ llvm::ArrayType::get(Int32Ty, llvm::alignTo(Size, 32) / 32);
return ABIArgInfo::getDirect(CoerceTy);
}
@@ -5227,15 +5304,27 @@
/// isIllegalVector - check whether Ty is an illegal vector type.
bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- // Check whether VT is legal.
- unsigned NumElements = VT->getNumElements();
- uint64_t Size = getContext().getTypeSize(VT);
- // NumElements should be power of 2.
- if ((NumElements & (NumElements - 1)) != 0)
- return true;
- // Size should be greater than 32 bits.
- return Size <= 32;
+ if (const VectorType *VT = Ty->getAs<VectorType> ()) {
+ if (isAndroid()) {
+ // Android shipped using Clang 3.1, which supported a slightly different
+ // vector ABI. The primary differences were that 3-element vector types
+ // were legal, and so were sub 32-bit vectors (i.e. <2 x i8>). This path
+ // accepts that legacy behavior for Android only.
+ // Check whether VT is legal.
+ unsigned NumElements = VT->getNumElements();
+ // NumElements should be power of 2 or equal to 3.
+ if (!llvm::isPowerOf2_32(NumElements) && NumElements != 3)
+ return true;
+ } else {
+ // Check whether VT is legal.
+ unsigned NumElements = VT->getNumElements();
+ uint64_t Size = getContext().getTypeSize(VT);
+ // NumElements should be power of 2.
+ if (!llvm::isPowerOf2_32(NumElements))
+ return true;
+ // Size should be greater than 32 bits.
+ return Size <= 32;
+ }
}
return false;
}
@@ -5893,6 +5982,26 @@
else if (FD->hasAttr<NoMips16Attr>()) {
Fn->addFnAttr("nomips16");
}
+
+ const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
+ if (!Attr)
+ return;
+
+ const char *Kind;
+ switch (Attr->getInterrupt()) {
+ case MipsInterruptAttr::eic: Kind = "eic"; break;
+ case MipsInterruptAttr::sw0: Kind = "sw0"; break;
+ case MipsInterruptAttr::sw1: Kind = "sw1"; break;
+ case MipsInterruptAttr::hw0: Kind = "hw0"; break;
+ case MipsInterruptAttr::hw1: Kind = "hw1"; break;
+ case MipsInterruptAttr::hw2: Kind = "hw2"; break;
+ case MipsInterruptAttr::hw3: Kind = "hw3"; break;
+ case MipsInterruptAttr::hw4: Kind = "hw4"; break;
+ case MipsInterruptAttr::hw5: Kind = "hw5"; break;
+ }
+
+ Fn->addFnAttr("interrupt", Kind);
+
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
@@ -5996,8 +6105,8 @@
Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes),
(uint64_t)StackAlignInBytes);
- unsigned CurrOffset = llvm::RoundUpToAlignment(Offset, Align);
- Offset = CurrOffset + llvm::RoundUpToAlignment(TySize, Align * 8) / 8;
+ unsigned CurrOffset = llvm::alignTo(Offset, Align);
+ Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;
if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {
// Ignore empty aggregates.
@@ -6498,7 +6607,7 @@
return;
// Finish the current 64-bit word.
- uint64_t Aligned = llvm::RoundUpToAlignment(Size, 64);
+ uint64_t Aligned = llvm::alignTo(Size, 64);
if (Aligned > Size && Aligned <= ToSize) {
Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));
Size = Aligned;
@@ -6615,7 +6724,7 @@
CoerceBuilder CB(getVMContext(), getDataLayout());
CB.addStruct(0, StrTy);
- CB.pad(llvm::RoundUpToAlignment(CB.DL.getTypeSizeInBits(StrTy), 64));
+ CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64));
// Try to use the original type for coercion.
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
@@ -6657,7 +6766,7 @@
case ABIArgInfo::Direct: {
auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
- Stride = CharUnits::fromQuantity(AllocSize).RoundUpToAlignment(SlotSize);
+ Stride = CharUnits::fromQuantity(AllocSize).alignTo(SlotSize);
ArgAddr = Addr;
break;
}
@@ -6884,7 +6993,7 @@
Val = Builder.CreateBitCast(AP, ArgPtrTy);
ArgSize = CharUnits::fromQuantity(
getDataLayout().getTypeAllocSize(AI.getCoerceToType()));
- ArgSize = ArgSize.RoundUpToAlignment(SlotSize);
+ ArgSize = ArgSize.alignTo(SlotSize);
break;
case ABIArgInfo::Indirect:
Val = Builder.CreateElementBitCast(AP, ArgPtrTy);
@@ -7428,7 +7537,8 @@
}
case llvm::Triple::ppc:
- return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
+ return *(TheTargetCodeGenInfo =
+ new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft"));
case llvm::Triple::ppc64:
if (Triple.isOSBinFormatELF()) {
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index fdbae11..b45f290 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -8,17 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Action.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Regex.h"
#include <cassert>
using namespace clang::driver;
using namespace llvm::opt;
-Action::~Action() {
- if (OwnsInputs) {
- for (iterator it = begin(), ie = end(); it != ie; ++it)
- delete *it;
- }
-}
+Action::~Action() {}
const char *Action::getClassName(ActionClass AC) {
switch (AC) {
@@ -51,36 +48,53 @@
void BindArchAction::anchor() {}
-BindArchAction::BindArchAction(std::unique_ptr<Action> Input,
- const char *_ArchName)
- : Action(BindArchClass, std::move(Input)), ArchName(_ArchName) {}
+BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
+ : Action(BindArchClass, Input), ArchName(_ArchName) {}
+
+// Converts CUDA GPU architecture, e.g. "sm_21", to its corresponding virtual
+// compute arch, e.g. "compute_20". Returns null if the input arch is null or
+// doesn't match an existing arch.
+static const char* GpuArchToComputeName(const char *ArchName) {
+ if (!ArchName)
+ return nullptr;
+ return llvm::StringSwitch<const char *>(ArchName)
+ .Cases("sm_20", "sm_21", "compute_20")
+ .Case("sm_30", "compute_30")
+ .Case("sm_32", "compute_32")
+ .Case("sm_35", "compute_35")
+ .Case("sm_37", "compute_37")
+ .Case("sm_50", "compute_50")
+ .Case("sm_52", "compute_52")
+ .Case("sm_53", "compute_53")
+ .Default(nullptr);
+}
void CudaDeviceAction::anchor() {}
-CudaDeviceAction::CudaDeviceAction(std::unique_ptr<Action> Input,
- const char *ArchName,
- const char *DeviceTriple, bool AtTopLevel)
- : Action(CudaDeviceClass, std::move(Input)), GpuArchName(ArchName),
- DeviceTriple(DeviceTriple), AtTopLevel(AtTopLevel) {}
+CudaDeviceAction::CudaDeviceAction(Action *Input, const char *ArchName,
+ bool AtTopLevel)
+ : Action(CudaDeviceClass, Input), GpuArchName(ArchName),
+ AtTopLevel(AtTopLevel) {
+ assert(!GpuArchName || IsValidGpuArchName(GpuArchName));
+}
+
+const char *CudaDeviceAction::getComputeArchName() const {
+ return GpuArchToComputeName(GpuArchName);
+}
+
+bool CudaDeviceAction::IsValidGpuArchName(llvm::StringRef ArchName) {
+ return GpuArchToComputeName(ArchName.data()) != nullptr;
+}
void CudaHostAction::anchor() {}
-CudaHostAction::CudaHostAction(std::unique_ptr<Action> Input,
- const ActionList &DeviceActions,
- const char *DeviceTriple)
- : Action(CudaHostClass, std::move(Input)), DeviceActions(DeviceActions),
- DeviceTriple(DeviceTriple) {}
-
-CudaHostAction::~CudaHostAction() {
- for (auto &DA : DeviceActions)
- delete DA;
-}
+CudaHostAction::CudaHostAction(Action *Input, const ActionList &DeviceActions)
+ : Action(CudaHostClass, Input), DeviceActions(DeviceActions) {}
void JobAction::anchor() {}
-JobAction::JobAction(ActionClass Kind, std::unique_ptr<Action> Input,
- types::ID Type)
- : Action(Kind, std::move(Input), Type) {}
+JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
+ : Action(Kind, Input, Type) {}
JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
@@ -88,45 +102,38 @@
void PreprocessJobAction::anchor() {}
-PreprocessJobAction::PreprocessJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(PreprocessJobClass, std::move(Input), OutputType) {}
+PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PreprocessJobClass, Input, OutputType) {}
void PrecompileJobAction::anchor() {}
-PrecompileJobAction::PrecompileJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(PrecompileJobClass, std::move(Input), OutputType) {}
+PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PrecompileJobClass, Input, OutputType) {}
void AnalyzeJobAction::anchor() {}
-AnalyzeJobAction::AnalyzeJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(AnalyzeJobClass, std::move(Input), OutputType) {}
+AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AnalyzeJobClass, Input, OutputType) {}
void MigrateJobAction::anchor() {}
-MigrateJobAction::MigrateJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(MigrateJobClass, std::move(Input), OutputType) {}
+MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
+ : JobAction(MigrateJobClass, Input, OutputType) {}
void CompileJobAction::anchor() {}
-CompileJobAction::CompileJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(CompileJobClass, std::move(Input), OutputType) {}
+CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(CompileJobClass, Input, OutputType) {}
void BackendJobAction::anchor() {}
-BackendJobAction::BackendJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(BackendJobClass, std::move(Input), OutputType) {}
+BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
+ : JobAction(BackendJobClass, Input, OutputType) {}
void AssembleJobAction::anchor() {}
-AssembleJobAction::AssembleJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(AssembleJobClass, std::move(Input), OutputType) {}
+AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AssembleJobClass, Input, OutputType) {}
void LinkJobAction::anchor() {}
@@ -148,21 +155,20 @@
void VerifyJobAction::anchor() {}
-VerifyJobAction::VerifyJobAction(ActionClass Kind,
- std::unique_ptr<Action> Input, types::ID Type)
- : JobAction(Kind, std::move(Input), Type) {
+VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
+ types::ID Type)
+ : JobAction(Kind, Input, Type) {
assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
"ActionClass is not a valid VerifyJobAction");
}
void VerifyDebugInfoJobAction::anchor() {}
-VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(
- std::unique_ptr<Action> Input, types::ID Type)
- : VerifyJobAction(VerifyDebugInfoJobClass, std::move(Input), Type) {}
+VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
+ types::ID Type)
+ : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
void VerifyPCHJobAction::anchor() {}
-VerifyPCHJobAction::VerifyPCHJobAction(std::unique_ptr<Action> Input,
- types::ID Type)
- : VerifyJobAction(VerifyPCHJobClass, std::move(Input), Type) {}
+VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
+ : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 101d1fc..1c2eecd 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -24,8 +24,9 @@
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
InputArgList *_Args, DerivedArgList *_TranslatedArgs)
- : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
- TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
+ : TheDriver(D), DefaultToolChain(_DefaultToolChain),
+ CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr),
+ Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
ForDiagnostics(false) {}
Compilation::~Compilation() {
@@ -39,11 +40,6 @@
if (it->second != TranslatedArgs)
delete it->second;
- // Free the actions, if built.
- for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
- it != ie; ++it)
- delete *it;
-
// Free redirections of stdout/stderr.
if (Redirects) {
delete Redirects[1];
@@ -207,7 +203,8 @@
ForDiagnostics = true;
// Free actions and jobs.
- DeleteContainerPointers(Actions);
+ Actions.clear();
+ AllActions.clear();
Jobs.clear();
// Clear temporary/results file lists.
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 425c915..5c01ef0 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -209,6 +209,7 @@
DerivedArgList *DAL = new DerivedArgList(Args);
bool HasNostdlib = Args.hasArg(options::OPT_nostdlib);
+ bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs);
for (Arg *A : Args) {
// Unfortunately, we have to parse some forwarding options (-Xassembler,
// -Xlinker, -Xpreprocessor) because we either integrate their functionality
@@ -252,7 +253,7 @@
StringRef Value = A->getValue();
// Rewrite unless -nostdlib is present.
- if (!HasNostdlib && Value == "stdc++") {
+ if (!HasNostdlib && !HasNodefaultlib && Value == "stdc++") {
DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_reserved_lib_stdcxx));
continue;
}
@@ -491,6 +492,10 @@
// The compilation takes ownership of Args.
Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs);
+ C->setCudaDeviceToolChain(
+ &getToolChain(C->getArgs(), llvm::Triple(TC.getTriple().isArch64Bit()
+ ? "nvptx64-nvidia-cuda"
+ : "nvptx-nvidia-cuda")));
if (!HandleImmediateArgs(*C))
return C;
@@ -501,10 +506,9 @@
// Construct the list of abstract actions to perform for this compilation. On
// MachO targets this uses the driver-driver and universal actions.
if (TC.getTriple().isOSBinFormatMachO())
- BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(), Inputs,
- C->getActions());
+ BuildUniversalActions(*C, C->getDefaultToolChain(), Inputs);
else
- BuildActions(C->getDefaultToolChain(), C->getArgs(), Inputs,
+ BuildActions(*C, C->getDefaultToolChain(), C->getArgs(), Inputs,
C->getActions());
if (CCCPrintPhases) {
@@ -617,9 +621,9 @@
// Darwin OSes this uses the driver-driver and builds universal actions.
const ToolChain &TC = C.getDefaultToolChain();
if (TC.getTriple().isOSBinFormatMachO())
- BuildUniversalActions(TC, C.getArgs(), Inputs, C.getActions());
+ BuildUniversalActions(C, TC, Inputs);
else
- BuildActions(TC, C.getArgs(), Inputs, C.getActions());
+ BuildActions(C, TC, C.getArgs(), Inputs, C.getActions());
BuildJobs(C);
@@ -695,11 +699,11 @@
}
void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) {
- // Since argumentsFitWithinSystemLimits() may underestimate system's capacity
+ // Since commandLineFitsWithinSystemLimits() may underestimate system's capacity
// if the tool does not support response files, there is a chance/ that things
// will just work without a response file, so we silently just skip it.
if (Cmd.getCreator().getResponseFilesSupport() == Tool::RF_None ||
- llvm::sys::argumentsFitWithinSystemLimits(Cmd.getArguments()))
+ llvm::sys::commandLineFitsWithinSystemLimits(Cmd.getExecutable(), Cmd.getArguments()))
return;
std::string TmpName = GetTemporaryPath("response", "txt");
@@ -945,10 +949,11 @@
os << '"' << BIA->getArchName() << '"' << ", {"
<< PrintActions1(C, *BIA->begin(), Ids) << "}";
} else if (CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) {
- os << '"' << CDA->getGpuArchName() << '"' << ", {"
- << PrintActions1(C, *CDA->begin(), Ids) << "}";
+ os << '"'
+ << (CDA->getGpuArchName() ? CDA->getGpuArchName() : "(multiple archs)")
+ << '"' << ", {" << PrintActions1(C, *CDA->begin(), Ids) << "}";
} else {
- ActionList *AL;
+ const ActionList *AL;
if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) {
os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}"
<< ", gpu binaries ";
@@ -997,9 +1002,10 @@
return false;
}
-void Driver::BuildUniversalActions(const ToolChain &TC, DerivedArgList &Args,
- const InputList &BAInputs,
- ActionList &Actions) const {
+void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC,
+ const InputList &BAInputs) const {
+ DerivedArgList &Args = C.getArgs();
+ ActionList &Actions = C.getActions();
llvm::PrettyStackTraceString CrashInfo("Building universal build actions");
// Collect the list of architectures. Duplicates are allowed, but should only
// be handled once (in the order seen).
@@ -1028,7 +1034,7 @@
Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName()));
ActionList SingleActions;
- BuildActions(TC, Args, BAInputs, SingleActions);
+ BuildActions(C, TC, Args, BAInputs, SingleActions);
// Add in arch bindings for every top level action, as well as lipo and
// dsymutil steps if needed.
@@ -1044,19 +1050,15 @@
<< types::getTypeName(Act->getType());
ActionList Inputs;
- for (unsigned i = 0, e = Archs.size(); i != e; ++i) {
- Inputs.push_back(
- new BindArchAction(std::unique_ptr<Action>(Act), Archs[i]));
- if (i != 0)
- Inputs.back()->setOwnsInputs(false);
- }
+ for (unsigned i = 0, e = Archs.size(); i != e; ++i)
+ Inputs.push_back(C.MakeAction<BindArchAction>(Act, Archs[i]));
// Lipo if necessary, we do it this way because we need to set the arch flag
// so that -Xarch_ gets overwritten.
if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing)
Actions.append(Inputs.begin(), Inputs.end());
else
- Actions.push_back(new LipoJobAction(Inputs, Act->getType()));
+ Actions.push_back(C.MakeAction<LipoJobAction>(Inputs, Act->getType()));
// Handle debug info queries.
Arg *A = Args.getLastArg(options::OPT_g_Group);
@@ -1072,15 +1074,16 @@
ActionList Inputs;
Inputs.push_back(Actions.back());
Actions.pop_back();
- Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
+ Actions.push_back(
+ C.MakeAction<DsymutilJobAction>(Inputs, types::TY_dSYM));
}
// Verify the debug info output.
if (Args.hasArg(options::OPT_verify_debug_info)) {
- std::unique_ptr<Action> VerifyInput(Actions.back());
+ Action* LastAction = Actions.back();
Actions.pop_back();
- Actions.push_back(new VerifyDebugInfoJobAction(std::move(VerifyInput),
- types::TY_Nothing));
+ Actions.push_back(C.MakeAction<VerifyDebugInfoJobAction>(
+ LastAction, types::TY_Nothing));
}
}
}
@@ -1278,32 +1281,29 @@
// Actions and /p Current is released. Otherwise the function creates
// and returns a new CudaHostAction which wraps /p Current and device
// side actions.
-static std::unique_ptr<Action>
-buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args,
- const Arg *InputArg, std::unique_ptr<Action> HostAction,
- ActionList &Actions) {
- // Figure out which NVPTX triple to use for device-side compilation based on
- // whether host is 64-bit.
- const char *DeviceTriple = TC.getTriple().isArch64Bit()
- ? "nvptx64-nvidia-cuda"
- : "nvptx-nvidia-cuda";
+static Action *buildCudaActions(Compilation &C, DerivedArgList &Args,
+ const Arg *InputArg, Action *HostAction,
+ ActionList &Actions) {
Arg *PartialCompilationArg = Args.getLastArg(options::OPT_cuda_host_only,
options::OPT_cuda_device_only);
// Host-only compilation case.
if (PartialCompilationArg &&
PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only))
- return std::unique_ptr<Action>(
- new CudaHostAction(std::move(HostAction), {}, DeviceTriple));
+ return C.MakeAction<CudaHostAction>(HostAction, ActionList());
// Collect all cuda_gpu_arch parameters, removing duplicates.
SmallVector<const char *, 4> GpuArchList;
llvm::StringSet<> GpuArchNames;
for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) {
- A->claim();
- if (GpuArchNames.insert(A->getValue()).second)
- GpuArchList.push_back(A->getValue());
- }
+ if (!A->getOption().matches(options::OPT_cuda_gpu_arch_EQ))
+ continue;
+ A->claim();
+
+ const auto& Arch = A->getValue();
+ if (!CudaDeviceAction::IsValidGpuArchName(Arch))
+ C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << Arch;
+ else if (GpuArchNames.insert(Arch).second)
+ GpuArchList.push_back(Arch);
}
// Default to sm_20 which is the lowest common denominator for supported GPUs.
@@ -1317,19 +1317,19 @@
CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg));
// Build actions for all device inputs.
+ assert(C.getCudaDeviceToolChain() &&
+ "Missing toolchain for device-side compilation.");
ActionList CudaDeviceActions;
- D.BuildActions(TC, Args, CudaDeviceInputs, CudaDeviceActions);
+ C.getDriver().BuildActions(C, *C.getCudaDeviceToolChain(), Args,
+ CudaDeviceInputs, CudaDeviceActions);
assert(GpuArchList.size() == CudaDeviceActions.size() &&
"Failed to create actions for all devices");
// Check whether any of device actions stopped before they could generate PTX.
- bool PartialCompilation = false;
- for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
- if (CudaDeviceActions[I]->getKind() != Action::BackendJobClass) {
- PartialCompilation = true;
- break;
- }
- }
+ bool PartialCompilation =
+ llvm::any_of(CudaDeviceActions, [](const Action *a) {
+ return a->getKind() != Action::AssembleJobClass;
+ });
// Figure out what to do with device actions -- pass them as inputs to the
// host action or run each of them independently.
@@ -1342,35 +1342,52 @@
// -o is ambiguous if we have more than one top-level action.
if (Args.hasArg(options::OPT_o) &&
(!DeviceOnlyCompilation || GpuArchList.size() > 1)) {
- D.Diag(clang::diag::err_drv_output_argument_with_multiple_files);
+ C.getDriver().Diag(
+ clang::diag::err_drv_output_argument_with_multiple_files);
return nullptr;
}
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I)
- Actions.push_back(new CudaDeviceAction(
- std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I],
- DeviceTriple, /* AtTopLevel */ true));
+ Actions.push_back(C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I],
+ GpuArchList[I],
+ /* AtTopLevel */ true));
// Kill host action in case of device-only compilation.
if (DeviceOnlyCompilation)
- HostAction.reset(nullptr);
+ return nullptr;
return HostAction;
}
- // Outputs of device actions during complete CUDA compilation get created
- // with AtTopLevel=false and become inputs for the host action.
+ // If we're not a partial or device-only compilation, we compile each arch to
+ // ptx and assemble to cubin, then feed the cubin *and* the ptx into a device
+ // "link" action, which uses fatbinary to combine these cubins into one
+ // fatbin. The fatbin is then an input to the host compilation.
ActionList DeviceActions;
- for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I)
- DeviceActions.push_back(new CudaDeviceAction(
- std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I],
- DeviceTriple, /* AtTopLevel */ false));
+ for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
+ Action* AssembleAction = CudaDeviceActions[I];
+ assert(AssembleAction->getType() == types::TY_Object);
+ assert(AssembleAction->getInputs().size() == 1);
+
+ Action* BackendAction = AssembleAction->getInputs()[0];
+ assert(BackendAction->getType() == types::TY_PP_Asm);
+
+ for (const auto& A : {AssembleAction, BackendAction}) {
+ DeviceActions.push_back(C.MakeAction<CudaDeviceAction>(
+ A, GpuArchList[I], /* AtTopLevel */ false));
+ }
+ }
+ auto FatbinAction = C.MakeAction<CudaDeviceAction>(
+ C.MakeAction<LinkJobAction>(DeviceActions, types::TY_CUDA_FATBIN),
+ /* GpuArchName = */ nullptr,
+ /* AtTopLevel = */ false);
// Return a new host action that incorporates original host action and all
// device actions.
- return std::unique_ptr<Action>(
- new CudaHostAction(std::move(HostAction), DeviceActions, DeviceTriple));
+ return C.MakeAction<CudaHostAction>(std::move(HostAction),
+ ActionList({FatbinAction}));
}
-void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
- const InputList &Inputs, ActionList &Actions) const {
+void Driver::BuildActions(Compilation &C, const ToolChain &TC,
+ DerivedArgList &Args, const InputList &Inputs,
+ ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
if (!SuppressMissingInputWarning && Inputs.empty()) {
@@ -1466,15 +1483,14 @@
continue;
}
- phases::ID CudaInjectionPhase = FinalPhase;
- for (const auto &Phase : PL)
- if (Phase <= FinalPhase && Phase == phases::Compile) {
- CudaInjectionPhase = Phase;
- break;
- }
+ phases::ID CudaInjectionPhase =
+ (phases::Compile < FinalPhase &&
+ llvm::find(PL, phases::Compile) != PL.end())
+ ? phases::Compile
+ : FinalPhase;
// Build the pipeline for this file.
- std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType));
+ Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end();
i != e; ++i) {
phases::ID Phase = *i;
@@ -1486,7 +1502,8 @@
// Queue linker inputs.
if (Phase == phases::Link) {
assert((i + 1) == e && "linking must be final compilation step.");
- LinkerInputs.push_back(Current.release());
+ LinkerInputs.push_back(Current);
+ Current = nullptr;
break;
}
@@ -1497,11 +1514,10 @@
continue;
// Otherwise construct the appropriate action.
- Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current));
+ Current = ConstructPhaseAction(C, TC, Args, Phase, Current);
if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) {
- Current = buildCudaActions(*this, TC, Args, InputArg,
- std::move(Current), Actions);
+ Current = buildCudaActions(C, Args, InputArg, Current, Actions);
if (!Current)
break;
}
@@ -1512,12 +1528,13 @@
// If we ended with something, add to the output list.
if (Current)
- Actions.push_back(Current.release());
+ Actions.push_back(Current);
}
// Add a link action if necessary.
if (!LinkerInputs.empty())
- Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image));
+ Actions.push_back(
+ C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image));
// If we are linking, claim any options which are obviously only used for
// compilation.
@@ -1534,10 +1551,9 @@
Args.ClaimAllArgs(options::OPT_cuda_host_only);
}
-std::unique_ptr<Action>
-Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args,
- phases::ID Phase,
- std::unique_ptr<Action> Input) const {
+Action *Driver::ConstructPhaseAction(Compilation &C, const ToolChain &TC,
+ const ArgList &Args, phases::ID Phase,
+ Action *Input) const {
llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
// Build the appropriate action.
switch (Phase) {
@@ -1557,7 +1573,7 @@
assert(OutputTy != types::TY_INVALID &&
"Cannot preprocess this input type!");
}
- return llvm::make_unique<PreprocessJobAction>(std::move(Input), OutputTy);
+ return C.MakeAction<PreprocessJobAction>(Input, OutputTy);
}
case phases::Precompile: {
types::ID OutputTy = types::TY_PCH;
@@ -1565,53 +1581,43 @@
// Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing;
}
- return llvm::make_unique<PrecompileJobAction>(std::move(Input), OutputTy);
+ return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
}
case phases::Compile: {
if (Args.hasArg(options::OPT_fsyntax_only))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_Nothing);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_Nothing);
if (Args.hasArg(options::OPT_rewrite_objc))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_RewrittenObjC);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_RewrittenObjC);
if (Args.hasArg(options::OPT_rewrite_legacy_objc))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_RewrittenLegacyObjC);
+ return C.MakeAction<CompileJobAction>(Input,
+ types::TY_RewrittenLegacyObjC);
if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto))
- return llvm::make_unique<AnalyzeJobAction>(std::move(Input),
- types::TY_Plist);
+ return C.MakeAction<AnalyzeJobAction>(Input, types::TY_Plist);
if (Args.hasArg(options::OPT__migrate))
- return llvm::make_unique<MigrateJobAction>(std::move(Input),
- types::TY_Remap);
+ return C.MakeAction<MigrateJobAction>(Input, types::TY_Remap);
if (Args.hasArg(options::OPT_emit_ast))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_AST);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_AST);
if (Args.hasArg(options::OPT_module_file_info))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_ModuleFile);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
if (Args.hasArg(options::OPT_verify_pch))
- return llvm::make_unique<VerifyPCHJobAction>(std::move(Input),
- types::TY_Nothing);
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_LLVM_BC);
+ return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
if (isUsingLTO()) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
- return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
+ return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
- return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
+ return C.MakeAction<BackendJobAction>(Input, Output);
}
- return llvm::make_unique<BackendJobAction>(std::move(Input),
- types::TY_PP_Asm);
+ return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
}
case phases::Assemble:
- return llvm::make_unique<AssembleJobAction>(std::move(Input),
- types::TY_Object);
+ return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object);
}
llvm_unreachable("invalid phase in ConstructPhaseAction");
@@ -1643,6 +1649,8 @@
if (A->getOption().matches(options::OPT_arch))
ArchNames.insert(A->getValue());
+ // Set of (Action, canonical ToolChain triple) pairs we've built jobs for.
+ std::map<std::pair<const Action *, std::string>, InputInfo> CachedResults;
for (Action *A : C.getActions()) {
// If we are linking an image for multiple archs then the linker wants
// -arch_multiple and -final_output <final image name>. Unfortunately, this
@@ -1658,12 +1666,11 @@
LinkingOutput = getDefaultImageName();
}
- InputInfo II;
BuildJobsForAction(C, A, &C.getDefaultToolChain(),
/*BoundArch*/ nullptr,
/*AtTopLevel*/ true,
/*MultipleArchs*/ ArchNames.size() > 1,
- /*LinkingOutput*/ LinkingOutput, II);
+ /*LinkingOutput*/ LinkingOutput, CachedResults);
}
// If the user passed -Qunused-arguments or there were errors, don't warn
@@ -1791,21 +1798,45 @@
return ToolForJob;
}
-void Driver::BuildJobsForAction(Compilation &C, const Action *A,
- const ToolChain *TC, const char *BoundArch,
- bool AtTopLevel, bool MultipleArchs,
- const char *LinkingOutput,
- InputInfo &Result) const {
+InputInfo Driver::BuildJobsForAction(
+ Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch,
+ bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput,
+ std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults)
+ const {
+ // The bound arch is not necessarily represented in the toolchain's triple --
+ // for example, armv7 and armv7s both map to the same triple -- so we need
+ // both in our map.
+ std::string TriplePlusArch = TC->getTriple().normalize();
+ if (BoundArch) {
+ TriplePlusArch += "-";
+ TriplePlusArch += BoundArch;
+ }
+ std::pair<const Action *, std::string> ActionTC = {A, TriplePlusArch};
+ auto CachedResult = CachedResults.find(ActionTC);
+ if (CachedResult != CachedResults.end()) {
+ return CachedResult->second;
+ }
+ InputInfo Result =
+ BuildJobsForActionNoCache(C, A, TC, BoundArch, AtTopLevel, MultipleArchs,
+ LinkingOutput, CachedResults);
+ CachedResults[ActionTC] = Result;
+ return Result;
+}
+
+InputInfo Driver::BuildJobsForActionNoCache(
+ Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch,
+ bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput,
+ std::map<std::pair<const Action *, std::string>, InputInfo> &CachedResults)
+ const {
llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
InputInfoList CudaDeviceInputInfos;
if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) {
- InputInfo II;
// Append outputs of device jobs to the input list.
for (const Action *DA : CHA->getDeviceActions()) {
- BuildJobsForAction(C, DA, TC, "", AtTopLevel,
- /*MultipleArchs*/ false, LinkingOutput, II);
- CudaDeviceInputInfos.push_back(II);
+ CudaDeviceInputInfos.push_back(BuildJobsForAction(
+ C, DA, TC, nullptr, AtTopLevel,
+ /*MultipleArchs*/ false, LinkingOutput, CachedResults));
}
// Override current action with a real host compile action and continue
// processing it.
@@ -1819,11 +1850,9 @@
Input.claim();
if (Input.getOption().matches(options::OPT_INPUT)) {
const char *Name = Input.getValue();
- Result = InputInfo(Name, A->getType(), Name);
- } else {
- Result = InputInfo(&Input, A->getType(), "");
+ return InputInfo(A, Name, /* BaseInput = */ Name);
}
- return;
+ return InputInfo(A, &Input, /* BaseInput = */ "");
}
if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
@@ -1837,18 +1866,21 @@
else
TC = &C.getDefaultToolChain();
- BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel,
- MultipleArchs, LinkingOutput, Result);
- return;
+ return BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel,
+ MultipleArchs, LinkingOutput, CachedResults);
}
if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) {
- BuildJobsForAction(
- C, *CDA->begin(),
- &getToolChain(C.getArgs(), llvm::Triple(CDA->getDeviceTriple())),
- CDA->getGpuArchName(), CDA->isAtTopLevel(),
- /*MultipleArchs*/ true, LinkingOutput, Result);
- return;
+ // Initial processing of CudaDeviceAction carries host params.
+ // Call BuildJobsForAction() again, now with correct device parameters.
+ InputInfo II = BuildJobsForAction(
+ C, *CDA->begin(), C.getCudaDeviceToolChain(), CDA->getGpuArchName(),
+ CDA->isAtTopLevel(), /*MultipleArchs*/ true, LinkingOutput,
+ CachedResults);
+ // Currently II's Action is *CDA->begin(). Set it to CDA instead, so that
+ // one can retrieve II's GPU arch.
+ II.setAction(A);
+ return II;
}
const ActionList *Inputs = &A->getInputs();
@@ -1858,16 +1890,15 @@
const Tool *T =
selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA);
if (!T)
- return;
+ return InputInfo();
// If we've collapsed action list that contained CudaHostAction we
// need to build jobs for device-side inputs it may have held.
if (CollapsedCHA) {
- InputInfo II;
for (const Action *DA : CollapsedCHA->getDeviceActions()) {
- BuildJobsForAction(C, DA, TC, "", AtTopLevel,
- /*MultipleArchs*/ false, LinkingOutput, II);
- CudaDeviceInputInfos.push_back(II);
+ CudaDeviceInputInfos.push_back(BuildJobsForAction(
+ C, DA, TC, "", AtTopLevel,
+ /*MultipleArchs*/ false, LinkingOutput, CachedResults));
}
}
@@ -1877,14 +1908,11 @@
// Treat dsymutil and verify sub-jobs as being at the top-level too, they
// shouldn't get temporary output names.
// FIXME: Clean this up.
- bool SubJobAtTopLevel = false;
- if (AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)))
- SubJobAtTopLevel = true;
-
- InputInfo II;
- BuildJobsForAction(C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs,
- LinkingOutput, II);
- InputInfos.push_back(II);
+ bool SubJobAtTopLevel =
+ AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A));
+ InputInfos.push_back(BuildJobsForAction(C, Input, TC, BoundArch,
+ SubJobAtTopLevel, MultipleArchs,
+ LinkingOutput, CachedResults));
}
// Always use the first input as the base input.
@@ -1900,12 +1928,13 @@
InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end());
// Determine the place to write output to, if any.
+ InputInfo Result;
if (JA->getType() == types::TY_Nothing)
- Result = InputInfo(A->getType(), BaseInput);
+ Result = InputInfo(A, BaseInput);
else
- Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
- AtTopLevel, MultipleArchs),
- A->getType(), BaseInput);
+ Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
+ AtTopLevel, MultipleArchs),
+ BaseInput);
if (CCCPrintBindings && !CCGenDiagnostics) {
llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"'
@@ -1920,6 +1949,7 @@
T->ConstructJob(C, *JA, Result, InputInfos,
C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
}
+ return Result;
}
const char *Driver::getDefaultImageName() const {
@@ -2154,6 +2184,11 @@
// FIXME: Needs a better variable than DefaultTargetTriple
Names.emplace_back(DefaultTargetTriple + "-" + Tool);
Names.emplace_back(Tool);
+
+ // Allow the discovery of tools prefixed with LLVM's default target triple.
+ std::string LLVMDefaultTargetTriple = llvm::sys::getDefaultTargetTriple();
+ if (LLVMDefaultTargetTriple != DefaultTargetTriple)
+ Names.emplace_back(LLVMDefaultTargetTriple + "-" + Tool);
}
static bool ScanDirForExecutable(SmallString<128> &Dir,
@@ -2251,6 +2286,9 @@
case llvm::Triple::Linux:
if (Target.getArch() == llvm::Triple::hexagon)
TC = new toolchains::HexagonToolChain(*this, Target, Args);
+ else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) &&
+ !Target.hasEnvironment())
+ TC = new toolchains::MipsLLVMToolChain(*this, Target, Args);
else
TC = new toolchains::Linux(*this, Target, Args);
break;
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index b23ba57..0c36e81 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
#define LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
+#include "clang/Driver/Action.h"
#include "clang/Driver/Types.h"
#include "llvm/Option/Arg.h"
#include <cassert>
@@ -38,21 +39,36 @@
const llvm::opt::Arg *InputArg;
} Data;
Class Kind;
+ const Action* Act;
types::ID Type;
const char *BaseInput;
-public:
- InputInfo() {}
- InputInfo(types::ID _Type, const char *_BaseInput)
- : Kind(Nothing), Type(_Type), BaseInput(_BaseInput) {
+ static types::ID GetActionType(const Action *A) {
+ return A != nullptr ? A->getType() : types::TY_Nothing;
}
- InputInfo(const char *_Filename, types::ID _Type, const char *_BaseInput)
- : Kind(Filename), Type(_Type), BaseInput(_BaseInput) {
+
+public:
+ InputInfo() : InputInfo(nullptr, nullptr) {}
+ InputInfo(const Action *A, const char *_BaseInput)
+ : Kind(Nothing), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {}
+
+ InputInfo(types::ID _Type, const char *_Filename, const char *_BaseInput)
+ : Kind(Filename), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
Data.Filename = _Filename;
}
- InputInfo(const llvm::opt::Arg *_InputArg, types::ID _Type,
+ InputInfo(const Action *A, const char *_Filename, const char *_BaseInput)
+ : Kind(Filename), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
+ Data.Filename = _Filename;
+ }
+
+ InputInfo(types::ID _Type, const llvm::opt::Arg *_InputArg,
const char *_BaseInput)
- : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) {
+ : Kind(InputArg), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
+ Data.InputArg = _InputArg;
+ }
+ InputInfo(const Action *A, const llvm::opt::Arg *_InputArg,
+ const char *_BaseInput)
+ : Kind(InputArg), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
Data.InputArg = _InputArg;
}
@@ -61,6 +77,9 @@
bool isInputArg() const { return Kind == InputArg; }
types::ID getType() const { return Type; }
const char *getBaseInput() const { return BaseInput; }
+ /// The action for which this InputInfo was created. May be null.
+ const Action *getAction() const { return Act; }
+ void setAction(const Action *A) { Act = A; }
const char *getFilename() const {
assert(isFilename() && "Invalid accessor.");
diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp
index b7e576e..6874715 100644
--- a/lib/Driver/MSVCToolChain.cpp
+++ b/lib/Driver/MSVCToolChain.cpp
@@ -634,6 +634,96 @@
return Res;
}
+static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ bool SupportsForcingFramePointer,
+ const char *ExpandChar, const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT__SLASH_O));
+
+ StringRef OptStr = A->getValue();
+ for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
+ const char &OptChar = *(OptStr.data() + I);
+ switch (OptChar) {
+ default:
+ break;
+ case '1':
+ case '2':
+ case 'x':
+ case 'd':
+ if (&OptChar == ExpandChar) {
+ if (OptChar == 'd') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
+ } else {
+ if (OptChar == '1') {
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ } else if (OptChar == '2' || OptChar == 'x') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ }
+ if (SupportsForcingFramePointer)
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ if (OptChar == '1' || OptChar == '2')
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_ffunction_sections));
+ }
+ }
+ break;
+ case 'b':
+ if (I + 1 != E && isdigit(OptStr[I + 1]))
+ ++I;
+ break;
+ case 'g':
+ break;
+ case 'i':
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ ++I;
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
+ } else {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ }
+ break;
+ case 's':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ break;
+ case 't':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ break;
+ case 'y': {
+ bool OmitFramePointer = true;
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ OmitFramePointer = false;
+ ++I;
+ }
+ if (SupportsForcingFramePointer) {
+ if (OmitFramePointer)
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ else
+ DAL.AddFlagArg(
+ A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT_D));
+
+ StringRef Val = A->getValue();
+ size_t Hash = Val.find('#');
+ if (Hash == StringRef::npos || Hash > Val.find('=')) {
+ DAL.append(A);
+ return;
+ }
+
+ std::string NewVal = Val;
+ NewVal[Hash] = '=';
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
+}
+
llvm::opt::DerivedArgList *
MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
const char *BoundArch) const {
@@ -664,81 +754,18 @@
}
}
- // The -O flag actually takes an amalgam of other options. For example,
- // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
for (Arg *A : Args) {
- if (!A->getOption().matches(options::OPT__SLASH_O)) {
+ if (A->getOption().matches(options::OPT__SLASH_O)) {
+ // The -O flag actually takes an amalgam of other options. For example,
+ // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
+ TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
+ } else if (A->getOption().matches(options::OPT_D)) {
+ // Translate -Dfoo#bar into -Dfoo=bar.
+ TranslateDArg(A, *DAL, Opts);
+ } else {
DAL->append(A);
- continue;
- }
-
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- const char &OptChar = *(OptStr.data() + I);
- switch (OptChar) {
- default:
- break;
- case '1':
- case '2':
- case 'x':
- case 'd':
- if (&OptChar == ExpandChar) {
- if (OptChar == 'd') {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_O0));
- } else {
- if (OptChar == '1') {
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- } else if (OptChar == '2' || OptChar == 'x') {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- }
- if (SupportsForcingFramePointer)
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- if (OptChar == '1' || OptChar == '2')
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_ffunction_sections));
- }
- }
- break;
- case 'b':
- if (I + 1 != E && isdigit(OptStr[I + 1]))
- ++I;
- break;
- case 'g':
- break;
- case 'i':
- if (I + 1 != E && OptStr[I + 1] == '-') {
- ++I;
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
- } else {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- }
- break;
- case 's':
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- break;
- case 't':
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- break;
- case 'y': {
- bool OmitFramePointer = true;
- if (I + 1 != E && OptStr[I + 1] == '-') {
- OmitFramePointer = false;
- ++I;
- }
- if (SupportsForcingFramePointer) {
- if (OmitFramePointer)
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- else
- DAL->AddFlagArg(
- A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
- }
- break;
- }
- }
}
}
+
return DAL;
}
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 3f1b99c..cf8d39d 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -33,7 +33,7 @@
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow,
RecoverableByDefault = Undefined | Integer,
- Unrecoverable = Address | Unreachable | Return,
+ Unrecoverable = Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
NeedsLTO = CFI,
TrappingSupported =
@@ -160,7 +160,16 @@
return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) &&
!Sanitizers.has(Address) &&
!Sanitizers.has(Memory) &&
- !Sanitizers.has(Thread);
+ !Sanitizers.has(Thread) &&
+ !CfiCrossDso;
+}
+
+bool SanitizerArgs::needsCfiRt() const {
+ return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
+}
+
+bool SanitizerArgs::needsCfiDiagRt() const {
+ return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
}
bool SanitizerArgs::requiresPIE() const {
@@ -171,24 +180,8 @@
return Sanitizers.Mask & NeedsUnwindTables;
}
-void SanitizerArgs::clear() {
- Sanitizers.clear();
- RecoverableSanitizers.clear();
- TrapSanitizers.clear();
- BlacklistFiles.clear();
- ExtraDeps.clear();
- CoverageFeatures = 0;
- MsanTrackOrigins = 0;
- MsanUseAfterDtor = false;
- NeedPIE = false;
- AsanFieldPadding = 0;
- AsanSharedRuntime = false;
- LinkCXXRuntimes = false;
-}
-
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
const llvm::opt::ArgList &Args) {
- clear();
SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
@@ -430,6 +423,17 @@
TC.getTriple().getArch() == llvm::Triple::x86_64);
}
+ if (AllAddedKinds & CFI) {
+ CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
+ options::OPT_fno_sanitize_cfi_cross_dso, false);
+ // Without PIE, external function address may resolve to a PLT record, which
+ // can not be verified by the target module.
+ NeedPIE |= CfiCrossDso;
+ }
+
+ Stats = Args.hasFlag(options::OPT_fsanitize_stats,
+ options::OPT_fno_sanitize_stats, false);
+
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
// enabled sanitizers.
if (AllAddedKinds & SupportsCoverage) {
@@ -547,6 +551,20 @@
return Res;
}
+static void addIncludeLinkerOption(const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ StringRef SymbolName) {
+ SmallString<64> LinkerOptionFlag;
+ LinkerOptionFlag = "--linker-option=/include:";
+ if (TC.getTriple().getArch() == llvm::Triple::x86) {
+ // Win32 mangles C function names with a '_' prefix.
+ LinkerOptionFlag += '_';
+ }
+ LinkerOptionFlag += SymbolName;
+ CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
+}
+
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
types::ID InputType) const {
@@ -580,6 +598,12 @@
if (MsanUseAfterDtor)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor"));
+ if (CfiCrossDso)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
+
+ if (Stats)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats"));
+
if (AsanFieldPadding)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
llvm::utostr(AsanFieldPadding)));
@@ -615,6 +639,18 @@
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
}
+ if (TC.getTriple().isOSWindows() && needsStatsRt()) {
+ CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
+ TC.getCompilerRT(Args, "stats_client")));
+
+ // The main executable must export the stats runtime.
+ // FIXME: Only exporting from the main executable (e.g. based on whether the
+ // translation unit defines main()) would save a little space, but having
+ // multiple copies of the runtime shouldn't hurt.
+ CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
+ TC.getCompilerRT(Args, "stats")));
+ addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
+ }
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index a41a3b2..cbbd485 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -333,7 +333,6 @@
std::string ToolChain::GetFilePath(const char *Name) const {
return D.GetFilePath(Name, *this);
-
}
std::string ToolChain::GetProgramPath(const char *Name) const {
@@ -360,7 +359,7 @@
return "";
}
- return GetProgramPath("ld");
+ return GetProgramPath(DefaultLinker);
}
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
@@ -617,6 +616,13 @@
}
}
+void ToolChain::AddFilePathLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ for (const auto &LibPath : getFilePaths())
+ if(LibPath.length() > 0)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+}
+
void ToolChain::AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-lcc_kext");
@@ -657,3 +663,6 @@
Res |= CFIICall;
return Res;
}
+
+void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index f83c7c9..45cd8bd 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -323,21 +323,35 @@
ArgStringList &CmdArgs) const {
if (!needsProfileRT(Args)) return;
+ // TODO: Clean this up once autoconf is gone
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "lib", "darwin");
+ const char *Library = "libclang_rt.profile_osx.a";
+
// Select the appropriate runtime library for the target.
- if (isTargetWatchOSBased()) {
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_watchos.a",
- /*AlwaysLink*/ true);
- } else if (isTargetTvOSBased()) {
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_tvos.a",
- /*AlwaysLink*/ true);
- } else if (isTargetIOSBased()) {
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a",
- /*AlwaysLink*/ true);
+ if (isTargetWatchOS()) {
+ Library = "libclang_rt.profile_watchos.a";
+ } else if (isTargetWatchOSSimulator()) {
+ llvm::sys::path::append(P, "libclang_rt.profile_watchossim.a");
+ Library = getVFS().exists(P) ? "libclang_rt.profile_watchossim.a"
+ : "libclang_rt.profile_watchos.a";
+ } else if (isTargetTvOS()) {
+ Library = "libclang_rt.profile_tvos.a";
+ } else if (isTargetTvOSSimulator()) {
+ llvm::sys::path::append(P, "libclang_rt.profile_tvossim.a");
+ Library = getVFS().exists(P) ? "libclang_rt.profile_tvossim.a"
+ : "libclang_rt.profile_tvos.a";
+ } else if (isTargetIPhoneOS()) {
+ Library = "libclang_rt.profile_ios.a";
+ } else if (isTargetIOSSimulator()) {
+ llvm::sys::path::append(P, "libclang_rt.profile_iossim.a");
+ Library = getVFS().exists(P) ? "libclang_rt.profile_iossim.a"
+ : "libclang_rt.profile_ios.a";
} else {
assert(isTargetMacOS() && "unexpected non MacOS platform");
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a",
- /*AlwaysLink*/ true);
}
+ AddLinkRuntimeLib(Args, CmdArgs, Library,
+ /*AlwaysLink*/ true);
return;
}
@@ -399,6 +413,13 @@
AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
if (Sanitize.needsTsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
+ if (Sanitize.needsStatsRt()) {
+ StringRef OS = isTargetMacOS() ? "osx" : "iossim";
+ AddLinkRuntimeLib(Args, CmdArgs,
+ (Twine("libclang_rt.stats_client_") + OS + ".a").str(),
+ /*AlwaysLink=*/true);
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
+ }
// Otherwise link libSystem, then the dynamic runtime library, and finally any
// target specific static runtime library.
@@ -512,7 +533,7 @@
// no environment variable defined, see if we can set the default based
// on -isysroot.
if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() &&
- Args.hasArg(options::OPT_isysroot)) {
+ TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) {
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef isysroot = A->getValue();
// Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk
@@ -1053,12 +1074,9 @@
getTriple().getArch() != llvm::Triple::thumb)
return false;
- // We can't check directly for watchOS here. ComputeLLVMTriple only
- // fills in the ArchName correctly.
+ // Only watchOS uses the new DWARF/Compact unwinding method.
llvm::Triple Triple(ComputeLLVMTriple(Args));
- return !(Triple.getArchName() == "armv7k" ||
- Triple.getArchName() == "thumbv7k");
-
+ return !Triple.isWatchABI();
}
bool MachO::isPICDefault() const { return true; }
@@ -1442,8 +1460,9 @@
"i586-linux-gnu"};
static const char *const MIPSLibDirs[] = {"/lib"};
- static const char *const MIPSTriples[] = {
- "mips-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu"};
+ static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux",
+ "mips-mti-linux-gnu",
+ "mips-img-linux-gnu"};
static const char *const MIPSELLibDirs[] = {"/lib"};
static const char *const MIPSELTriples[] = {
"mipsel-linux-gnu", "mipsel-linux-android", "mips-img-linux-gnu"};
@@ -1632,6 +1651,7 @@
Args.getLastArgValue(options::OPT_cuda_path_EQ));
else {
CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda");
+ CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.5");
CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.0");
}
@@ -1640,16 +1660,42 @@
continue;
CudaInstallPath = CudaPath;
+ CudaBinPath = CudaPath + "/bin";
CudaIncludePath = CudaInstallPath + "/include";
CudaLibDevicePath = CudaInstallPath + "/nvvm/libdevice";
CudaLibPath =
CudaInstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib");
if (!(D.getVFS().exists(CudaIncludePath) &&
- D.getVFS().exists(CudaLibPath) &&
+ D.getVFS().exists(CudaBinPath) && D.getVFS().exists(CudaLibPath) &&
D.getVFS().exists(CudaLibDevicePath)))
continue;
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(CudaLibDevicePath, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef FilePath = LI->path();
+ StringRef FileName = llvm::sys::path::filename(FilePath);
+ // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc
+ const StringRef LibDeviceName = "libdevice.";
+ if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc")))
+ continue;
+ StringRef GpuArch = FileName.slice(
+ LibDeviceName.size(), FileName.find('.', LibDeviceName.size()));
+ CudaLibDeviceMap[GpuArch] = FilePath.str();
+ // Insert map entries for specifc devices with this compute capability.
+ if (GpuArch == "compute_20") {
+ CudaLibDeviceMap["sm_20"] = FilePath;
+ CudaLibDeviceMap["sm_21"] = FilePath;
+ } else if (GpuArch == "compute_30") {
+ CudaLibDeviceMap["sm_30"] = FilePath;
+ CudaLibDeviceMap["sm_32"] = FilePath;
+ } else if (GpuArch == "compute_35") {
+ CudaLibDeviceMap["sm_35"] = FilePath;
+ CudaLibDeviceMap["sm_37"] = FilePath;
+ }
+ }
+
IsValid = true;
break;
}
@@ -1834,6 +1880,32 @@
});
}
+ // Check for Musl toolchain multilibs
+ MultilibSet MuslMipsMultilibs;
+ {
+ auto MArchMipsR2 = makeMultilib("")
+ .osSuffix("/mips-r2-hard-musl")
+ .flag("+EB")
+ .flag("-EL")
+ .flag("+march=mips32r2");
+
+ auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
+ .flag("-EB")
+ .flag("+EL")
+ .flag("+march=mips32r2");
+
+ MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
+
+ // Specify the callback that computes the include directories.
+ MuslMipsMultilibs.setIncludeDirsCallback([](
+ StringRef InstallDir, StringRef TripleStr, const Multilib &M) {
+ std::vector<std::string> Dirs;
+ Dirs.push_back(
+ (InstallDir + "/../sysroot" + M.osSuffix() + "/usr/include").str());
+ return Dirs;
+ });
+ }
+
// Check for Code Sourcery toolchain multilibs
MultilibSet CSMipsMultilibs;
{
@@ -1979,6 +2051,16 @@
return false;
}
+ if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
+ TargetTriple.getOS() == llvm::Triple::Linux &&
+ TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) {
+ if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = MuslMipsMultilibs;
+ return true;
+ }
+ return false;
+ }
+
if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
TargetTriple.getEnvironment() == llvm::Triple::GNU) {
@@ -2304,9 +2386,6 @@
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
case llvm::Triple::systemz:
return true;
default:
@@ -2356,131 +2435,238 @@
getTriple().getArch() == llvm::Triple::aarch64_be ||
(getTriple().getOS() == llvm::Triple::Linux &&
(!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
- getTriple().getOS() == llvm::Triple::NaCl;
+ getTriple().getOS() == llvm::Triple::NaCl ||
+ (getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
+ !getTriple().hasEnvironment());
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array, UseInitArrayDefault))
CC1Args.push_back("-fuse-init-array");
}
+/// Mips Toolchain
+MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Linux(D, Triple, Args) {
+ // Select the correct multilib according to the given arguments.
+ DetectedMultilibs Result;
+ findMIPSMultilibs(D, Triple, "", Args, Result);
+ Multilibs = Result.Multilibs;
+ SelectedMultilib = Result.SelectedMultilib;
+
+ // Find out the library suffix based on the ABI.
+ LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple);
+ getFilePaths().clear();
+ getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix);
+
+ // Use LLD by default.
+ DefaultLinker = "lld";
+}
+
+void MipsLLVMToolChain::AddClangSystemIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ const Driver &D = getDriver();
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ const auto &Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ const auto IncludePaths =
+ Callback(D.getInstalledDir(), getTripleString(), SelectedMultilib);
+ for (const auto &Path : IncludePaths)
+ addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path);
+ }
+}
+
+Tool *MipsLLVMToolChain::buildLinker() const {
+ return new tools::gnutools::Linker(*this);
+}
+
+std::string MipsLLVMToolChain::computeSysRoot() const {
+ if (!getDriver().SysRoot.empty())
+ return getDriver().SysRoot + SelectedMultilib.osSuffix();
+
+ const std::string InstalledDir(getDriver().getInstalledDir());
+ std::string SysRootPath =
+ InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix();
+ if (llvm::sys::fs::exists(SysRootPath))
+ return SysRootPath;
+
+ return std::string();
+}
+
+ToolChain::CXXStdlibType
+MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+ if (A) {
+ StringRef Value = A->getValue();
+ if (Value != "libc++")
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+void MipsLLVMToolChain::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ assert((GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) &&
+ "Only -lc++ (aka libcxx) is suported in this toolchain.");
+
+ const auto &Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ const auto IncludePaths = Callback(getDriver().getInstalledDir(),
+ getTripleString(), SelectedMultilib);
+ for (const auto &Path : IncludePaths) {
+ if (llvm::sys::fs::exists(Path + "/c++/v1")) {
+ addSystemInclude(DriverArgs, CC1Args, Path + "/c++/v1");
+ break;
+ }
+ }
+ }
+}
+
+void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) &&
+ "Only -lc++ (aka libxx) is suported in this toolchain.");
+
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+}
+
+std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args,
+ StringRef Component,
+ bool Shared) const {
+ SmallString<128> Path(getDriver().ResourceDir);
+ llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix,
+ getOS());
+ llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" +
+ "mips" + (Shared ? ".so" : ".a")));
+ return Path.str();
+}
+
/// Hexagon Toolchain
-std::string HexagonToolChain::GetGnuDir(const std::string &InstalledDir,
- const ArgList &Args) const {
+std::string HexagonToolChain::getHexagonTargetDir(
+ const std::string &InstalledDir,
+ const SmallVectorImpl<std::string> &PrefixDirs) const {
+ std::string InstallRelDir;
+ const Driver &D = getDriver();
+
// Locate the rest of the toolchain ...
- std::string GccToolchain = getGCCToolchainDir(Args);
+ for (auto &I : PrefixDirs)
+ if (D.getVFS().exists(I))
+ return I;
- if (!GccToolchain.empty())
- return GccToolchain;
-
- std::string InstallRelDir = InstalledDir + "/../../gnu";
- if (getVFS().exists(InstallRelDir))
+ if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
return InstallRelDir;
- std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu";
+ std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/target";
if (getVFS().exists(PrefixRelDir))
return PrefixRelDir;
return InstallRelDir;
}
-const char *HexagonToolChain::GetSmallDataThreshold(const ArgList &Args) {
- Arg *A;
- A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ,
- options::OPT_msmall_data_threshold_EQ);
- if (A)
- return A->getValue();
+Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
+ const ArgList &Args) {
+ StringRef Gn = "";
+ if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ,
+ options::OPT_msmall_data_threshold_EQ)) {
+ Gn = A->getValue();
+ } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
+ options::OPT_fPIC)) {
+ Gn = "0";
+ }
- A = Args.getLastArg(options::OPT_shared, options::OPT_fpic,
- options::OPT_fPIC);
- if (A)
- return "0";
+ unsigned G;
+ if (!Gn.getAsInteger(10, G))
+ return G;
- return nullptr;
+ return None;
}
-bool HexagonToolChain::UsesG0(const char *smallDataThreshold) {
- return smallDataThreshold && smallDataThreshold[0] == '0';
-}
-static void GetHexagonLibraryPaths(const HexagonToolChain &TC,
- const ArgList &Args, const std::string &Ver,
- const std::string &MarchString,
- const std::string &InstalledDir,
- ToolChain::path_list *LibPaths) {
- bool buildingLib = Args.hasArg(options::OPT_shared);
+void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
+ ToolChain::path_list &LibPaths) const {
+ const Driver &D = getDriver();
//----------------------------------------------------------------------------
// -L Args
//----------------------------------------------------------------------------
for (Arg *A : Args.filtered(options::OPT_L))
for (const char *Value : A->getValues())
- LibPaths->push_back(Value);
+ LibPaths.push_back(Value);
//----------------------------------------------------------------------------
// Other standard paths
//----------------------------------------------------------------------------
- const std::string MarchSuffix = "/" + MarchString;
- const std::string G0Suffix = "/G0";
- const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
- const std::string RootDir = TC.GetGnuDir(InstalledDir, Args) + "/";
+ std::vector<std::string> RootDirs;
+ std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
+ std::back_inserter(RootDirs));
- // lib/gcc/hexagon/...
- std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/";
- if (buildingLib) {
- LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix);
- LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix);
+ std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
+ if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
+ RootDirs.push_back(TargetDir);
+
+ bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
+ // Assume G0 with -shared.
+ bool HasG0 = Args.hasArg(options::OPT_shared);
+ if (auto G = getSmallDataThreshold(Args))
+ HasG0 = G.getValue() == 0;
+
+ const std::string CpuVer = GetTargetCPUVersion(Args).str();
+ for (auto &Dir : RootDirs) {
+ std::string LibDir = Dir + "/hexagon/lib";
+ std::string LibDirCpu = LibDir + '/' + CpuVer;
+ if (HasG0) {
+ if (HasPIC)
+ LibPaths.push_back(LibDirCpu + "/G0/pic");
+ LibPaths.push_back(LibDirCpu + "/G0");
+ }
+ LibPaths.push_back(LibDirCpu);
+ LibPaths.push_back(LibDir);
}
- LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix);
- LibPaths->push_back(LibGCCHexagonDir + Ver);
-
- // lib/gcc/...
- LibPaths->push_back(RootDir + "lib/gcc");
-
- // hexagon/lib/...
- std::string HexagonLibDir = RootDir + "hexagon/lib";
- if (buildingLib) {
- LibPaths->push_back(HexagonLibDir + MarchG0Suffix);
- LibPaths->push_back(HexagonLibDir + G0Suffix);
- }
- LibPaths->push_back(HexagonLibDir + MarchSuffix);
- LibPaths->push_back(HexagonLibDir);
}
HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
+ const llvm::opt::ArgList &Args)
: Linux(D, Triple, Args) {
- const std::string InstalledDir(getDriver().getInstalledDir());
- const std::string GnuDir = GetGnuDir(InstalledDir, Args);
+ const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
// Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
// program paths
- const std::string BinDir(GnuDir + "/bin");
+ const std::string BinDir(TargetDir + "/bin");
if (D.getVFS().exists(BinDir))
getProgramPaths().push_back(BinDir);
- // Determine version of GCC libraries and headers to use.
- const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon");
- std::error_code ec;
- GCCVersion MaxVersion = GCCVersion::Parse("0.0.0");
- for (vfs::directory_iterator di = D.getVFS().dir_begin(HexagonDir, ec), de;
- !ec && di != de; di = di.increment(ec)) {
- GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->getName()));
- if (MaxVersion < cv)
- MaxVersion = cv;
- }
- GCCLibAndIncVersion = MaxVersion;
-
- ToolChain::path_list *LibPaths = &getFilePaths();
+ ToolChain::path_list &LibPaths = getFilePaths();
// Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
// 'elf' OS type, so the Linux paths are not appropriate. When we actually
// support 'linux' we'll need to fix this up
- LibPaths->clear();
-
- GetHexagonLibraryPaths(*this, Args, GetGCCLibAndIncVersion(),
- GetTargetCPU(Args), InstalledDir, LibPaths);
+ LibPaths.clear();
+ getHexagonLibraryPaths(Args, LibPaths);
}
HexagonToolChain::~HexagonToolChain() {}
@@ -2495,18 +2681,14 @@
void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
-
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
- std::string Ver(GetGCCLibAndIncVersion());
- std::string GnuDir = GetGnuDir(D.InstalledDir, DriverArgs);
- std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
- addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include");
- addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed");
- addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include");
+ const Driver &D = getDriver();
+ std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
+ addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
}
void HexagonToolChain::AddClangCXXStdlibIncludeArgs(
@@ -2516,12 +2698,8 @@
return;
const Driver &D = getDriver();
- std::string Ver(GetGCCLibAndIncVersion());
- SmallString<128> IncludeDir(GetGnuDir(D.InstalledDir, DriverArgs));
-
- llvm::sys::path::append(IncludeDir, "hexagon/include/c++/");
- llvm::sys::path::append(IncludeDir, Ver);
- addSystemInclude(DriverArgs, CC1Args, IncludeDir);
+ std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
+ addSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include/c++");
}
ToolChain::CXXStdlibType
@@ -2531,53 +2709,29 @@
return ToolChain::CST_Libstdcxx;
StringRef Value = A->getValue();
- if (Value != "libstdc++") {
+ if (Value != "libstdc++")
getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
- }
return ToolChain::CST_Libstdcxx;
}
-static int getHexagonVersion(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ);
- // Select the default CPU (v4) if none was given.
- if (!A)
- return 4;
-
- // FIXME: produce errors if we cannot parse the version.
- StringRef WhichHexagon = A->getValue();
- if (WhichHexagon.startswith("hexagonv")) {
- int Val;
- if (!WhichHexagon.substr(sizeof("hexagonv") - 1).getAsInteger(10, Val))
- return Val;
- }
- if (WhichHexagon.startswith("v")) {
- int Val;
- if (!WhichHexagon.substr(1).getAsInteger(10, Val))
- return Val;
- }
-
- // FIXME: should probably be an error.
- return 4;
+//
+// Returns the default CPU for Hexagon. This is the default compilation target
+// if no Hexagon processor is selected at the command-line.
+//
+const StringRef HexagonToolChain::GetDefaultCPU() {
+ return "hexagonv60";
}
-StringRef HexagonToolChain::GetTargetCPU(const ArgList &Args) {
- int V = getHexagonVersion(Args);
- // FIXME: We don't support versions < 4. We should error on them.
- switch (V) {
- default:
- llvm_unreachable("Unexpected version");
- case 5:
- return "v5";
- case 4:
- return "v4";
- case 3:
- return "v3";
- case 2:
- return "v2";
- case 1:
- return "v1";
- }
+const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
+ Arg *CpuArg = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
+ CpuArg = A;
+
+ StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
+ if (CPU.startswith("hexagon"))
+ return CPU.substr(sizeof("hexagon") - 1);
+ return CPU;
}
// End Hexagon
@@ -2643,8 +2797,6 @@
break;
}
- // Use provided linker, not system linker
- Linker = GetLinkerPath();
NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s");
}
@@ -3348,7 +3500,8 @@
static std::string getMultiarchTriple(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef SysRoot) {
- llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment();
+ llvm::Triple::EnvironmentType TargetEnvironment =
+ TargetTriple.getEnvironment();
// For most architectures, just use whatever we have rather than trying to be
// clever.
@@ -3499,8 +3652,6 @@
GCCInstallation.getTriple().str() + "/bin")
.str());
- Linker = GetLinkerPath();
-
Distro Distro = DetectDistro(D, Arch);
if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) {
@@ -3767,6 +3918,10 @@
"/usr/include/arm-linux-gnueabi"};
const StringRef ARMHFMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabihf"};
+ const StringRef ARMEBMultiarchIncludeDirs[] = {
+ "/usr/include/armeb-linux-gnueabi"};
+ const StringRef ARMEBHFMultiarchIncludeDirs[] = {
+ "/usr/include/armeb-linux-gnueabihf"};
const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"};
const StringRef MIPSELMultiarchIncludeDirs[] = {
"/usr/include/mipsel-linux-gnu"};
@@ -3800,11 +3955,19 @@
MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
break;
case llvm::Triple::arm:
+ case llvm::Triple::thumb:
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
else
MultiarchIncludeDirs = ARMMultiarchIncludeDirs;
break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
+ MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs;
+ else
+ MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs;
+ break;
case llvm::Triple::mips:
MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
break;
@@ -3950,6 +4113,18 @@
}
}
+void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nocudainc))
+ return;
+
+ if (CudaInstallation.isValid()) {
+ addSystemInclude(DriverArgs, CC1Args, CudaInstallation.getIncludePath());
+ CC1Args.push_back("-include");
+ CC1Args.push_back("__clang_cuda_runtime_wrapper.h");
+ }
+}
+
bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
SanitizerMask Linux::getSupportedSanitizers() const {
@@ -3970,7 +4145,7 @@
Res |= SanitizerKind::DataFlow;
if (IsX86_64 || IsMIPS64 || IsAArch64)
Res |= SanitizerKind::Leak;
- if (IsX86_64 || IsMIPS64 || IsAArch64)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64)
Res |= SanitizerKind::Thread;
if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64)
Res |= SanitizerKind::Memory;
@@ -4005,10 +4180,7 @@
getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
- if (D.getVFS().exists("/usr/lib/gcc47"))
- getFilePaths().push_back("/usr/lib/gcc47");
- else
- getFilePaths().push_back("/usr/lib/gcc44");
+ getFilePaths().push_back("/usr/lib/gcc50");
}
Tool *DragonFly::buildAssembler() const {
@@ -4019,19 +4191,38 @@
return new tools::dragonfly::Linker(*this);
}
-/// Stub for CUDA toolchain. At the moment we don't have assembler or
-/// linker and need toolchain mainly to propagate device-side options
-/// to CC1.
+/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
+/// which isn't properly a linker but nonetheless performs the step of stitching
+/// together object files from the assembler into a single blob.
CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Linux(D, Triple, Args) {}
+ : Linux(D, Triple, Args) {
+ if (CudaInstallation.isValid())
+ getProgramPaths().push_back(CudaInstallation.getBinPath());
+}
void
CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
Linux::addClangTargetOptions(DriverArgs, CC1Args);
CC1Args.push_back("-fcuda-is-device");
+
+ if (DriverArgs.hasArg(options::OPT_nocudalib))
+ return;
+
+ std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(
+ DriverArgs.getLastArgValue(options::OPT_march_EQ));
+ if (!LibDeviceFile.empty()) {
+ CC1Args.push_back("-mlink-cuda-bitcode");
+ CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
+
+ // Libdevice in CUDA-7.0 requires PTX version that's more recent
+ // than LLVM defaults to. Use PTX4.2 which is the PTX version that
+ // came with CUDA-7.0.
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+ptx42");
+ }
}
llvm::opt::DerivedArgList *
@@ -4043,7 +4234,7 @@
for (Arg *A : Args) {
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches BoundArch
- if (A->getValue(0) != StringRef(BoundArch))
+ if (!BoundArch || A->getValue(0) != StringRef(BoundArch))
continue;
unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
@@ -4074,10 +4265,19 @@
DAL->append(A);
}
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
+ if (BoundArch)
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
return DAL;
}
+Tool *CudaToolChain::buildAssembler() const {
+ return new tools::NVPTX::Assembler(*this);
+}
+
+Tool *CudaToolChain::buildLinker() const {
+ return new tools::NVPTX::Linker(*this);
+}
+
/// XCore tool chain
XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
@@ -4153,12 +4353,33 @@
// choose the myriad installation when targeting a non-myriad sparc install.
switch (Triple.getArch()) {
default:
- D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() << "myriad";
+ D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
+ << "myriad";
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::shave:
GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"});
}
+
+ if (GCCInstallation.isValid()) {
+ // The contents of LibDir are independent of the version of gcc.
+ // This contains libc, libg (a superset of libc), libm, libstdc++, libssp.
+ SmallString<128> LibDir(GCCInstallation.getParentLibPath());
+ if (Triple.getArch() == llvm::Triple::sparcel)
+ llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib/le");
+ else
+ llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib");
+ addPathIfExists(D, LibDir, getFilePaths());
+
+ // This directory contains crt{i,n,begin,end}.o as well as libgcc.
+ // These files are tied to a particular version of gcc.
+ SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath());
+ // There are actually 4 choices: {le,be} x {fpu,nofpu}
+ // but as this toolchain is for LEON sparc, it can assume FPU.
+ if (Triple.getArch() == llvm::Triple::sparcel)
+ llvm::sys::path::append(CompilerSupportDir, "le");
+ addPathIfExists(D, CompilerSupportDir, getFilePaths());
+ }
}
MyriadToolChain::~MyriadToolChain() {}
@@ -4169,8 +4390,8 @@
addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
}
-void MyriadToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+void MyriadToolChain::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
@@ -4181,8 +4402,9 @@
StringRef TripleStr = GCCInstallation.getTriple().str();
const Multilib &Multilib = GCCInstallation.getMultilib();
- addLibStdCXXIncludePaths(LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
- "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args);
+ addLibStdCXXIncludePaths(
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
+ "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args);
}
// MyriadToolChain handles several triples:
@@ -4192,6 +4414,7 @@
if (!isShaveCompilation(getTriple()))
return ToolChain::SelectTool(JA);
switch (JA.getKind()) {
+ case Action::PreprocessJobClass:
case Action::CompileJobClass:
if (!Compiler)
Compiler.reset(new tools::SHAVE::Compiler(*this));
@@ -4205,31 +4428,17 @@
}
}
-void MyriadToolChain::getCompilerSupportDir(std::string &Dir) const {
- // This directory contains crt{i,n,begin,end}.o as well as libgcc.
- // These files are tied to a particular version of gcc.
- SmallString<128> Result(GCCInstallation.getInstallPath());
- // There are actually 4 choices: {le,be} x {fpu,nofpu}
- // but as this toolchain is for LEON sparc, it can assume FPU.
- if (this->getTriple().getArch() == llvm::Triple::sparcel)
- llvm::sys::path::append(Result, "le");
- Dir.assign(Result.str());
-}
-void MyriadToolChain::getBuiltinLibDir(std::string &Dir) const {
- // The contents of LibDir are independent of the version of gcc.
- // This contains libc, libg (a superset of libc), libm, libstdc++, libssp.
- SmallString<128> Result(GCCInstallation.getParentLibPath());
- if (this->getTriple().getArch() == llvm::Triple::sparcel)
- llvm::sys::path::append(Result, "../sparc-myriad-elf/lib/le");
- else
- llvm::sys::path::append(Result, "../sparc-myriad-elf/lib");
- Dir.assign(Result.str());
-}
-
Tool *MyriadToolChain::buildLinker() const {
return new tools::Myriad::Linker(*this);
}
+WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ // Use LLD by default.
+ DefaultLinker = "lld";
+}
+
bool WebAssembly::IsMathErrnoDefault() const { return false; }
bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
@@ -4252,6 +4461,8 @@
// TODO: Support profiling.
bool WebAssembly::SupportsProfiling() const { return false; }
+bool WebAssembly::HasNativeLLVMSupport() const { return true; }
+
void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
@@ -4259,6 +4470,33 @@
CC1Args.push_back("-fuse-init-array");
}
+ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const {
+ return ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
+ return ToolChain::CST_Libcxx;
+}
+
+void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(options::OPT_nostdinc))
+ addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
+}
+
+void WebAssembly::AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
+ !DriverArgs.hasArg(options::OPT_nostdincxx))
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/include/c++/v1");
+}
+
+Tool *WebAssembly::buildLinker() const {
+ return new tools::wasm::Linker(*this);
+}
+
PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
if (Args.hasArg(options::OPT_static))
@@ -4276,11 +4514,11 @@
} else {
PS4SDKDir = getDriver().Dir;
llvm::sys::path::append(PS4SDKDir, "/../../");
- }
+ }
- // By default, the driver won't report a warning if it can't find
+ // By default, the driver won't report a warning if it can't find
// PS4's include or lib directories. This behavior could be changed if
- // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
+ // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
// If -isysroot was passed, use that as the SDK base path.
std::string PrefixDir;
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 7743378..a5f5473 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -163,9 +163,11 @@
bool IsValid;
const Driver &D;
std::string CudaInstallPath;
+ std::string CudaBinPath;
std::string CudaLibPath;
std::string CudaLibDevicePath;
std::string CudaIncludePath;
+ llvm::StringMap<std::string> CudaLibDeviceMap;
public:
CudaInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
@@ -178,6 +180,8 @@
/// \brief Get the detected Cuda installation path.
StringRef getInstallPath() const { return CudaInstallPath; }
+ /// \brief Get the detected path to Cuda's bin directory.
+ StringRef getBinPath() const { return CudaBinPath; }
/// \brief Get the detected Cuda Include path.
StringRef getIncludePath() const { return CudaIncludePath; }
/// \brief Get the detected Cuda library path.
@@ -185,6 +189,9 @@
/// \brief Get the detected Cuda device library path.
StringRef getLibDevicePath() const { return CudaLibDevicePath; }
/// \brief Get libdevice file for given architecture
+ std::string getLibDeviceFile(StringRef Gpu) const {
+ return CudaLibDeviceMap.lookup(Gpu);
+ }
};
CudaInstallationDetector CudaInstallation;
@@ -562,6 +569,9 @@
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,
// Darwin defaults to standalone/full debug info.
bool GetDefaultStandaloneDebug() const override { return true; }
+ llvm::DebuggerKind getDefaultDebuggerTuning() const override {
+ return llvm::DebuggerKind::LLDB;
+ }
/// }
@@ -784,20 +794,19 @@
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
bool isPIEDefault() const override;
SanitizerMask getSupportedSanitizers() const override;
void addProfileRTLibs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ virtual std::string computeSysRoot() const;
- std::string Linker;
std::vector<std::string> ExtraOpts;
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
-
-private:
- std::string computeSysRoot() const;
};
class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux {
@@ -810,6 +819,50 @@
const char *BoundArch) const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+
+ // Never try to use the integrated assembler with CUDA; always fork out to
+ // ptxas.
+ bool useIntegratedAs() const override { return false; }
+
+protected:
+ Tool *buildAssembler() const override; // ptxas
+ Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
+};
+
+class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux {
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ bool Shared = false) const override;
+
+ std::string computeSysRoot() const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc
+ : RuntimeLibType::RLT_CompilerRT;
+ }
+
+private:
+ Multilib SelectedMultilib;
+ std::string LibSuffix;
};
class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
@@ -832,15 +885,21 @@
CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
+ bool IsIntegratedAssemblerDefault() const override {
+ return true;
+ }
- std::string GetGnuDir(const std::string &InstalledDir,
- const llvm::opt::ArgList &Args) const;
+ std::string getHexagonTargetDir(
+ const std::string &InstalledDir,
+ const SmallVectorImpl<std::string> &PrefixDirs) const;
+ void getHexagonLibraryPaths(const llvm::opt::ArgList &Args,
+ ToolChain::path_list &LibPaths) const;
- static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
+ static const StringRef GetDefaultCPU();
+ static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
- static const char *GetSmallDataThreshold(const llvm::opt::ArgList &Args);
-
- static bool UsesG0(const char *smallDataThreshold);
+ static Optional<unsigned> getSmallDataThreshold(
+ const llvm::opt::ArgList &Args);
};
class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
@@ -881,7 +940,6 @@
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const override;
- std::string Linker;
protected:
Tool *buildLinker() const override;
@@ -1028,8 +1086,6 @@
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
Tool *SelectTool(const JobAction &JA) const override;
- void getCompilerSupportDir(std::string &Dir) const;
- void getBuiltinLibDir(std::string &Dir) const;
unsigned GetDefaultDwarfVersion() const override { return 2; }
protected:
@@ -1046,8 +1102,7 @@
class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain {
public:
WebAssembly(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : ToolChain(D, Triple, Args) {}
+ const llvm::opt::ArgList &Args);
private:
bool IsMathErrnoDefault() const override;
@@ -1060,8 +1115,19 @@
bool hasBlocksRuntime() const override;
bool SupportsObjCGC() const override;
bool SupportsProfiling() const override;
+ bool HasNativeLLVMSupport() const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ RuntimeLibType GetDefaultRuntimeLibType() const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF {
@@ -1078,6 +1144,10 @@
return 2; // SSPStrong
}
+ llvm::DebuggerKind getDefaultDebuggerTuning() const override {
+ return llvm::DebuggerKind::SCE;
+ }
+
SanitizerMask getSupportedSanitizers() const override;
protected:
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index e06f5c3..1d07fa0 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -52,6 +52,24 @@
using namespace clang;
using namespace llvm::opt;
+static void handleTargetFeaturesGroup(const ArgList &Args,
+ std::vector<const char *> &Features,
+ OptSpecifier Group) {
+ for (const Arg *A : Args.filtered(Group)) {
+ StringRef Name = A->getOption().getName();
+ A->claim();
+
+ // Skip over "-m".
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
+
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
+}
+
static const char *getSparcAsmModeForCPU(StringRef Name,
const llvm::Triple &Triple) {
if (Triple.getArch() == llvm::Triple::sparcv9) {
@@ -215,13 +233,9 @@
Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input);
for (const auto &II : Inputs) {
- if (!TC.HasNativeLLVMSupport()) {
+ if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType()))
// Don't try to pass LLVM inputs unless we have native support.
- if (II.getType() == types::TY_LLVM_IR ||
- II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
- D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString();
- }
+ D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString();
// Add filenames immediately.
if (II.isFilename()) {
@@ -278,7 +292,8 @@
const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfo &Output,
- const InputInfoList &Inputs) const {
+ const InputInfoList &Inputs,
+ const ToolChain *AuxToolChain) const {
Arg *A;
CheckPreprocessingOptions(D, Args);
@@ -470,12 +485,26 @@
// OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH");
+ // Optional AuxToolChain indicates that we need to include headers
+ // for more than one target. If that's the case, add include paths
+ // from AuxToolChain right after include paths of the same kind for
+ // the current target.
+
// Add C++ include arguments, if needed.
- if (types::isCXX(Inputs[0].getType()))
+ if (types::isCXX(Inputs[0].getType())) {
getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+ if (AuxToolChain)
+ AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+ }
// Add system include arguments.
getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs);
+ if (AuxToolChain)
+ AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+
+ // Add CUDA include arguments, if needed.
+ if (types::isCuda(Inputs[0].getType()))
+ getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
}
// FIXME: Move to target hook.
@@ -574,23 +603,47 @@
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
+// Decode ARM features from string like +[no]featureA+[no]featureB+...
+static bool DecodeARMFeatures(const Driver &D, StringRef text,
+ std::vector<const char *> &Features) {
+ SmallVector<StringRef, 8> Split;
+ text.split(Split, StringRef("+"), -1, false);
+
+ for (StringRef Feature : Split) {
+ const char *FeatureName = llvm::ARM::getArchExtFeature(Feature);
+ if (FeatureName)
+ Features.push_back(FeatureName);
+ else
+ return false;
+ }
+ return true;
+}
+
// Check if -march is valid by checking if it can be canonicalised and parsed.
// getARMArch is used here instead of just checking the -march value in order
// to handle -march=native correctly.
static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
llvm::StringRef ArchName,
+ std::vector<const char *> &Features,
const llvm::Triple &Triple) {
+ std::pair<StringRef, StringRef> Split = ArchName.split("+");
+
std::string MArch = arm::getARMArch(ArchName, Triple);
- if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID)
+ if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID ||
+ (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
llvm::StringRef CPUName, llvm::StringRef ArchName,
+ std::vector<const char *> &Features,
const llvm::Triple &Triple) {
+ std::pair<StringRef, StringRef> Split = CPUName.split("+");
+
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
- if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty())
+ if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() ||
+ (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
@@ -645,6 +698,7 @@
case llvm::Triple::TvOS: {
// Darwin defaults to "softfp" for v6 and v7.
ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
+ ABI = Triple.isWatchABI() ? FloatABI::Hard : ABI;
break;
}
case llvm::Triple::WatchOS:
@@ -756,12 +810,12 @@
D.Diag(clang::diag::warn_drv_unused_argument)
<< ArchArg->getAsString(Args);
ArchName = StringRef(WaArch->getValue()).substr(7);
- checkARMArchName(D, WaArch, Args, ArchName, Triple);
+ checkARMArchName(D, WaArch, Args, ArchName, Features, Triple);
// FIXME: Set Arch.
D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args);
} else if (ArchArg) {
ArchName = ArchArg->getValue();
- checkARMArchName(D, ArchArg, Args, ArchName, Triple);
+ checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple);
}
// Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
@@ -772,10 +826,10 @@
D.Diag(clang::diag::warn_drv_unused_argument)
<< CPUArg->getAsString(Args);
CPUName = StringRef(WaCPU->getValue()).substr(6);
- checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Triple);
+ checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple);
} else if (CPUArg) {
CPUName = CPUArg->getValue();
- checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Triple);
+ checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple);
}
// Add CPU features for generic CPUs
@@ -886,7 +940,7 @@
Features.push_back("+reserve-r9");
// The kext linker doesn't know how to deal with movw/movt.
- if (KernelOrKext)
+ if (KernelOrKext || Args.hasArg(options::OPT_mno_movt))
Features.push_back("+no-movt");
}
@@ -901,7 +955,7 @@
} else if (Triple.isOSBinFormatMachO()) {
if (useAAPCSForMachO(Triple)) {
ABIName = "aapcs";
- } else if (Triple.isWatchOS()) {
+ } else if (Triple.isWatchABI()) {
ABIName = "aapcs16";
} else {
ABIName = "apcs-gnu";
@@ -1115,6 +1169,16 @@
// FIXME: Warn on inconsistent use of -march and -mabi.
}
+std::string mips::getMipsABILibSuffix(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ StringRef CPUName, ABIName;
+ tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ return llvm::StringSwitch<std::string>(ABIName)
+ .Case("o32", "")
+ .Case("n32", "32")
+ .Case("n64", "64");
+}
+
// Convert ABI name to the GNU tools acceptable variant.
static StringRef getGnuCompatibleMipsABIName(StringRef ABI) {
return llvm::StringSwitch<llvm::StringRef>(ABI)
@@ -1362,35 +1426,56 @@
return "";
}
-static void getPPCTargetFeatures(const ArgList &Args,
+static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
std::vector<const char *> &Features) {
- for (const Arg *A : Args.filtered(options::OPT_m_ppc_Features_Group)) {
- StringRef Name = A->getOption().getName();
- A->claim();
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
-
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
-
- // Note that gcc calls this mfcrf and LLVM calls this mfocrf so we
- // pass the correct option to the backend while calling the frontend
- // option the same.
- // TODO: Change the LLVM backend option maybe?
- if (Name == "mfcrf")
- Name = "mfocrf";
-
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
+ ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
+ if (FloatABI == ppc::FloatABI::Soft &&
+ !(Triple.getArch() == llvm::Triple::ppc64 ||
+ Triple.getArch() == llvm::Triple::ppc64le))
+ Features.push_back("+soft-float");
+ else if (FloatABI == ppc::FloatABI::Soft &&
+ (Triple.getArch() == llvm::Triple::ppc64 ||
+ Triple.getArch() == llvm::Triple::ppc64le))
+ D.Diag(diag::err_drv_invalid_mfloat_abi)
+ << "soft float is not supported for ppc64";
// Altivec is a bit weird, allow overriding of the Altivec feature here.
AddTargetFeature(Args, Features, options::OPT_faltivec,
options::OPT_fno_altivec, "altivec");
}
+ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
+ ppc::FloatABI ABI = ppc::FloatABI::Invalid;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float))
+ ABI = ppc::FloatABI::Soft;
+ else if (A->getOption().matches(options::OPT_mhard_float))
+ ABI = ppc::FloatABI::Hard;
+ else {
+ ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
+ .Case("soft", ppc::FloatABI::Soft)
+ .Case("hard", ppc::FloatABI::Hard)
+ .Default(ppc::FloatABI::Invalid);
+ if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
+ D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = ppc::FloatABI::Hard;
+ }
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ if (ABI == ppc::FloatABI::Invalid) {
+ ABI = ppc::FloatABI::Hard;
+ }
+
+ return ABI;
+}
+
void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Select the ABI to use.
@@ -1427,6 +1512,21 @@
if (StringRef(A->getValue()) != "altivec")
ABIName = A->getValue();
+ ppc::FloatABI FloatABI =
+ ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
+
+ if (FloatABI == ppc::FloatABI::Soft) {
+ // Floating point operations and argument passing are soft.
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
+ }
+
if (ABIName) {
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
@@ -1669,7 +1769,8 @@
return getX86TargetCPU(Args, T);
case llvm::Triple::hexagon:
- return "hexagon" + toolchains::HexagonToolChain::GetTargetCPU(Args).str();
+ return "hexagon" +
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
case llvm::Triple::systemz:
return getSystemZTargetCPU(Args);
@@ -1702,6 +1803,19 @@
if (!CPU.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ StringRef OOpt;
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ OOpt = "3";
+ else if (A->getOption().matches(options::OPT_O))
+ OOpt = A->getValue();
+ else if (A->getOption().matches(options::OPT_O0))
+ OOpt = "0";
+ if (!OOpt.empty())
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
+ }
+
if (IsThinLTO)
CmdArgs.push_back("-plugin-opt=thinlto");
}
@@ -1898,20 +2012,7 @@
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
- for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group)) {
- StringRef Name = A->getOption().getName();
- A->claim();
-
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
-
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
-
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group);
}
void Clang::AddX86TargetArgs(const ArgList &Args,
@@ -1952,12 +2053,11 @@
CmdArgs.push_back("-mqdsp6-compat");
CmdArgs.push_back("-Wreturn-type");
- if (const char *v =
- toolchains::HexagonToolChain::GetSmallDataThreshold(Args)) {
- std::string SmallDataThreshold = "-hexagon-small-data-threshold=";
- SmallDataThreshold += v;
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ std::string Opt = std::string("-hexagon-small-data-threshold=") + N;
CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
+ CmdArgs.push_back(Args.MakeArgString(Opt));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -1970,6 +2070,16 @@
CmdArgs.push_back("-machine-sink-split=0");
}
+void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Default to "hidden" visibility.
+ if (!Args.hasArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ }
+}
+
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
static bool DecodeAArch64Features(const Driver &D, StringRef text,
std::vector<const char *> &Features) {
@@ -1982,10 +2092,14 @@
.Case("simd", "+neon")
.Case("crc", "+crc")
.Case("crypto", "+crypto")
+ .Case("fp16", "+fullfp16")
+ .Case("profile", "+spe")
.Case("nofp", "-fp-armv8")
.Case("nosimd", "-neon")
.Case("nocrc", "-crc")
.Case("nocrypto", "-crypto")
+ .Case("nofp16", "-fullfp16")
+ .Case("noprofile", "-spe")
.Default(nullptr);
if (result)
Features.push_back(result);
@@ -2004,7 +2118,7 @@
std::pair<StringRef, StringRef> Split = Mcpu.split("+");
CPU = Split.first;
if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" ||
- CPU == "cortex-a72") {
+ CPU == "cortex-a72" || CPU == "cortex-a35" || CPU == "exynos-m1") {
Features.push_back("+neon");
Features.push_back("+crc");
Features.push_back("+crypto");
@@ -2031,6 +2145,8 @@
// ok, no additional features.
} else if (Split.first == "armv8.1-a" || Split.first == "armv8.1a") {
Features.push_back("+v8.1a");
+ } else if (Split.first == "armv8.2-a" || Split.first == "armv8.2a" ) {
+ Features.push_back("+v8.2a");
} else {
return false;
}
@@ -2081,9 +2197,7 @@
return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
}
-static void getAArch64TargetFeatures(const Driver &D,
- const llvm::Triple &Triple,
- const ArgList &Args,
+static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
std::vector<const char *> &Features) {
Arg *A;
bool success = true;
@@ -2129,26 +2243,39 @@
if (A->getOption().matches(options::OPT_mno_unaligned_access))
Features.push_back("+strict-align");
- if (Args.hasArg(options::OPT_ffixed_x18) || Triple.isOSDarwin())
+ if (Args.hasArg(options::OPT_ffixed_x18))
Features.push_back("+reserve-x18");
}
+static void getHexagonTargetFeatures(const ArgList &Args,
+ std::vector<const char *> &Features) {
+ bool HasHVX = false, HasHVXD = false;
+
+ // FIXME: This should be able to use handleTargetFeaturesGroup except it is
+ // doing dependent option handling here rather than in initFeatureMap or a
+ // similar handler.
+ for (auto &A : Args) {
+ auto &Opt = A->getOption();
+ if (Opt.matches(options::OPT_mhexagon_hvx))
+ HasHVX = true;
+ else if (Opt.matches(options::OPT_mno_hexagon_hvx))
+ HasHVXD = HasHVX = false;
+ else if (Opt.matches(options::OPT_mhexagon_hvx_double))
+ HasHVXD = HasHVX = true;
+ else if (Opt.matches(options::OPT_mno_hexagon_hvx_double))
+ HasHVXD = false;
+ else
+ continue;
+ A->claim();
+ }
+
+ Features.push_back(HasHVX ? "+hvx" : "-hvx");
+ Features.push_back(HasHVXD ? "+hvx-double" : "-hvx-double");
+}
+
static void getWebAssemblyTargetFeatures(const ArgList &Args,
std::vector<const char *> &Features) {
- for (const Arg *A : Args.filtered(options::OPT_m_wasm_Features_Group)) {
- StringRef Name = A->getOption().getName();
- A->claim();
-
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
-
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
-
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
}
static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
@@ -2176,19 +2303,22 @@
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
- getPPCTargetFeatures(Args, Features);
+ getPPCTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::systemz:
getSystemZTargetFeatures(Args, Features);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
- getAArch64TargetFeatures(D, Triple, Args, Features);
+ getAArch64TargetFeatures(D, Args, Features);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
getX86TargetFeatures(D, Triple, Args, Features);
break;
+ case llvm::Triple::hexagon:
+ getHexagonTargetFeatures(Args, Features);
+ break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
getWebAssemblyTargetFeatures(Args, Features);
@@ -2364,6 +2494,20 @@
RelaxDefault);
}
+// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
+// to the corresponding DebugInfoKind.
+static CodeGenOptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
+ assert(A.getOption().matches(options::OPT_gN_Group) &&
+ "Not a -g option that specifies a debug-info level");
+ if (A.getOption().matches(options::OPT_g0) ||
+ A.getOption().matches(options::OPT_ggdb0))
+ return CodeGenOptions::NoDebugInfo;
+ if (A.getOption().matches(options::OPT_gline_tables_only) ||
+ A.getOption().matches(options::OPT_ggdb1))
+ return CodeGenOptions::DebugLineTablesOnly;
+ return CodeGenOptions::LimitedDebugInfo;
+}
+
// Extract the integer N from a string spelled "-dwarf-N", returning 0
// on mismatch. The StringRef input (rather than an Arg) allows
// for use by the "-Xassembler" option parser.
@@ -2372,12 +2516,14 @@
.Case("-gdwarf-2", 2)
.Case("-gdwarf-3", 3)
.Case("-gdwarf-4", 4)
+ .Case("-gdwarf-5", 5)
.Default(0);
}
static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
CodeGenOptions::DebugInfoKind DebugInfoKind,
- unsigned DwarfVersion) {
+ unsigned DwarfVersion,
+ llvm::DebuggerKind DebuggerTuning) {
switch (DebugInfoKind) {
case CodeGenOptions::DebugLineTablesOnly:
CmdArgs.push_back("-debug-info-kind=line-tables-only");
@@ -2394,6 +2540,19 @@
if (DwarfVersion > 0)
CmdArgs.push_back(
Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
+ switch (DebuggerTuning) {
+ case llvm::DebuggerKind::GDB:
+ CmdArgs.push_back("-debugger-tuning=gdb");
+ break;
+ case llvm::DebuggerKind::LLDB:
+ CmdArgs.push_back("-debugger-tuning=lldb");
+ break;
+ case llvm::DebuggerKind::SCE:
+ CmdArgs.push_back("-debugger-tuning=sce");
+ break;
+ default:
+ break;
+ }
}
static void CollectArgsForIntegratedAssembler(Compilation &C,
@@ -2403,6 +2562,15 @@
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-mrelax-all");
+ // Only default to -mincremental-linker-compatible if we think we are
+ // targeting the MSVC linker.
+ bool DefaultIncrementalLinkerCompatible =
+ C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
+ if (Args.hasFlag(options::OPT_mincremental_linker_compatible,
+ options::OPT_mno_incremental_linker_compatible,
+ DefaultIncrementalLinkerCompatible))
+ CmdArgs.push_back("-mincremental-linker-compatible");
+
// When passing -I arguments to the assembler we sometimes need to
// unconditionally take the next argument. For example, when parsing
// '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
@@ -2413,6 +2581,7 @@
// When using an integrated assembler, translate -Wa, and -Xassembler
// options.
bool CompressDebugSections = false;
+ const char *MipsTargetFeature = nullptr;
for (const Arg *A :
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
A->claim();
@@ -2451,7 +2620,26 @@
CmdArgs.push_back("-soft-float");
continue;
}
- break;
+
+ MipsTargetFeature = llvm::StringSwitch<const char *>(Value)
+ .Case("-mips1", "+mips1")
+ .Case("-mips2", "+mips2")
+ .Case("-mips3", "+mips3")
+ .Case("-mips4", "+mips4")
+ .Case("-mips5", "+mips5")
+ .Case("-mips32", "+mips32")
+ .Case("-mips32r2", "+mips32r2")
+ .Case("-mips32r3", "+mips32r3")
+ .Case("-mips32r5", "+mips32r5")
+ .Case("-mips32r6", "+mips32r6")
+ .Case("-mips64", "+mips64")
+ .Case("-mips64r2", "+mips64r2")
+ .Case("-mips64r3", "+mips64r3")
+ .Case("-mips64r5", "+mips64r5")
+ .Case("-mips64r6", "+mips64r6")
+ .Default(nullptr);
+ if (MipsTargetFeature)
+ continue;
}
if (Value == "-force_cpusubtype_ALL") {
@@ -2481,7 +2669,8 @@
CmdArgs.push_back(Value.data());
} else {
RenderDebugEnablingArgs(
- Args, CmdArgs, CodeGenOptions::LimitedDebugInfo, DwarfVersion);
+ Args, CmdArgs, CodeGenOptions::LimitedDebugInfo, DwarfVersion,
+ llvm::DebuggerKind::Default);
}
} else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
Value.startswith("-mhwdiv") || Value.startswith("-march")) {
@@ -2498,6 +2687,10 @@
else
D.Diag(diag::warn_debug_compression_unavailable);
}
+ if (MipsTargetFeature != nullptr) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(MipsTargetFeature);
+ }
}
// This adds the static libclang_rt.builtins-arch.a directly to the command line
@@ -2581,12 +2774,12 @@
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, StringRef Sanitizer,
- bool IsShared) {
- // Static runtimes must be forced into executable, so we wrap them in
+ bool IsShared, bool IsWhole) {
+ // Wrap any static runtimes that must be forced into executable in
// whole-archive.
- if (!IsShared) CmdArgs.push_back("-whole-archive");
+ if (IsWhole) CmdArgs.push_back("-whole-archive");
CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared));
- if (!IsShared) CmdArgs.push_back("-no-whole-archive");
+ if (IsWhole) CmdArgs.push_back("-no-whole-archive");
}
// Tries to use a file with the list of dynamic symbols that need to be exported
@@ -2619,12 +2812,17 @@
collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
SmallVectorImpl<StringRef> &SharedRuntimes,
SmallVectorImpl<StringRef> &StaticRuntimes,
- SmallVectorImpl<StringRef> &HelperStaticRuntimes) {
+ SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
+ SmallVectorImpl<StringRef> &HelperStaticRuntimes,
+ SmallVectorImpl<StringRef> &RequiredSymbols) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
// Collect shared runtimes.
if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
SharedRuntimes.push_back("asan");
}
+ // The stats_client library is also statically linked into DSOs.
+ if (SanArgs.needsStatsRt())
+ StaticRuntimes.push_back("stats_client");
// Collect static runtimes.
if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) {
@@ -2661,6 +2859,14 @@
}
if (SanArgs.needsSafeStackRt())
StaticRuntimes.push_back("safestack");
+ if (SanArgs.needsCfiRt())
+ StaticRuntimes.push_back("cfi");
+ if (SanArgs.needsCfiDiagRt())
+ StaticRuntimes.push_back("cfi_diag");
+ if (SanArgs.needsStatsRt()) {
+ NonWholeStaticRuntimes.push_back("stats");
+ RequiredSymbols.push_back("__sanitizer_stats_register");
+ }
}
// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
@@ -2668,18 +2874,27 @@
static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
- HelperStaticRuntimes;
+ NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
- HelperStaticRuntimes);
+ NonWholeStaticRuntimes, HelperStaticRuntimes,
+ RequiredSymbols);
for (auto RT : SharedRuntimes)
- addSanitizerRuntime(TC, Args, CmdArgs, RT, true);
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
for (auto RT : HelperStaticRuntimes)
- addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
bool AddExportDynamic = false;
for (auto RT : StaticRuntimes) {
- addSanitizerRuntime(TC, Args, CmdArgs, RT, false);
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
}
+ for (auto RT : NonWholeStaticRuntimes) {
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
+ AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
+ }
+ for (auto S : RequiredSymbols) {
+ CmdArgs.push_back("-u");
+ CmdArgs.push_back(Args.MakeArgString(S));
+ }
// If there is a static runtime with no dynamic list, force all the symbols
// to be dynamic to be sure we export sanitizer interface functions.
if (AddExportDynamic)
@@ -2747,6 +2962,8 @@
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
return A->getOption().matches(options::OPT_fno_omit_frame_pointer);
+ if (Args.hasArg(options::OPT_pg))
+ return true;
return shouldUseFramePointerForTarget(Args, Triple);
}
@@ -2756,6 +2973,8 @@
if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
options::OPT_momit_leaf_frame_pointer))
return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
+ if (Args.hasArg(options::OPT_pg))
+ return true;
if (Triple.isPS4CPU())
return false;
@@ -2804,7 +3023,7 @@
ExtractArgs.push_back(OutFile);
const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy"));
- InputInfo II(Output.getFilename(), types::TY_Object, Output.getFilename());
+ InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename());
// First extract the dwo sections.
C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
@@ -3059,6 +3278,23 @@
}
}
+static void addPS4ProfileRTArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
+ Args.hasFlag(options::OPT_fprofile_generate,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_generate_EQ,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_instr_generate,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)))
+ CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
+}
+
/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then,
/// smooshes them together with platform defaults, to decide whether
/// this compile should be using PIC mode or not. Returns a tuple of
@@ -3070,6 +3306,10 @@
// ToolChain.getTriple() and Triple?
bool PIE = ToolChain.isPIEDefault();
bool PIC = PIE || ToolChain.isPICDefault();
+ // The Darwin/MachO default to use PIC does not apply when using -static.
+ if (ToolChain.getTriple().isOSBinFormatMachO() &&
+ Args.hasArg(options::OPT_static))
+ PIE = PIC = false;
bool IsPICLevelTwo = PIC;
bool KernelOrKext =
@@ -3254,6 +3494,25 @@
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
+ const ToolChain *AuxToolChain = nullptr;
+ if (IsCuda) {
+ // FIXME: We need a (better) way to pass information about
+ // particular compilation pass we're constructing here. For now we
+ // can check which toolchain we're using and pick the other one to
+ // extract the triple.
+ if (&getToolChain() == C.getCudaDeviceToolChain())
+ AuxToolChain = C.getCudaHostToolChain();
+ else if (&getToolChain() == C.getCudaHostToolChain())
+ AuxToolChain = C.getCudaDeviceToolChain();
+ else
+ llvm_unreachable("Can't figure out CUDA compilation mode.");
+ assert(AuxToolChain != nullptr && "No aux toolchain.");
+ CmdArgs.push_back("-aux-triple");
+ CmdArgs.push_back(Args.MakeArgString(AuxToolChain->getTriple().str()));
+ CmdArgs.push_back("-fcuda-target-overloads");
+ CmdArgs.push_back("-fcuda-disable-target-call-checks");
+ }
+
if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
@@ -3343,6 +3602,13 @@
Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ);
}
+ if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
+ if (!types::isLLVMIR(Input.getType()))
+ D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
+ << "-x ir";
+ Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
+ }
+
// We normally speed up the clang process a bit by skipping destructors at
// exit, but when we're generating diagnostics we can rely on some of the
// cleanup.
@@ -3377,8 +3643,23 @@
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
- if (!IsWindowsMSVC)
- CmdArgs.push_back("-analyzer-checker=unix");
+ if (!IsWindowsMSVC) {
+ CmdArgs.push_back("-analyzer-checker=unix");
+ } else {
+ // Enable "unix" checkers that also work on Windows.
+ CmdArgs.push_back("-analyzer-checker=unix.API");
+ CmdArgs.push_back("-analyzer-checker=unix.Malloc");
+ CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof");
+ CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator");
+ CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg");
+ CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg");
+ }
+
+ // Disable some unix checkers for PS4.
+ if (IsPS4CPU) {
+ CmdArgs.push_back("-analyzer-disable-checker=unix.API");
+ CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
+ }
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
CmdArgs.push_back("-analyzer-checker=osx");
@@ -3388,14 +3669,15 @@
if (types::isCXX(Input.getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
- // Enable the following experimental checkers for testing.
- CmdArgs.push_back(
- "-analyzer-checker=security.insecureAPI.UncheckedReturn");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
+ if (!IsPS4CPU) {
+ CmdArgs.push_back(
+ "-analyzer-checker=security.insecureAPI.UncheckedReturn");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
+ }
// Default nullability checks.
CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull");
@@ -3703,7 +3985,8 @@
if (KernelOrKext && getToolChain().getTriple().isOSDarwin())
CmdArgs.push_back("-fforbid-guard-variables");
- if (Args.hasArg(options::OPT_mms_bitfields)) {
+ if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
+ false)) {
CmdArgs.push_back("-mms-bitfields");
}
@@ -3795,20 +4078,27 @@
case llvm::Triple::hexagon:
AddHexagonTargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ AddWebAssemblyTargetArgs(Args, CmdArgs);
+ break;
}
// The 'g' groups options involve a somewhat intricate sequence of decisions
// about what to pass from the driver to the frontend, but by the time they
- // reach cc1 they've been factored into two well-defined orthogonal choices:
+ // reach cc1 they've been factored into three well-defined orthogonal choices:
// * what level of debug info to generate
// * what dwarf version to write
+ // * what debugger tuning to use
// This avoids having to monkey around further in cc1 other than to disable
// codeview if not running in a Windows environment. Perhaps even that
// decision should be made in the driver as well though.
+ unsigned DwarfVersion = 0;
+ llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning();
+ // These two are potentially updated by AddClangCLArgs.
enum CodeGenOptions::DebugInfoKind DebugInfoKind =
CodeGenOptions::NoDebugInfo;
- // These two are potentially updated by AddClangCLArgs.
- unsigned DwarfVersion = 0;
bool EmitCodeView = false;
// Add clang-cl arguments.
@@ -3857,27 +4147,34 @@
Args.ClaimAllArgs(options::OPT_g_Group);
Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- // If you say "-gline-tables-only -gsplit-dwarf", split-dwarf wins,
- // which mandates turning on "-g". But -split-dwarf is not a g_group option,
- // hence it takes a nontrivial test to decide about line-tables-only.
- if (A->getOption().matches(options::OPT_gline_tables_only) &&
- (!SplitDwarfArg || A->getIndex() > SplitDwarfArg->getIndex())) {
- DebugInfoKind = CodeGenOptions::DebugLineTablesOnly;
- SplitDwarfArg = nullptr;
- } else if (!A->getOption().matches(options::OPT_g0)) {
- // Some 'g' group option other than one expressly disabling debug info
- // must have been the final (winning) one. They're all equivalent.
+ // If the last option explicitly specified a debug-info level, use it.
+ if (A->getOption().matches(options::OPT_gN_Group)) {
+ DebugInfoKind = DebugLevelToInfoKind(*A);
+ // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses.
+ // But -gsplit-dwarf is not a g_group option, hence we have to check the
+ // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.)
+ if (SplitDwarfArg && DebugInfoKind < CodeGenOptions::LimitedDebugInfo &&
+ A->getIndex() > SplitDwarfArg->getIndex())
+ SplitDwarfArg = nullptr;
+ } else
+ // For any other 'g' option, use Limited.
DebugInfoKind = CodeGenOptions::LimitedDebugInfo;
- }
}
- // If a -gdwarf argument appeared, use it, unless DebugInfoKind is None
- // (because that would mean that "-g0" was the rightmost 'g' group option).
- // FIXME: specifying "-gdwarf-<N>" "-g1" in that order works,
- // but "-g1" "-gdwarf-<N>" does not. A deceptively simple (but wrong) "fix"
- // exists of removing the gdwarf options from the g_group.
+ // If a debugger tuning argument appeared, remember it.
+ if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
+ options::OPT_ggdbN_Group)) {
+ if (A->getOption().matches(options::OPT_glldb))
+ DebuggerTuning = llvm::DebuggerKind::LLDB;
+ else if (A->getOption().matches(options::OPT_gsce))
+ DebuggerTuning = llvm::DebuggerKind::SCE;
+ else
+ DebuggerTuning = llvm::DebuggerKind::GDB;
+ }
+
+ // If a -gdwarf argument appeared, remember it.
if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
- options::OPT_gdwarf_4))
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5))
DwarfVersion = DwarfVersionNum(A->getSpelling());
// Forward -gcodeview.
@@ -3924,7 +4221,8 @@
getToolChain().GetDefaultStandaloneDebug());
if (DebugInfoKind == CodeGenOptions::LimitedDebugInfo && NeedFullDebug)
DebugInfoKind = CodeGenOptions::FullDebugInfo;
- RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion);
+ RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
+ DebuggerTuning);
// -ggnu-pubnames turns on gnu style pubnames in the backend.
if (Args.hasArg(options::OPT_ggnu_pubnames)) {
@@ -3946,8 +4244,11 @@
CmdArgs.push_back("-generate-type-units");
}
- // CloudABI uses -ffunction-sections and -fdata-sections by default.
- bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI;
+ // CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
+ // default.
+ bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI ||
+ Triple.getArch() == llvm::Triple::wasm32 ||
+ Triple.getArch() == llvm::Triple::wasm64;
if (Args.hasFlag(options::OPT_ffunction_sections,
options::OPT_fno_function_sections, UseSeparateSections)) {
@@ -3967,6 +4268,10 @@
addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
+ // Add runtime flag for PS4 when PGO or Coverage are enabled.
+ if (getToolChain().getTriple().isPS4CPU())
+ addPS4ProfileRTArgs(getToolChain(), Args, CmdArgs);
+
// Pass options for controlling the default header search paths.
if (Args.hasArg(options::OPT_nostdinc)) {
CmdArgs.push_back("-nostdsysteminc");
@@ -4059,7 +4364,8 @@
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
+ AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs,
+ AuxToolChain);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
@@ -4301,7 +4607,7 @@
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
// Emulated TLS is enabled by default on Android, and can be enabled manually
// with -femulated-tls.
- bool EmulatedTLSDefault = Triple.isAndroid();
+ bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isWindowsCygwinEnvironment();
if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
EmulatedTLSDefault))
CmdArgs.push_back("-femulated-tls");
@@ -4505,11 +4811,33 @@
A->render(Args, CmdArgs);
}
- // -fbuiltin is default unless -mkernel is used
- if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
- !Args.hasArg(options::OPT_mkernel)))
+ // -fbuiltin is default unless -mkernel is used.
+ bool UseBuiltins =
+ Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
+ !Args.hasArg(options::OPT_mkernel));
+ if (!UseBuiltins)
CmdArgs.push_back("-fno-builtin");
+ // -ffreestanding implies -fno-builtin.
+ if (Args.hasArg(options::OPT_ffreestanding))
+ UseBuiltins = false;
+
+ // Process the -fno-builtin-* options.
+ for (const auto &Arg : Args) {
+ const Option &O = Arg->getOption();
+ if (!O.matches(options::OPT_fno_builtin_))
+ continue;
+
+ Arg->claim();
+ // If -fno-builtin is specified, then there's no need to pass the option to
+ // the frontend.
+ if (!UseBuiltins)
+ continue;
+
+ StringRef FuncName = Arg->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
+ }
+
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
@@ -4714,12 +5042,15 @@
}
// -fuse-cxa-atexit is default.
- if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
- options::OPT_fno_use_cxa_atexit,
- !IsWindowsCygnus && !IsWindowsGNU &&
- getToolChain().getTriple().getOS() != llvm::Triple::Solaris &&
- getToolChain().getArch() != llvm::Triple::hexagon &&
- getToolChain().getArch() != llvm::Triple::xcore) ||
+ if (!Args.hasFlag(
+ options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
+ !IsWindowsCygnus && !IsWindowsGNU &&
+ getToolChain().getTriple().getOS() != llvm::Triple::Solaris &&
+ getToolChain().getArch() != llvm::Triple::hexagon &&
+ getToolChain().getArch() != llvm::Triple::xcore &&
+ ((getToolChain().getTriple().getVendor() !=
+ llvm::Triple::MipsTechnologies) ||
+ getToolChain().getTriple().hasEnvironment())) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
@@ -5438,7 +5769,7 @@
// -fgnu-runtime
} else {
assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime));
- // Legacy behaviour is to target the gnustep runtime if we are i
+ // Legacy behaviour is to target the gnustep runtime if we are in
// non-fragile mode or the GCC runtime in fragile mode.
if (isNonFragile)
runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6));
@@ -5729,7 +6060,8 @@
unsigned DwarfVersion = 0;
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- WantDebug = !A->getOption().matches(options::OPT_g0);
+ WantDebug = !A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0);
if (WantDebug)
DwarfVersion = DwarfVersionNum(A->getSpelling());
}
@@ -5738,7 +6070,7 @@
RenderDebugEnablingArgs(Args, CmdArgs,
(WantDebug ? CodeGenOptions::LimitedDebugInfo
: CodeGenOptions::NoDebugInfo),
- DwarfVersion);
+ DwarfVersion, llvm::DebuggerKind::Default);
// Add the -fdebug-compilation-dir flag if needed.
addDebugCompDirArg(Args, CmdArgs);
@@ -5806,8 +6138,7 @@
// doesn't handle that so rather than warning about unused flags that are
// actually used, we'll lie by omission instead.
// FIXME: Stop lying and consume only the appropriate driver flags
- for (const Arg *A : Args.filtered(options::OPT_W_Group))
- A->claim();
+ Args.ClaimAllArgs(options::OPT_W_Group);
CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
getToolChain().getDriver());
@@ -5844,6 +6175,12 @@
for (const auto &A : Args) {
if (forwardToGCC(A->getOption())) {
+ // It is unfortunate that we have to claim here, as this means
+ // we will basically never report anything interesting for
+ // platforms using a generic gcc, even if we are just using gcc
+ // to get to the assembler.
+ A->claim();
+
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -5854,11 +6191,6 @@
A->getOption().matches(options::OPT_W_Group))
continue;
- // It is unfortunate that we have to claim here, as this means
- // we will basically never report anything interesting for
- // platforms using a generic gcc, even if we are just using gcc
- // to get to the assembler.
- A->claim();
A->render(Args, CmdArgs);
}
}
@@ -5914,8 +6246,7 @@
// inputs into '-Wl,' options?
for (const auto &II : Inputs) {
// Don't try to pass LLVM or AST inputs to a generic gcc.
- if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
+ if (types::isLLVMIR(II.getType()))
D.Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
else if (II.getType() == types::TY_AST)
@@ -5975,6 +6306,11 @@
case types::TY_LTO_BC:
CmdArgs.push_back("-c");
break;
+ // We assume we've got an "integrated" assembler in that gcc will produce an
+ // object file itself.
+ case types::TY_Object:
+ CmdArgs.push_back("-c");
+ break;
case types::TY_PP_Asm:
CmdArgs.push_back("-S");
break;
@@ -5993,7 +6329,9 @@
// Hexagon tools start.
void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {}
+ ArgStringList &CmdArgs) const {
+}
+
void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -6001,15 +6339,21 @@
const char *LinkingOutput) const {
claimNoWarnArgs(Args);
- const Driver &D = getToolChain().getDriver();
+ auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
+ const Driver &D = HTC.getDriver();
ArgStringList CmdArgs;
- std::string MarchString = "-march=";
- MarchString += toolchains::HexagonToolChain::GetTargetCPU(Args);
- CmdArgs.push_back(Args.MakeArgString(MarchString));
+ std::string MArchString = "-march=hexagon";
+ CmdArgs.push_back(Args.MakeArgString(MArchString));
RenderExtraToolArgs(JA, CmdArgs);
+ std::string AsName = "hexagon-llvm-mc";
+ std::string MCpuString = "-mcpu=hexagon" +
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+ CmdArgs.push_back("-filetype=obj");
+ CmdArgs.push_back(Args.MakeArgString(MCpuString));
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -6018,8 +6362,10 @@
CmdArgs.push_back("-fsyntax-only");
}
- if (const char *v = toolchains::HexagonToolChain::GetSmallDataThreshold(Args))
- CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v));
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N));
+ }
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
@@ -6033,60 +6379,56 @@
// inputs into '-Wl,' options?
for (const auto &II : Inputs) {
// Don't try to pass LLVM or AST inputs to a generic gcc.
- if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
+ if (types::isLLVMIR(II.getType()))
D.Diag(clang::diag::err_drv_no_linker_llvm_support)
- << getToolChain().getTripleString();
+ << HTC.getTripleString();
else if (II.getType() == types::TY_AST)
D.Diag(clang::diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
+ << HTC.getTripleString();
else if (II.getType() == types::TY_ModuleFile)
D.Diag(diag::err_drv_no_module_support)
- << getToolChain().getTripleString();
+ << HTC.getTripleString();
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
// Don't render as input, we need gcc to do the translations.
- // FIXME: Pranav: What is this ?
+ // FIXME: What is this?
II.getInputArg().render(Args, CmdArgs);
}
- const char *GCCName = "hexagon-as";
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
- // The types are (hopefully) good enough.
}
static void
constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
- const toolchains::HexagonToolChain &ToolChain,
+ const toolchains::HexagonToolChain &HTC,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, ArgStringList &CmdArgs,
const char *LinkingOutput) {
- const Driver &D = ToolChain.getDriver();
+ const Driver &D = HTC.getDriver();
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
- bool hasStaticArg = Args.hasArg(options::OPT_static);
- bool buildingLib = Args.hasArg(options::OPT_shared);
- bool buildPIE = Args.hasArg(options::OPT_pie);
- bool incStdLib = !Args.hasArg(options::OPT_nostdlib);
- bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles);
- bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
- bool useG0 = false;
- bool useShared = buildingLib && !hasStaticArg;
+ bool IsStatic = Args.hasArg(options::OPT_static);
+ bool IsShared = Args.hasArg(options::OPT_shared);
+ bool IsPIE = Args.hasArg(options::OPT_pie);
+ bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
+ bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+ bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+ bool UseG0 = false;
+ bool UseShared = IsShared && !IsStatic;
//----------------------------------------------------------------------------
// Silence warnings for various options
//----------------------------------------------------------------------------
-
Args.ClaimAllArgs(options::OPT_g_Group);
Args.ClaimAllArgs(options::OPT_emit_llvm);
Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
@@ -6096,28 +6438,37 @@
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
- for (const auto &Opt : ToolChain.ExtraOpts)
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ if (Args.hasArg(options::OPT_r))
+ CmdArgs.push_back("-r");
+
+ for (const auto &Opt : HTC.ExtraOpts)
CmdArgs.push_back(Opt.c_str());
- std::string MarchString = toolchains::HexagonToolChain::GetTargetCPU(Args);
- CmdArgs.push_back(Args.MakeArgString("-m" + MarchString));
+ CmdArgs.push_back("-march=hexagon");
+ std::string CpuVer =
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+ std::string MCpuString = "-mcpu=hexagon" + CpuVer;
+ CmdArgs.push_back(Args.MakeArgString(MCpuString));
- if (buildingLib) {
+ if (IsShared) {
CmdArgs.push_back("-shared");
- CmdArgs.push_back("-call_shared"); // should be the default, but doing as
- // hexagon-gcc does
+ // The following should be the default, but doing as hexagon-gcc does.
+ CmdArgs.push_back("-call_shared");
}
- if (hasStaticArg)
+ if (IsStatic)
CmdArgs.push_back("-static");
- if (buildPIE && !buildingLib)
+ if (IsPIE && !IsShared)
CmdArgs.push_back("-pie");
- if (const char *v =
- toolchains::HexagonToolChain::GetSmallDataThreshold(Args)) {
- CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v));
- useG0 = toolchains::HexagonToolChain::UsesG0(v);
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N));
+ UseG0 = G.getValue() == 0;
}
//----------------------------------------------------------------------------
@@ -6126,49 +6477,60 @@
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- const std::string MarchSuffix = "/" + MarchString;
- const std::string G0Suffix = "/G0";
- const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
- const std::string RootDir = ToolChain.GetGnuDir(D.InstalledDir, Args) + "/";
- const std::string StartFilesDir =
- RootDir + "hexagon/lib" + (useG0 ? MarchG0Suffix : MarchSuffix);
-
//----------------------------------------------------------------------------
// moslib
//----------------------------------------------------------------------------
- std::vector<std::string> oslibs;
- bool hasStandalone = false;
+ std::vector<std::string> OsLibs;
+ bool HasStandalone = false;
for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
A->claim();
- oslibs.emplace_back(A->getValue());
- hasStandalone = hasStandalone || (oslibs.back() == "standalone");
+ OsLibs.emplace_back(A->getValue());
+ HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
}
- if (oslibs.empty()) {
- oslibs.push_back("standalone");
- hasStandalone = true;
+ if (OsLibs.empty()) {
+ OsLibs.push_back("standalone");
+ HasStandalone = true;
}
//----------------------------------------------------------------------------
// Start Files
//----------------------------------------------------------------------------
- if (incStdLib && incStartFiles) {
+ const std::string MCpuSuffix = "/" + CpuVer;
+ const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
+ const std::string RootDir =
+ HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
+ const std::string StartSubDir =
+ "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
- if (!buildingLib) {
- if (hasStandalone) {
- CmdArgs.push_back(
- Args.MakeArgString(StartFilesDir + "/crt0_standalone.o"));
+ auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
+ const char *Name) -> std::string {
+ std::string RelName = SubDir + Name;
+ std::string P = HTC.GetFilePath(RelName.c_str());
+ if (llvm::sys::fs::exists(P))
+ return P;
+ return RootDir + RelName;
+ };
+
+ if (IncStdLib && IncStartFiles) {
+ if (!IsShared) {
+ if (HasStandalone) {
+ std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0SA));
}
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o"));
+ std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0));
}
- std::string initObj = useShared ? "/initS.o" : "/init.o";
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj));
+ std::string Init = UseShared
+ ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
+ : Find(RootDir, StartSubDir, "/init.o");
+ CmdArgs.push_back(Args.MakeArgString(Init));
}
//----------------------------------------------------------------------------
// Library Search Paths
//----------------------------------------------------------------------------
- const ToolChain::path_list &LibPaths = ToolChain.getFilePaths();
+ const ToolChain::path_list &LibPaths = HTC.getFilePaths();
for (const auto &LibPath : LibPaths)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
@@ -6179,21 +6541,21 @@
{options::OPT_T_Group, options::OPT_e, options::OPT_s,
options::OPT_t, options::OPT_u_Group});
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+ AddLinkerInputs(HTC, Inputs, Args, CmdArgs);
//----------------------------------------------------------------------------
// Libraries
//----------------------------------------------------------------------------
- if (incStdLib && incDefLibs) {
+ if (IncStdLib && IncDefLibs) {
if (D.CCCIsCXX()) {
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
CmdArgs.push_back("--start-group");
- if (!buildingLib) {
- for (const std::string &Lib : oslibs)
+ if (!IsShared) {
+ for (const std::string &Lib : OsLibs)
CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
CmdArgs.push_back("-lc");
}
@@ -6205,9 +6567,11 @@
//----------------------------------------------------------------------------
// End files
//----------------------------------------------------------------------------
- if (incStdLib && incStartFiles) {
- std::string finiObj = useShared ? "/finiS.o" : "/fini.o";
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj));
+ if (IncStdLib && IncStartFiles) {
+ std::string Fini = UseShared
+ ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
+ : Find(RootDir, StartSubDir, "/fini.o");
+ CmdArgs.push_back(Args.MakeArgString(Fini));
}
}
@@ -6216,15 +6580,13 @@
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
-
- const toolchains::HexagonToolChain &ToolChain =
- static_cast<const toolchains::HexagonToolChain &>(getToolChain());
+ auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
ArgStringList CmdArgs;
- constructHexagonLinkArgs(C, JA, ToolChain, Output, Inputs, Args, CmdArgs,
+ constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
LinkingOutput);
- std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
+ std::string Linker = HTC.GetProgramPath("hexagon-link");
C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
@@ -6238,10 +6600,6 @@
std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("gnu");
- CmdArgs.push_back("-target");
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -6250,13 +6608,47 @@
}
// AMDGPU tools end.
+wasm::Linker::Linker(const ToolChain &TC)
+ : GnuTool("wasm::Linker", "lld", TC) {}
+
+bool wasm::Linker::isLinkJob() const {
+ return true;
+}
+
+bool wasm::Linker::hasIntegratedCPP() const {
+ return false;
+}
+
+void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const char *Linker = Args.MakeArgString(getToolChain().GetLinkerPath());
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("ld");
+
+ // Enable garbage collection of unused input sections by default, since code
+ // size is of particular importance. This is significantly facilitated by
+ // the enabling of -ffunction-sections and -fdata-sections in
+ // Clang::ConstructJob.
+ if (areOptimizationsEnabled(Args))
+ CmdArgs.push_back("--gc-sections");
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
+}
+
const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
std::string MArch;
if (!Arch.empty())
MArch = Arch;
else
MArch = Triple.getArchName();
- MArch = StringRef(MArch).lower();
+ MArch = StringRef(MArch).split("+").first.lower();
// Handle -march=native.
if (MArch == "native") {
@@ -6295,7 +6687,7 @@
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
if (!CPU.empty()) {
- std::string MCPU = StringRef(CPU).lower();
+ std::string MCPU = StringRef(CPU).split("+").first.lower();
// Handle -mcpu=native.
if (MCPU == "native")
return llvm::sys::getHostCPUName();
@@ -6533,16 +6925,13 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list &Paths = ToolChain.getFilePaths();
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs,
{options::OPT_T_Group, options::OPT_e, options::OPT_s,
options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
@@ -6552,16 +6941,14 @@
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX())
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lcompiler_rt");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles))
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
@@ -6585,11 +6972,11 @@
SourceAction = SourceAction->getInputs()[0];
}
- // If -fno_integrated_as is used add -Q to the darwin assember driver to make
+ // If -fno-integrated-as is used add -Q to the darwin assember driver to make
// sure it runs its system assembler not clang's integrated assembler.
// Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as.
// FIXME: at run-time detect assembler capabilities or rely on version
- // information forwarded by -target-assembler-version (future)
+ // information forwarded by -target-assembler-version.
if (Args.hasArg(options::OPT_fno_integrated_as)) {
const llvm::Triple &T(getToolChain().getTriple());
if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7)))
@@ -6908,8 +7295,7 @@
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles))
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs);
// SafeStack requires its own runtime libraries
@@ -6941,12 +7327,11 @@
InputFileList.push_back(II.getFilename());
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs))
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
- if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (isObjCRuntimeLinked(Args) &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
// We use arclite library for both ARC and subscripting support.
getMachOToolChain().AddLinkARCArgs(Args, CmdArgs);
@@ -6967,8 +7352,7 @@
getMachOToolChain().addProfileRTLibs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (getToolChain().getDriver().CCCIsCXX())
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
@@ -6978,8 +7362,7 @@
getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
// endfile_spec is empty.
}
@@ -6990,8 +7373,7 @@
for (const Arg *A : Args.filtered(options::OPT_iframework))
CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue()));
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
if (A->getValue() == StringRef("Accelerate")) {
CmdArgs.push_back("-framework");
@@ -7102,8 +7484,7 @@
// Demangle C++ names in errors
CmdArgs.push_back("-C");
- if ((!Args.hasArg(options::OPT_nostdlib)) &&
- (!Args.hasArg(options::OPT_shared))) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
CmdArgs.push_back("-e");
CmdArgs.push_back("_start");
}
@@ -7129,8 +7510,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
@@ -7142,17 +7522,14 @@
Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
}
- const ToolChain::path_list &Paths = getToolChain().getFilePaths();
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ getToolChain().AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_e, options::OPT_r});
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (getToolChain().getDriver().CCCIsCXX())
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lgcc_s");
@@ -7163,8 +7540,7 @@
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
@@ -7268,8 +7644,7 @@
else if (getToolChain().getArch() == llvm::Triple::mips64el)
CmdArgs.push_back("-EL");
- if ((!Args.hasArg(options::OPT_nostdlib)) &&
- (!Args.hasArg(options::OPT_shared))) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
CmdArgs.push_back("-e");
CmdArgs.push_back("__start");
}
@@ -7299,8 +7674,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back(
@@ -7328,8 +7702,7 @@
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
@@ -7359,8 +7732,7 @@
CmdArgs.push_back("-lgcc");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
@@ -7401,8 +7773,7 @@
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
- if ((!Args.hasArg(options::OPT_nostdlib)) &&
- (!Args.hasArg(options::OPT_shared))) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
CmdArgs.push_back("-e");
CmdArgs.push_back("__start");
}
@@ -7429,8 +7800,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back(
@@ -7451,8 +7821,7 @@
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
@@ -7492,8 +7861,7 @@
CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch));
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
@@ -7545,6 +7913,12 @@
else
CmdArgs.push_back("-EL");
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-G" + v));
+ A->claim();
+ }
+
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
@@ -7654,6 +8028,17 @@
CmdArgs.push_back("elf32ppc_fbsd");
}
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ if (ToolChain.getArch() == llvm::Triple::mips ||
+ ToolChain.getArch() == llvm::Triple::mipsel ||
+ ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mips64el) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-G" + v));
+ A->claim();
+ }
+ }
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -7661,8 +8046,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
@@ -7689,9 +8073,7 @@
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list &Paths = ToolChain.getFilePaths();
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -7705,8 +8087,7 @@
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
addOpenMPRuntime(CmdArgs, ToolChain, Args);
if (D.CCCIsCXX()) {
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
@@ -7762,8 +8143,7 @@
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || IsPIE)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
@@ -7977,8 +8357,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
@@ -8026,8 +8405,7 @@
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
@@ -8054,8 +8432,7 @@
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
@@ -8354,20 +8731,17 @@
return "/lib/ld-linux.so.3";
} else if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el) {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, ToolChain.getTriple(), CPUName, ABIName);
- bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple());
-
- StringRef LibDir = llvm::StringSwitch<llvm::StringRef>(ABIName)
- .Case("o32", "/lib")
- .Case("n32", "/lib32")
- .Case("n64", "/lib64")
- .Default("/lib");
+ std::string LibDir =
+ "/lib" + mips::getMipsABILibSuffix(Args, ToolChain.getTriple());
StringRef LibName;
+ bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple());
if (mips::isUCLibc(Args))
LibName = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
- else
+ else if (!ToolChain.getTriple().hasEnvironment()) {
+ bool LE = (ToolChain.getTriple().getArch() == llvm::Triple::mipsel) ||
+ (ToolChain.getTriple().getArch() == llvm::Triple::mips64el);
+ LibName = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
+ } else
LibName = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
return (LibDir + "/" + LibName).str();
@@ -8479,6 +8853,9 @@
const bool IsPIE =
!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) &&
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
+ const bool HasCRTBeginEndFiles =
+ ToolChain.getTriple().hasEnvironment() ||
+ (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies);
ArgStringList CmdArgs;
@@ -8490,6 +8867,14 @@
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ if (llvm::sys::path::filename(Exec) == "lld") {
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("old-gnu");
+ CmdArgs.push_back("-target");
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
+ }
+
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
@@ -8537,8 +8922,7 @@
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!isAndroid) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
@@ -8564,7 +8948,9 @@
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
else
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+
+ if (HasCRTBeginEndFiles)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
// Add crtfastmath.o if available and fast math is enabled.
ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
@@ -8573,10 +8959,7 @@
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
- const ToolChain::path_list &Paths = ToolChain.getFilePaths();
-
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
if (D.isUsingLTO())
AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin);
@@ -8589,8 +8972,8 @@
// The profile runtime also needs access to system libraries.
getToolChain().addProfileRTLibs(Args, CmdArgs);
- if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (OnlyLibstdcxxStatic)
@@ -8663,14 +9046,14 @@
else
crtend = isAndroid ? "crtend_android.o" : "crtend.o";
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ if (HasCRTBeginEndFiles)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
if (!isAndroid)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
}
- C.addCommand(llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(),
- CmdArgs, Inputs));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// NaCl ARM assembly (inline or standalone) can be written with a set of macros
@@ -8684,7 +9067,7 @@
const char *LinkingOutput) const {
const toolchains::NaClToolChain &ToolChain =
static_cast<const toolchains::NaClToolChain &>(getToolChain());
- InputInfo NaClMacros(ToolChain.GetNaClArmMacrosPath(), types::TY_PP_Asm,
+ InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
"nacl-arm-macros.s");
InputInfoList NewInputs;
NewInputs.push_back(NaClMacros);
@@ -8756,8 +9139,7 @@
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
@@ -8775,18 +9157,15 @@
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
- const ToolChain::path_list &Paths = ToolChain.getFilePaths();
-
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
bool OnlyLibstdcxxStatic =
Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic;
if (OnlyLibstdcxxStatic)
@@ -8845,8 +9224,8 @@
}
}
- C.addCommand(llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(),
- CmdArgs, Inputs));
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
@@ -8884,8 +9263,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
CmdArgs.push_back(
@@ -8900,16 +9278,14 @@
getToolChain().addProfileRTLibs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
@@ -8959,7 +9335,6 @@
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
- bool UseGCC47 = llvm::sys::fs::exists("/usr/lib/gcc47");
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
@@ -8976,7 +9351,8 @@
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/usr/libexec/ld-elf.so.2");
}
- CmdArgs.push_back("--hash-style=both");
+ CmdArgs.push_back("--hash-style=gnu");
+ CmdArgs.push_back("--enable-new-dtags");
}
// When building 32-bit code on DragonFly/pc64, we have to explicitly
@@ -8993,8 +9369,7 @@
assert(Output.isNothing() && "Invalid output.");
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back(
@@ -9022,23 +9397,12 @@
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
- // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of
- // rpaths
- if (UseGCC47)
- CmdArgs.push_back("-L/usr/lib/gcc47");
- else
- CmdArgs.push_back("-L/usr/lib/gcc44");
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ CmdArgs.push_back("-L/usr/lib/gcc50");
if (!Args.hasArg(options::OPT_static)) {
- if (UseGCC47) {
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back("/usr/lib/gcc47");
- } else {
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back("/usr/lib/gcc44");
- }
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("/usr/lib/gcc50");
}
if (D.CCCIsCXX()) {
@@ -9053,34 +9417,25 @@
CmdArgs.push_back("-lc");
}
- if (UseGCC47) {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc)) {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_static_libgcc)) {
CmdArgs.push_back("-lgcc");
CmdArgs.push_back("-lgcc_eh");
- } else {
- if (Args.hasArg(options::OPT_shared_libgcc)) {
+ } else {
+ if (Args.hasArg(options::OPT_shared_libgcc)) {
CmdArgs.push_back("-lgcc_pic");
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-lgcc");
- } else {
+ } else {
CmdArgs.push_back("-lgcc");
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lgcc_pic");
CmdArgs.push_back("--no-as-needed");
- }
- }
- } else {
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-lgcc_pic");
- } else {
- CmdArgs.push_back("-lgcc");
}
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
@@ -9129,8 +9484,8 @@
CmdArgs.push_back(
Args.MakeArgString(std::string("-out:") + Output.getFilename()));
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles) && !C.getDriver().IsCLMode())
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
+ !C.getDriver().IsCLMode())
CmdArgs.push_back("-defaultlib:libcmt");
if (!llvm::sys::Process::GetEnv("LIB")) {
@@ -9254,6 +9609,8 @@
A.renderAsInput(Args, CmdArgs);
}
+ TC.addProfileRTLibs(Args, CmdArgs);
+
// We need to special case some linker paths. In the case of lld, we need to
// translate 'lld' into 'lld-link', and in the case of the regular msvc
// linker, we need to use a special search algorithm.
@@ -9472,6 +9829,8 @@
if (LinkerName.equals_lower("lld")) {
CmdArgs.push_back("-flavor");
CmdArgs.push_back("gnu");
+ } else if (!LinkerName.equals_lower("ld")) {
+ D.Diag(diag::err_drv_unsupported_linker) << LinkerName;
}
if (!D.SysRoot.empty())
@@ -9525,8 +9884,7 @@
Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o")));
} else {
@@ -9541,18 +9899,15 @@
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list Paths = TC.getFilePaths();
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
-
+ TC.AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(TC, Inputs, Args, CmdArgs);
// TODO: Add ASan stuff here
// TODO: Add profile stuff here
- if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (OnlyLibstdcxxStatic)
@@ -9790,8 +10145,7 @@
CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
: "-Bdynamic");
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
CmdArgs.push_back("--entry");
CmdArgs.push_back(Args.MakeArgString(EntryPoint));
}
@@ -9813,8 +10167,7 @@
CmdArgs.push_back(Args.MakeArgString(ImpLib));
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
const std::string CRTPath(D.SysRoot + "/usr/lib/");
const char *CRTBegin;
@@ -9824,11 +10177,7 @@
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
-
- const auto &Paths = TC.getFilePaths();
- for (const auto &Path : Paths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
-
+ TC.AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(TC, Inputs, Args, CmdArgs);
if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
@@ -9876,23 +10225,28 @@
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
-
ArgStringList CmdArgs;
-
assert(Inputs.size() == 1);
const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX);
- assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm.
+ assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX ||
+ II.getType() == types::TY_PP_CXX);
- CmdArgs.push_back("-DMYRIAD2");
+ if (JA.getKind() == Action::PreprocessJobClass) {
+ Args.ClaimAllArgs();
+ CmdArgs.push_back("-E");
+ } else {
+ assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm.
+ CmdArgs.push_back("-S");
+ CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified.
+ }
CmdArgs.push_back("-mcpu=myriad2");
- CmdArgs.push_back("-S");
+ CmdArgs.push_back("-DMYRIAD2");
// Append all -I, -iquote, -isystem paths, defines/undefines,
// 'f' flags, optimize flags, and warning options.
// These are spelled the same way in clang and moviCompile.
Args.AddAllArgs(CmdArgs, {options::OPT_I_Group, options::OPT_clang_i_Group,
- options::OPT_D, options::OPT_U,
+ options::OPT_std_EQ, options::OPT_D, options::OPT_U,
options::OPT_f_Group, options::OPT_f_clang_Group,
options::OPT_g_Group, options::OPT_M_Group,
options::OPT_O_Group, options::OPT_W_Group});
@@ -9912,8 +10266,6 @@
}
}
- CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified.
-
CmdArgs.push_back(II.getFilename());
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -9966,13 +10318,10 @@
static_cast<const toolchains::MyriadToolChain &>(getToolChain());
const llvm::Triple &T = TC.getTriple();
ArgStringList CmdArgs;
- bool UseStartfiles = !Args.hasArg(options::OPT_nostartfiles);
- bool UseDefaultLibs = !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs);
-
- std::string StartFilesDir, BuiltinLibDir;
- TC.getCompilerSupportDir(StartFilesDir);
- TC.getBuiltinLibDir(BuiltinLibDir);
+ bool UseStartfiles =
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
+ bool UseDefaultLibs =
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs);
if (T.getArch() == llvm::Triple::sparc)
CmdArgs.push_back("-EB");
@@ -9997,19 +10346,15 @@
if (UseStartfiles) {
// If you want startfiles, it means you want the builtin crti and crtbegin,
// but not crt0. Myriad link commands provide their own crt0.o as needed.
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crti.o"));
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtbegin.o"));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
}
Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_e, options::OPT_s, options::OPT_t,
options::OPT_Z_Flag, options::OPT_r});
- // The linker doesn't use these builtin paths unless directed to,
- // because it was not compiled for support with sysroots, nor does
- // it have a default of little-endian with FPU.
- CmdArgs.push_back(Args.MakeArgString("-L" + BuiltinLibDir));
- CmdArgs.push_back(Args.MakeArgString("-L" + StartFilesDir));
+ TC.AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
@@ -10029,8 +10374,8 @@
CmdArgs.push_back("-lgcc");
}
if (UseStartfiles) {
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtend.o"));
- CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtn.o"));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o")));
}
std::string Exec =
@@ -10062,21 +10407,6 @@
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
-static void AddPS4ProfileRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
- false) ||
- Args.hasArg(options::OPT_fprofile_generate) ||
- Args.hasArg(options::OPT_fprofile_instr_generate) ||
- Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage)))
- return;
-
- assert(TC.getTriple().isPS4CPU() &&
- "Profiling libraries are only implemented for the PS4 CPU");
- CmdArgs.push_back("-lclang_rt.profile-x86_64");
-}
-
static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
if (SanArgs.needsUbsanRt()) {
@@ -10141,8 +10471,6 @@
CmdArgs.push_back("-lpthread");
}
- AddPS4ProfileRT(ToolChain, Args, CmdArgs);
-
const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld"));
C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
@@ -10196,8 +10524,7 @@
AddPS4SanitizerArgs(ToolChain, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
@@ -10224,12 +10551,7 @@
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
-
- const ToolChain::path_list Paths = ToolChain.getFilePaths();
- for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
- i != e; ++i)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
-
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -10241,8 +10563,7 @@
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
// For PS4, we always want to pass libm, libstdc++ and libkernel
// libraries for both C and C++ compilations.
CmdArgs.push_back("-lkernel");
@@ -10313,8 +10634,7 @@
}
}
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
@@ -10322,11 +10642,9 @@
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- AddPS4ProfileRT(ToolChain, Args, CmdArgs);
-
const char *Exec =
#ifdef LLVM_ON_WIN32
- Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld.gold.exe"));
+ Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld.gold"));
#else
Args.MakeArgString(ToolChain.GetProgramPath("ps4-ld"));
#endif
@@ -10362,3 +10680,81 @@
else
ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
}
+
+void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ assert(TC.getArch() == llvm::Triple::nvptx ||
+ TC.getArch() == llvm::Triple::nvptx64);
+
+ std::vector<std::string> gpu_archs =
+ Args.getAllArgValues(options::OPT_march_EQ);
+ assert(gpu_archs.size() == 1 && "Exactly one GPU Arch required for ptxas.");
+ const std::string& gpu_arch = gpu_archs[0];
+
+
+ ArgStringList CmdArgs;
+ CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32");
+
+ // Clang's default optimization level is -O0, but ptxas's default is -O3.
+ CmdArgs.push_back(Args.MakeArgString(
+ llvm::Twine("-O") +
+ Args.getLastArgValue(options::OPT_O_Group, "0").data()));
+
+ // Don't bother passing -g to ptxas: It's enabled by default at -O0, and
+ // not supported at other optimization levels.
+
+ CmdArgs.push_back("--gpu-name");
+ CmdArgs.push_back(Args.MakeArgString(gpu_arch));
+ CmdArgs.push_back("--output-file");
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ for (const auto& II : Inputs)
+ CmdArgs.push_back(Args.MakeArgString(II.getFilename()));
+
+ for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
+ CmdArgs.push_back(Args.MakeArgString(A));
+
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath("ptxas"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// All inputs to this linker must be from CudaDeviceActions, as we need to look
+// at the Inputs' Actions in order to figure out which GPU architecture they
+// correspond to.
+void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ assert(TC.getArch() == llvm::Triple::nvptx ||
+ TC.getArch() == llvm::Triple::nvptx64);
+
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("--cuda");
+ CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32");
+ CmdArgs.push_back(Args.MakeArgString("--create"));
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+
+ for (const auto& II : Inputs) {
+ auto* A = cast<const CudaDeviceAction>(II.getAction());
+ // We need to pass an Arch of the form "sm_XX" for cubin files and
+ // "compute_XX" for ptx.
+ const char *Arch = (II.getType() == types::TY_PP_Asm)
+ ? A->getComputeArchName()
+ : A->getGpuArchName();
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") +
+ Arch + ",file=" + II.getFilename()));
+ }
+
+ for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
+ CmdArgs.push_back(Args.MakeArgString(A));
+
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 83f6db6..69c0465 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -57,7 +57,8 @@
const Driver &D, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const InputInfo &Output,
- const InputInfoList &Inputs) const;
+ const InputInfoList &Inputs,
+ const ToolChain *AuxToolChain) const;
void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
@@ -81,6 +82,8 @@
llvm::opt::ArgStringList &CmdArgs) const;
void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
@@ -148,6 +151,10 @@
Common(const char *Name, const char *ShortName, const ToolChain &TC)
: GnuTool(Name, ShortName, TC) {}
+ // A gcc tool has an "integrated" assembler that it will call to produce an
+ // object. Let it use that assembler so that we don't have to deal with
+ // assembly syntax incompatibilities.
+ bool hasIntegratedAssembler() const override { return true; }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
@@ -233,7 +240,7 @@
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
- Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "lld", TC) {}
+ Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {}
bool isLinkJob() const override { return true; }
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
@@ -244,6 +251,21 @@
} // end namespace amdgpu
+namespace wasm {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ explicit Linker(const ToolChain &TC);
+ bool isLinkJob() const override;
+ bool hasIntegratedCPP() const override;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace wasm
+
namespace arm {
std::string getARMTargetCPU(StringRef CPU, StringRef Arch,
const llvm::Triple &Triple);
@@ -270,6 +292,8 @@
void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, StringRef &CPUName,
StringRef &ABIName);
+std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
bool isUCLibc(const llvm::opt::ArgList &Args);
bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
@@ -553,9 +577,9 @@
const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
- Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {}
+ Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -739,6 +763,16 @@
FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args);
} // end namespace arm
+namespace ppc {
+enum class FloatABI {
+ Invalid,
+ Soft,
+ Hard,
+};
+
+FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+} // end namespace ppc
+
namespace XCore {
// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and
// Compile.
@@ -869,6 +903,41 @@
};
} // end namespace PS4cpu
+namespace NVPTX {
+
+// Run ptxas, the NVPTX assembler.
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+ public:
+ Assembler(const ToolChain &TC)
+ : Tool("NVPTX::Assembler", "ptxas", TC, RF_Full, llvm::sys::WEM_UTF8,
+ "--options-file") {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX
+// assembly into a single output file.
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+ public:
+ Linker(const ToolChain &TC)
+ : Tool("NVPTX::Linker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8,
+ "--options-file") {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace NVPTX
+
} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 2085b01..3b3b67f 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -128,6 +128,19 @@
}
}
+bool types::isLLVMIR(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_LLVM_IR:
+ case TY_LLVM_BC:
+ case TY_LTO_IR:
+ case TY_LTO_BC:
+ return true;
+ }
+}
+
bool types::isCuda(ID Id) {
switch (Id) {
default:
@@ -219,8 +232,7 @@
P.push_back(phases::Compile);
P.push_back(phases::Backend);
}
- if (Id != TY_CUDA_DEVICE)
- P.push_back(phases::Assemble);
+ P.push_back(phases::Assemble);
}
}
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index 9f71168..482c0f6 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1077,6 +1077,9 @@
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
return false;
+
+ case CK_BooleanToSignedIntegral:
+ llvm_unreachable("OpenCL-specific cast in Objective-C?");
}
}
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 72157bd..b820f53 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -38,6 +38,12 @@
return End->TotalLength - Tok.TotalLength + 1;
}
+static unsigned getLengthToNextOperator(const FormatToken &Tok) {
+ if (!Tok.NextOperator)
+ return 0;
+ return Tok.NextOperator->TotalLength - Tok.TotalLength;
+}
+
// Returns \c true if \c Tok is the "." or "->" of a call and starts the next
// segment of a builder type call.
static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
@@ -125,10 +131,10 @@
// Don't break after very short return types (e.g. "void") as that is often
// unexpected.
- if (Current.is(TT_FunctionDeclarationName) &&
- Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_None &&
- State.Column < 6)
- return false;
+ if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) {
+ if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None)
+ return false;
+ }
return !State.Stack.back().NoLineBreak;
}
@@ -144,6 +150,12 @@
if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
return true;
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
+ (Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
+ // FIXME: This is a temporary workaround for the case where clang-format
+ // sets BreakBeforeParameter to avoid bin packing and this creates a
+ // completely unnecessary line break after a template type that isn't
+ // line-wrapped.
+ (Previous.NestingLevel == 1 || Style.BinPackParameters)) ||
(Style.BreakBeforeTernaryOperators && Current.is(TT_ConditionalExpr) &&
Previous.isNot(tok::question)) ||
(!Style.BreakBeforeTernaryOperators &&
@@ -152,7 +164,8 @@
!Current.isOneOf(tok::r_paren, tok::r_brace))
return true;
if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) ||
- Previous.is(TT_ArrayInitializerLSquare)) &&
+ (Previous.is(TT_ArrayInitializerLSquare) &&
+ Previous.ParameterCount > 1)) &&
Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column - 1 >
getColumnLimit(State))
@@ -169,7 +182,13 @@
return true;
unsigned NewLineColumn = getNewLineColumn(State);
- if (State.Column < NewLineColumn)
+ if (Current.isMemberAccess() && Style.ColumnLimit != 0 &&
+ State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit &&
+ (State.Column > NewLineColumn ||
+ Current.NestingLevel < State.StartOfLineLevel))
+ return true;
+
+ if (State.Column <= NewLineColumn)
return false;
if (Style.AlwaysBreakBeforeMultilineStrings &&
@@ -245,8 +264,10 @@
Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment))
return true;
- if (Current.is(tok::lessless) && Previous.is(tok::identifier) &&
- Previous.TokenText == "endl")
+ if (Current.is(tok::lessless) &&
+ ((Previous.is(tok::identifier) && Previous.TokenText == "endl") ||
+ (Previous.Tok.isLiteral() && (Previous.TokenText.endswith("\\n\"") ||
+ Previous.TokenText == "\'\\n\'"))))
return true;
return false;
@@ -315,16 +336,16 @@
if (Current.is(TT_SelectorName) &&
!State.Stack.back().ObjCSelectorNameFound) {
+ unsigned MinIndent =
+ std::max(State.FirstIndent + Style.ContinuationIndentWidth,
+ State.Stack.back().Indent);
+ unsigned FirstColonPos = State.Column + Spaces + Current.ColumnWidth;
if (Current.LongestObjCSelectorName == 0)
State.Stack.back().AlignColons = false;
- else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
- State.Column + Spaces + Current.ColumnWidth)
- State.Stack.back().ColonPos =
- std::max(State.FirstIndent + Style.ContinuationIndentWidth,
- State.Stack.back().Indent) +
- Current.LongestObjCSelectorName;
+ else if (MinIndent + Current.LongestObjCSelectorName > FirstColonPos)
+ State.Stack.back().ColonPos = MinIndent + Current.LongestObjCSelectorName;
else
- State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
+ State.Stack.back().ColonPos = FirstColonPos;
}
// In "AlwaysBreak" mode, enforce wrapping directly after the parenthesis by
@@ -369,14 +390,15 @@
State.Stack.back().LastSpace = State.Column;
State.Stack.back().NestedBlockIndent = State.Column;
} else if (!Current.isOneOf(tok::comment, tok::caret) &&
- (Previous.is(tok::comma) ||
+ ((Previous.is(tok::comma) &&
+ !Previous.is(TT_OverloadedOperator)) ||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
} else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
TT_CtorInitializerColon)) &&
((Previous.getPrecedence() != prec::Assignment &&
(Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
- !Previous.LastOperator)) ||
+ Previous.NextOperator)) ||
Current.StartsBinaryExpression)) {
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
@@ -691,7 +713,7 @@
std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
- Current.LastOperator ? 0 : State.Column;
+ !Current.NextOperator ? 0 : State.Column;
if (Current.is(TT_SelectorName)) {
State.Stack.back().ObjCSelectorNameFound = true;
if (Style.IndentWrappedFunctionNames) {
@@ -727,7 +749,7 @@
// }, a, b, c);
if (Current.isNot(tok::comment) && Previous &&
Previous->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) &&
- State.Stack.size() > 1) {
+ !Previous->is(TT_DictLiteral) && State.Stack.size() > 1) {
if (State.Stack[State.Stack.size() - 2].NestedBlockInlined && Newline)
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i)
State.Stack[i].NoLineBreak = true;
@@ -846,7 +868,7 @@
(!SkipFirstExtraIndent && *I > prec::Assignment &&
!Current.isTrailingComment()))
NewParenState.Indent += Style.ContinuationIndentWidth;
- if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
+ if ((Previous && !Previous->opensScope()) || *I != prec::Comma)
NewParenState.BreakBeforeParameter = false;
State.Stack.push_back(NewParenState);
SkipFirstExtraIndent = false;
@@ -892,8 +914,12 @@
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
const FormatToken *NextNoComment = Current.getNextNonComment();
+ bool EndsInComma = Current.MatchingParen &&
+ Current.MatchingParen->Previous &&
+ Current.MatchingParen->Previous->is(tok::comma);
AvoidBinPacking =
- Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) ||
+ (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) ||
+ Current.is(TT_DictLiteral) ||
Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||
(NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
if (Current.ParameterCount > 1)
@@ -1075,7 +1101,8 @@
return 0;
}
} else if (Current.is(TT_BlockComment) && Current.isTrailingComment()) {
- if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ if (!Style.ReflowComments ||
+ CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
@@ -1083,7 +1110,8 @@
} else if (Current.is(TT_LineComment) &&
(Current.Previous == nullptr ||
Current.Previous->isNot(TT_ImplicitStringLiteral))) {
- if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ if (!Style.ReflowComments ||
+ CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableLineComment(Current, State.Line->Level,
StartColumn, /*InPPDirective=*/false,
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index c1a3019..2689368 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -47,6 +47,7 @@
IO.enumCase(Value, "Java", FormatStyle::LK_Java);
IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
+ IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
}
};
@@ -105,6 +106,18 @@
};
template <>
+struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
+ static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::RTBS_None);
+ IO.enumCase(Value, "All", FormatStyle::RTBS_All);
+ IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
+ IO.enumCase(Value, "TopLevelDefinitions",
+ FormatStyle::RTBS_TopLevelDefinitions);
+ IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
+ }
+};
+
+template <>
struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
static void
enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
@@ -233,6 +246,21 @@
Style.AllowShortLoopsOnASingleLine);
IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
Style.AlwaysBreakAfterDefinitionReturnType);
+ IO.mapOptional("AlwaysBreakAfterReturnType",
+ Style.AlwaysBreakAfterReturnType);
+ // If AlwaysBreakAfterDefinitionReturnType was specified but
+ // AlwaysBreakAfterReturnType was not, initialize the latter from the
+ // former for backwards compatibility.
+ if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
+ Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
+ if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
+ else if (Style.AlwaysBreakAfterDefinitionReturnType ==
+ FormatStyle::DRTBS_TopLevel)
+ Style.AlwaysBreakAfterReturnType =
+ FormatStyle::RTBS_TopLevelDefinitions;
+ }
+
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
Style.AlwaysBreakBeforeMultilineStrings);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
@@ -285,6 +313,8 @@
IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
Style.PenaltyReturnTypeOnItsOwnLine);
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
+ IO.mapOptional("ReflowComments", Style.ReflowComments);
+ IO.mapOptional("SortIncludes", Style.SortIncludes);
IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
IO.mapOptional("SpaceBeforeAssignmentOperators",
Style.SpaceBeforeAssignmentOperators);
@@ -394,7 +424,6 @@
Expanded.BraceWrapping.AfterClass = true;
Expanded.BraceWrapping.AfterFunction = true;
Expanded.BraceWrapping.AfterNamespace = true;
- Expanded.BraceWrapping.BeforeElse = true;
break;
case FormatStyle::BS_Mozilla:
Expanded.BraceWrapping.AfterClass = true;
@@ -425,7 +454,6 @@
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
- Expanded.BraceWrapping.BeforeElse = true;
break;
default:
break;
@@ -449,6 +477,7 @@
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
+ LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
@@ -489,6 +518,7 @@
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
+ LLVMStyle.ReflowComments = true;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false;
LLVMStyle.SpaceInEmptyParentheses = false;
@@ -507,6 +537,7 @@
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
LLVMStyle.DisableFormat = false;
+ LLVMStyle.SortIncludes = true;
return LLVMStyle;
}
@@ -548,9 +579,11 @@
GoogleStyle.SpacesBeforeTrailingComments = 1;
} else if (Language == FormatStyle::LK_JavaScript) {
GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+ GoogleStyle.AlignOperands = false;
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeTernaryOperators = false;
+ GoogleStyle.CommentPragmas = "@(export|visibility) {";
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.SpacesInContainerLiterals = false;
} else if (Language == FormatStyle::LK_Proto) {
@@ -576,6 +609,7 @@
ChromiumStyle.BinPackParameters = false;
ChromiumStyle.DerivePointerAlignment = false;
}
+ ChromiumStyle.SortIncludes = false;
return ChromiumStyle;
}
@@ -583,6 +617,8 @@
FormatStyle MozillaStyle = getLLVMStyle();
MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ MozillaStyle.AlwaysBreakAfterReturnType =
+ FormatStyle::RTBS_TopLevelDefinitions;
MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
FormatStyle::DRTBS_TopLevel;
MozillaStyle.AlwaysBreakTemplateDeclarations = true;
@@ -622,6 +658,7 @@
FormatStyle getGNUStyle() {
FormatStyle Style = getLLVMStyle();
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Style.BreakBeforeTernaryOperators = true;
@@ -635,6 +672,7 @@
FormatStyle getNoStyle() {
FormatStyle NoStyle = getLLVMStyle();
NoStyle.DisableFormat = true;
+ NoStyle.SortIncludes = false;
return NoStyle;
}
@@ -1201,6 +1239,8 @@
FormatTok->Type = TT_ImplicitStringLiteral;
break;
}
+ if (FormatTok->Type == TT_ImplicitStringLiteral)
+ break;
}
if (FormatTok->is(TT_ImplicitStringLiteral))
@@ -1239,7 +1279,13 @@
FormatTok->Tok.setIdentifierInfo(&Info);
FormatTok->Tok.setKind(Info.getTokenID());
if (Style.Language == FormatStyle::LK_Java &&
- FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete)) {
+ FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete,
+ tok::kw_operator)) {
+ FormatTok->Tok.setKind(tok::identifier);
+ FormatTok->Tok.setIdentifierInfo(nullptr);
+ } else if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->isOneOf(tok::kw_struct, tok::kw_union,
+ tok::kw_operator)) {
FormatTok->Tok.setKind(tok::identifier);
FormatTok->Tok.setIdentifierInfo(nullptr);
}
@@ -1677,7 +1723,7 @@
StringRef Filename;
StringRef Text;
unsigned Offset;
- unsigned Category;
+ int Category;
};
} // end anonymous namespace
@@ -1699,7 +1745,7 @@
static void sortIncludes(const FormatStyle &Style,
const SmallVectorImpl<IncludeDirective> &Includes,
ArrayRef<tooling::Range> Ranges, StringRef FileName,
- tooling::Replacements &Replaces) {
+ tooling::Replacements &Replaces, unsigned *Cursor) {
if (!affectsRange(Ranges, Includes.front().Offset,
Includes.back().Offset + Includes.back().Text.size()))
return;
@@ -1723,10 +1769,21 @@
if (!OutOfOrder)
return;
- std::string result = Includes[Indices[0]].Text;
- for (unsigned i = 1, e = Indices.size(); i != e; ++i) {
- result += "\n";
- result += Includes[Indices[i]].Text;
+ std::string result;
+ bool CursorMoved = false;
+ for (unsigned Index : Indices) {
+ if (!result.empty())
+ result += "\n";
+ result += Includes[Index].Text;
+
+ if (Cursor && !CursorMoved) {
+ unsigned Start = Includes[Index].Offset;
+ unsigned End = Start + Includes[Index].Text.size();
+ if (*Cursor >= Start && *Cursor < End) {
+ *Cursor = Includes.front().Offset + result.size() + *Cursor - End;
+ CursorMoved = true;
+ }
+ }
}
// Sorting #includes shouldn't change their total number of characters.
@@ -1741,8 +1798,11 @@
tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
- StringRef FileName) {
+ StringRef FileName, unsigned *Cursor) {
tooling::Replacements Replaces;
+ if (!Style.SortIncludes)
+ return Replaces;
+
unsigned Prev = 0;
unsigned SearchFrom = 0;
llvm::Regex IncludeRegex(
@@ -1757,43 +1817,57 @@
//
// FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix
// cases where the first #include is unlikely to be the main header.
- bool LookForMainHeader = FileName.endswith(".c") ||
- FileName.endswith(".cc") ||
- FileName.endswith(".cpp")||
- FileName.endswith(".c++")||
- FileName.endswith(".cxx") ||
- FileName.endswith(".m")||
- FileName.endswith(".mm");
+ bool IsSource = FileName.endswith(".c") || FileName.endswith(".cc") ||
+ FileName.endswith(".cpp") || FileName.endswith(".c++") ||
+ FileName.endswith(".cxx") || FileName.endswith(".m") ||
+ FileName.endswith(".mm");
+ StringRef FileStem = llvm::sys::path::stem(FileName);
+ bool FirstIncludeBlock = true;
+ bool MainIncludeFound = false;
// Create pre-compiled regular expressions for the #include categories.
SmallVector<llvm::Regex, 4> CategoryRegexs;
for (const auto &Category : Style.IncludeCategories)
CategoryRegexs.emplace_back(Category.Regex);
+ bool FormattingOff = false;
+
for (;;) {
auto Pos = Code.find('\n', SearchFrom);
StringRef Line =
Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
- if (!Line.endswith("\\")) {
+
+ StringRef Trimmed = Line.trim();
+ if (Trimmed == "// clang-format off")
+ FormattingOff = true;
+ else if (Trimmed == "// clang-format on")
+ FormattingOff = false;
+
+ if (!FormattingOff && !Line.endswith("\\")) {
if (IncludeRegex.match(Line, &Matches)) {
StringRef IncludeName = Matches[2];
- unsigned Category;
- if (LookForMainHeader && !IncludeName.startswith("<")) {
- Category = 0;
- } else {
- Category = UINT_MAX;
- for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) {
- if (CategoryRegexs[i].match(IncludeName)) {
- Category = Style.IncludeCategories[i].Priority;
- break;
- }
+ int Category = INT_MAX;
+ for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) {
+ if (CategoryRegexs[i].match(IncludeName)) {
+ Category = Style.IncludeCategories[i].Priority;
+ break;
}
}
- LookForMainHeader = false;
+ if (IsSource && !MainIncludeFound && Category > 0 &&
+ FirstIncludeBlock && IncludeName.startswith("\"")) {
+ StringRef HeaderStem =
+ llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
+ if (FileStem.startswith(HeaderStem)) {
+ Category = 0;
+ MainIncludeFound = true;
+ }
+ }
IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
} else if (!IncludesInBlock.empty()) {
- sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces);
+ sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces,
+ Cursor);
IncludesInBlock.clear();
+ FirstIncludeBlock = false;
}
Prev = Pos + 1;
}
@@ -1802,7 +1876,7 @@
SearchFrom = Pos + 1;
}
if (!IncludesInBlock.empty())
- sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces);
+ sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor);
return Replaces;
}
@@ -1830,8 +1904,9 @@
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
new DiagnosticOptions);
SourceManager SourceMgr(Diagnostics, Files);
- InMemoryFileSystem->addFile(FileName, 0,
- llvm::MemoryBuffer::getMemBuffer(Code, FileName));
+ InMemoryFileSystem->addFile(
+ FileName, 0, llvm::MemoryBuffer::getMemBuffer(
+ Code, FileName, /*RequiresNullTerminator=*/false));
FileID ID = SourceMgr.createFileID(Files.getFile(FileName), SourceLocation(),
clang::SrcMgr::C_User);
SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);
@@ -1872,15 +1947,15 @@
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
- if (FileName.endswith(".java")) {
+ if (FileName.endswith(".java"))
return FormatStyle::LK_Java;
- } else if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) {
- // JavaScript or TypeScript.
- return FormatStyle::LK_JavaScript;
- } else if (FileName.endswith_lower(".proto") ||
- FileName.endswith_lower(".protodevel")) {
+ if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
+ return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
+ if (FileName.endswith_lower(".proto") ||
+ FileName.endswith_lower(".protodevel"))
return FormatStyle::LK_Proto;
- }
+ if (FileName.endswith_lower(".td"))
+ return FormatStyle::LK_TableGen;
return FormatStyle::LK_Cpp;
}
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index b1c64b8..d6cd450 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -80,8 +80,8 @@
// Ensure that we start on the opening brace.
const FormatToken *LBrace =
State.NextToken->Previous->getPreviousNonComment();
- if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->BlockKind == BK_Block ||
- LBrace->Type == TT_DictLiteral ||
+ if (!LBrace || !LBrace->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ LBrace->BlockKind == BK_Block || LBrace->Type == TT_DictLiteral ||
LBrace->Next->Type == TT_DesignatedInitializerPeriod)
return 0;
@@ -144,7 +144,8 @@
void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// FIXME: At some point we might want to do this for other lists, too.
- if (!Token->MatchingParen || Token->isNot(tok::l_brace))
+ if (!Token->MatchingParen ||
+ !Token->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare))
return;
// In C++11 braced list style, we should not format in columns unless they
@@ -154,6 +155,12 @@
Commas.size() < 19)
return;
+ // Limit column layout for JavaScript array initializers to 20 or more items
+ // for now to introduce it carefully. We can become more aggressive if this
+ // necessary.
+ if (Token->is(TT_ArrayInitializerLSquare) && Commas.size() < 19)
+ return;
+
// Column format doesn't really make sense if we don't align after brackets.
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign)
return;
@@ -211,9 +218,12 @@
ItemBegin = ItemEnd->Next;
}
- // Don't use column layout for nested lists, lists with few elements and in
- // presence of separating comments.
- if (Token->NestingLevel != 0 || Commas.size() < 5 || HasSeparatingComment)
+ // Don't use column layout for lists with few elements and in presence of
+ // separating comments.
+ if (Commas.size() < 5 || HasSeparatingComment)
+ return;
+
+ if (Token->NestingLevel != 0 && Token->is(tok::l_brace) && Commas.size() < 19)
return;
// We can never place more than ColumnLimit / 3 items in a row (because of the
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 002ff25..b683660 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -248,9 +248,9 @@
/// with the same precedence, contains the 0-based operator index.
unsigned OperatorIndex = 0;
- /// \brief Is this the last operator (or "."/"->") in a sequence of operators
- /// with the same precedence?
- bool LastOperator = false;
+ /// \brief If this is an operator (or "."/"->") in a sequence of operators
+ /// with the same precedence, points to the next operator.
+ FormatToken *NextOperator = nullptr;
/// \brief Is this token part of a \c DeclStmt defining multiple variables?
///
@@ -536,6 +536,7 @@
kw_finally = &IdentTable.get("finally");
kw_function = &IdentTable.get("function");
kw_import = &IdentTable.get("import");
+ kw_is = &IdentTable.get("is");
kw_let = &IdentTable.get("let");
kw_var = &IdentTable.get("var");
@@ -553,6 +554,7 @@
kw_mark = &IdentTable.get("mark");
+ kw_extend = &IdentTable.get("extend");
kw_option = &IdentTable.get("option");
kw_optional = &IdentTable.get("optional");
kw_repeated = &IdentTable.get("repeated");
@@ -560,6 +562,7 @@
kw_returns = &IdentTable.get("returns");
kw_signals = &IdentTable.get("signals");
+ kw_qsignals = &IdentTable.get("Q_SIGNALS");
kw_slots = &IdentTable.get("slots");
kw_qslots = &IdentTable.get("Q_SLOTS");
}
@@ -578,6 +581,7 @@
IdentifierInfo *kw_finally;
IdentifierInfo *kw_function;
IdentifierInfo *kw_import;
+ IdentifierInfo *kw_is;
IdentifierInfo *kw_let;
IdentifierInfo *kw_var;
@@ -597,6 +601,7 @@
IdentifierInfo *kw_mark;
// Proto keywords.
+ IdentifierInfo *kw_extend;
IdentifierInfo *kw_option;
IdentifierInfo *kw_optional;
IdentifierInfo *kw_repeated;
@@ -605,6 +610,7 @@
// QT keywords.
IdentifierInfo *kw_signals;
+ IdentifierInfo *kw_qsignals;
IdentifierInfo *kw_slots;
IdentifierInfo *kw_qslots;
};
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index b44a341..6d6df0c 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -119,7 +119,9 @@
}
}
- if (Left->Previous &&
+ if (Left->is(TT_OverloadedOperatorLParen)) {
+ Contexts.back().IsExpression = false;
+ } else if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
tok::kw_if, tok::kw_while, tok::l_paren,
tok::comma) ||
@@ -132,9 +134,7 @@
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
} else if (Line.InPPDirective &&
- (!Left->Previous ||
- !Left->Previous->isOneOf(tok::identifier,
- TT_OverloadedOperator))) {
+ (!Left->Previous || !Left->Previous->is(tok::identifier))) {
Contexts.back().IsExpression = true;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
// This is the parameter list of an ObjC block.
@@ -148,6 +148,10 @@
} else if (Left->Previous && Left->Previous->MatchingParen &&
Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) {
Contexts.back().IsExpression = false;
+ } else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
+ bool IsForOrCatch =
+ Left->Previous && Left->Previous->isOneOf(tok::kw_for, tok::kw_catch);
+ Contexts.back().IsExpression = !IsForOrCatch;
}
if (StartsObjCMethodExpr) {
@@ -155,7 +159,8 @@
Left->Type = TT_ObjCMethodExpr;
}
- bool MightBeFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
+ bool MightBeFunctionType = CurrentToken->isOneOf(tok::star, tok::amp) &&
+ !Contexts[Contexts.size() - 2].IsExpression;
bool HasMultipleLines = false;
bool HasMultipleParametersOnALine = false;
bool MightBeObjCForRangeLoop =
@@ -189,11 +194,23 @@
if (MightBeFunctionType && CurrentToken->Next &&
(CurrentToken->Next->is(tok::l_paren) ||
(CurrentToken->Next->is(tok::l_square) &&
- !Contexts.back().IsExpression)))
+ Line.MustBeDeclaration)))
Left->Type = TT_FunctionTypeLParen;
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
+ if (CurrentToken->Next && CurrentToken->Next->is(tok::l_brace) &&
+ Left->Previous && Left->Previous->is(tok::l_paren)) {
+ // Detect the case where macros are used to generate lambdas or
+ // function bodies, e.g.:
+ // auto my_lambda = MARCO((Type *type, int i) { .. body .. });
+ for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) {
+ if (Tok->is(TT_BinaryOperator) &&
+ Tok->isOneOf(tok::star, tok::amp, tok::ampamp))
+ Tok->Type = TT_PointerOrReference;
+ }
+ }
+
if (StartsObjCMethodExpr) {
CurrentToken->Type = TT_ObjCMethodExpr;
if (Contexts.back().FirstObjCSelectorName) {
@@ -280,10 +297,13 @@
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->Type = TT_JsComputedPropertyName;
- } else if (Parent &&
- Parent->isOneOf(tok::at, tok::equal, tok::comma, tok::l_paren,
- tok::l_square, tok::question, tok::colon,
- tok::kw_return)) {
+ } else if (Style.Language == FormatStyle::LK_Proto ||
+ (Parent &&
+ Parent->isOneOf(TT_BinaryOperator, tok::at, tok::comma,
+ tok::l_paren, tok::l_square, tok::question,
+ tok::colon, tok::kw_return,
+ // Should only be relevant to JavaScript:
+ tok::kw_default))) {
Left->Type = TT_ArrayInitializerLSquare;
} else {
BindingIncrease = 10;
@@ -453,16 +473,16 @@
break;
}
}
- if (Contexts.back().ColonIsDictLiteral) {
+ if (Contexts.back().ColonIsDictLiteral ||
+ Style.Language == FormatStyle::LK_Proto) {
Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
Line.startsWith(TT_ObjCMethodSpecifier)) {
Tok->Type = TT_ObjCMethodExpr;
Tok->Previous->Type = TT_SelectorName;
if (Tok->Previous->ColumnWidth >
- Contexts.back().LongestObjCSelectorName) {
+ Contexts.back().LongestObjCSelectorName)
Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth;
- }
if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
@@ -560,7 +580,8 @@
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
- if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator))
+ if (CurrentToken &&
+ CurrentToken->Previous->isOneOf(TT_BinaryOperator, tok::comma))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
if (CurrentToken) {
@@ -831,7 +852,7 @@
void modifyContext(const FormatToken &Current) {
if (Current.getPrecedence() == prec::Assignment &&
- !Line.First->isOneOf(tok::kw_template, tok::kw_using) &&
+ !Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) &&
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
if (!Line.startsWith(TT_UnaryOperator)) {
@@ -861,17 +882,6 @@
Contexts.back().IsExpression = false;
} else if (Current.is(TT_LambdaArrow) || Current.is(Keywords.kw_assert)) {
Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java;
- } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
- !Line.InPPDirective &&
- (!Current.Previous ||
- Current.Previous->isNot(tok::kw_decltype))) {
- bool ParametersOfFunctionType =
- Current.Previous && Current.Previous->is(tok::r_paren) &&
- Current.Previous->MatchingParen &&
- Current.Previous->MatchingParen->is(TT_FunctionTypeLParen);
- bool IsForOrCatch = Current.Previous &&
- Current.Previous->isOneOf(tok::kw_for, tok::kw_catch);
- Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
@@ -905,7 +915,7 @@
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
Contexts.back().FirstStartOfName = &Current;
Current.Type = TT_StartOfName;
- } else if (Current.is(tok::kw_auto)) {
+ } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) {
AutoFound = true;
} else if (Current.is(tok::arrow) &&
Style.Language == FormatStyle::LK_Java) {
@@ -1057,76 +1067,93 @@
/// \brief Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
- FormatToken *LeftOfParens = nullptr;
- if (Tok.MatchingParen)
- LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
- if (LeftOfParens && LeftOfParens->is(tok::r_paren) &&
- LeftOfParens->MatchingParen)
- LeftOfParens = LeftOfParens->MatchingParen->Previous;
- if (LeftOfParens && LeftOfParens->is(tok::r_square) &&
- LeftOfParens->MatchingParen &&
- LeftOfParens->MatchingParen->is(TT_LambdaLSquare))
+ // C-style casts are only used in C++ and Java.
+ if (Style.Language != FormatStyle::LK_Cpp &&
+ Style.Language != FormatStyle::LK_Java)
return false;
- if (Tok.Next) {
- if (Tok.Next->is(tok::question))
+
+ // Empty parens aren't casts and there are no casts at the end of the line.
+ if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
+ return false;
+
+ FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
+ if (LeftOfParens) {
+ // If there is an opening parenthesis left of the current parentheses,
+ // look past it as these might be chained casts.
+ if (LeftOfParens->is(tok::r_paren)) {
+ if (!LeftOfParens->MatchingParen ||
+ !LeftOfParens->MatchingParen->Previous)
+ return false;
+ LeftOfParens = LeftOfParens->MatchingParen->Previous;
+ }
+
+ // If there is an identifier (or with a few exceptions a keyword) right
+ // before the parentheses, this is unlikely to be a cast.
+ if (LeftOfParens->Tok.getIdentifierInfo() &&
+ !LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case,
+ tok::kw_delete))
return false;
- if (Style.Language == FormatStyle::LK_JavaScript &&
- Tok.Next->is(Keywords.kw_in))
+
+ // Certain other tokens right before the parentheses are also signals that
+ // this cannot be a cast.
+ if (LeftOfParens->isOneOf(tok::at, tok::r_square, TT_OverloadedOperator,
+ TT_TemplateCloser))
return false;
- if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
- return true;
}
- bool IsCast = false;
- bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen;
+
+ if (Tok.Next->is(tok::question))
+ return false;
+
+ // As Java has no function types, a "(" after the ")" likely means that this
+ // is a cast.
+ if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
+ return true;
+
+ // If a (non-string) literal follows, this is likely a cast.
+ if (Tok.Next->isNot(tok::string_literal) &&
+ (Tok.Next->Tok.isLiteral() ||
+ Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
+ return true;
+
+ // Heuristically try to determine whether the parentheses contain a type.
bool ParensAreType =
!Tok.Previous ||
Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) ||
Tok.Previous->isSimpleTypeSpecifier();
bool ParensCouldEndDecl =
- Tok.Next &&
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
- bool IsSizeOfOrAlignOf =
- LeftOfParens && LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
- if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
- (Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression))
- IsCast = true;
- else if (Tok.Next && Tok.Next->isNot(tok::string_literal) &&
- (Tok.Next->Tok.isLiteral() ||
- Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
- IsCast = true;
- // If there is an identifier after the (), it is likely a cast, unless
- // there is also an identifier before the ().
- else if (LeftOfParens && Tok.Next &&
- (LeftOfParens->Tok.getIdentifierInfo() == nullptr ||
- LeftOfParens->isOneOf(tok::kw_return, tok::kw_case)) &&
- !LeftOfParens->isOneOf(TT_OverloadedOperator, tok::at,
- TT_TemplateCloser)) {
- if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
- IsCast = true;
- } else {
- // Use heuristics to recognize c style casting.
- FormatToken *Prev = Tok.Previous;
- if (Prev && Prev->isOneOf(tok::amp, tok::star))
- Prev = Prev->Previous;
+ if (ParensAreType && !ParensCouldEndDecl)
+ return true;
- if (Prev && Tok.Next && Tok.Next->Next) {
- bool NextIsUnary = Tok.Next->isUnaryOperator() ||
- Tok.Next->isOneOf(tok::amp, tok::star);
- IsCast =
- NextIsUnary && !Tok.Next->is(tok::plus) &&
- Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant);
- }
+ // At this point, we heuristically assume that there are no casts at the
+ // start of the line. We assume that we have found most cases where there
+ // are by the logic above, e.g. "(void)x;".
+ if (!LeftOfParens)
+ return false;
- for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) {
- if (!Prev ||
- !Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon)) {
- IsCast = false;
- break;
- }
- }
- }
+ // If the following token is an identifier, this is a cast. All cases where
+ // this can be something else are handled above.
+ if (Tok.Next->is(tok::identifier))
+ return true;
+
+ if (!Tok.Next->Next)
+ return false;
+
+ // If the next token after the parenthesis is a unary operator, assume
+ // that this is cast, unless there are unexpected tokens inside the
+ // parenthesis.
+ bool NextIsUnary =
+ Tok.Next->isUnaryOperator() || Tok.Next->isOneOf(tok::amp, tok::star);
+ if (!NextIsUnary || Tok.Next->is(tok::plus) ||
+ !Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant))
+ return false;
+ // Search for unexpected tokens.
+ for (FormatToken *Prev = Tok.Previous; Prev != Tok.MatchingParen;
+ Prev = Prev->Previous) {
+ if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon))
+ return false;
}
- return IsCast && !ParensAreEmpty;
+ return true;
}
/// \brief Return the type of the given token assuming it is * or &.
@@ -1316,6 +1343,8 @@
} else {
// Operator found.
if (CurrentPrecedence == Precedence) {
+ if (LatestOperator)
+ LatestOperator->NextOperator = Current;
LatestOperator = Current;
Current->OperatorIndex = OperatorIndex;
++OperatorIndex;
@@ -1325,7 +1354,7 @@
}
if (LatestOperator && (Current || Precedence > 0)) {
- LatestOperator->LastOperator = true;
+ // LatestOperator->LastOperator = true;
if (Precedence == PrecedenceArrowAndPeriod) {
// Call expressions don't have a binary operator precedence.
addFakeParenthesis(Start, prec::Unknown);
@@ -1544,6 +1573,29 @@
return false;
}
+bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
+ assert(Line.MightBeFunctionDecl);
+
+ if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel ||
+ Style.AlwaysBreakAfterReturnType ==
+ FormatStyle::RTBS_TopLevelDefinitions) &&
+ Line.Level > 0)
+ return false;
+
+ switch (Style.AlwaysBreakAfterReturnType) {
+ case FormatStyle::RTBS_None:
+ return false;
+ case FormatStyle::RTBS_All:
+ case FormatStyle::RTBS_TopLevel:
+ return true;
+ case FormatStyle::RTBS_AllDefinitions:
+ case FormatStyle::RTBS_TopLevelDefinitions:
+ return Line.mightBeFunctionDefinition();
+ }
+
+ return false;
+}
+
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
E = Line.Children.end();
@@ -1595,15 +1647,9 @@
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
- if ((Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All ||
- (Style.AlwaysBreakAfterDefinitionReturnType ==
- FormatStyle::DRTBS_TopLevel &&
- Line.Level == 0)) &&
- InFunctionDecl && Current->is(TT_FunctionDeclarationName) &&
- !Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions.
- // FIXME: Line.Last points to other characters than tok::semi
- // and tok::lbrace.
- Current->MustBreakBefore = true;
+ if (!Current->MustBreakBefore && InFunctionDecl &&
+ Current->is(TT_FunctionDeclarationName))
+ Current->MustBreakBefore = mustBreakForReturnType(Line);
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
@@ -1680,7 +1726,7 @@
if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma))
return 100;
if (Left.is(TT_JsTypeColon))
- return 100;
+ return 35;
}
if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
@@ -1689,9 +1735,11 @@
if (Right.is(tok::l_square)) {
if (Style.Language == FormatStyle::LK_Proto)
return 1;
+ if (Left.is(tok::r_square))
+ return 25;
// Slightly prefer formatting local lambda definitions like functions.
if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal))
- return 50;
+ return 35;
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
TT_ArrayInitializerLSquare))
return 500;
@@ -1725,10 +1773,28 @@
return 2;
if (Right.isMemberAccess()) {
- if (Left.is(tok::r_paren) && Left.MatchingParen &&
- Left.MatchingParen->ParameterCount > 0)
- return 20; // Should be smaller than breaking at a nested comma.
- return 150;
+ // Breaking before the "./->" of a chained call/member access is reasonably
+ // cheap, as formatting those with one call per line is generally
+ // desirable. In particular, it should be cheaper to break before the call
+ // than it is to break inside a call's parameters, which could lead to weird
+ // "hanging" indents. The exception is the very last "./->" to support this
+ // frequent pattern:
+ //
+ // aaaaaaaa.aaaaaaaa.bbbbbbb().ccccccccccccccccccccc(
+ // dddddddd);
+ //
+ // which might otherwise be blown up onto many lines. Here, clang-format
+ // won't produce "hanging" indents anyway as there is no other trailing
+ // call.
+ //
+ // Also apply higher penalty is not a call as that might lead to a wrapping
+ // like:
+ //
+ // aaaaaaa
+ // .aaaaaaaaa.bbbbbbbb(cccccccc);
+ return !Right.NextOperator || !Right.NextOperator->Previous->closesScope()
+ ? 150
+ : 35;
}
if (Right.is(TT_TrailingAnnotation) &&
@@ -1780,7 +1846,7 @@
if (Right.is(tok::lessless)) {
if (Left.is(tok::string_literal) &&
- (!Right.LastOperator || Right.OperatorIndex != 1)) {
+ (Right.NextOperator || Right.OperatorIndex != 1)) {
StringRef Content = Left.TokenText;
if (Content.startswith("\""))
Content = Content.drop_front(1);
@@ -1837,6 +1903,8 @@
tok::numeric_constant, tok::l_paren, tok::l_brace,
tok::kw_true, tok::kw_false))
return false;
+ if (Left.is(tok::colon))
+ return !Left.is(TT_ObjCMethodExpr);
if (Left.is(tok::coloncolon))
return false;
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less))
@@ -1887,8 +1955,6 @@
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
- if (Left.is(tok::colon))
- return !Left.is(TT_ObjCMethodExpr);
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
return !Left.Children.empty(); // No spaces in "{}".
if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
@@ -1949,13 +2015,19 @@
} else if (Style.Language == FormatStyle::LK_Proto) {
if (Right.is(tok::period) &&
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
- Keywords.kw_repeated))
+ Keywords.kw_repeated, Keywords.kw_extend))
return true;
if (Right.is(tok::l_paren) &&
Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, TT_JsFatArrow))
+ if (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, TT_JsFatArrow,
+ Keywords.kw_in))
+ return true;
+ if (Left.is(tok::kw_default) && Left.Previous &&
+ Left.Previous->is(tok::kw_export))
+ return true;
+ if (Left.is(Keywords.kw_is) && Right.is(tok::l_brace))
return true;
if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
return false;
@@ -1999,14 +2071,14 @@
if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow))
return true;
+ if (Right.is(TT_OverloadedOperatorLParen))
+ return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
if (Left.is(tok::comma))
return true;
if (Right.is(tok::comma))
return false;
if (Right.isOneOf(TT_CtorInitializerColon, TT_ObjCBlockLParen))
return true;
- if (Right.is(TT_OverloadedOperatorLParen))
- return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
if (Right.is(tok::colon)) {
if (Line.First->isOneOf(tok::kw_case, tok::kw_default) ||
!Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi))
@@ -2047,7 +2119,8 @@
if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
return Style.SpacesInAngles;
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
- Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr))
+ (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
+ !Right.is(tok::r_paren)))
return true;
if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) &&
Right.isNot(TT_FunctionTypeLParen))
@@ -2102,6 +2175,7 @@
!Left.Children.empty())
// Support AllowShortFunctionsOnASingleLine for JavaScript.
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
(Left.NestingLevel == 0 && Line.Level == 0 &&
Style.AllowShortFunctionsOnASingleLine ==
FormatStyle::SFS_Inline);
@@ -2194,10 +2268,14 @@
Keywords.kw_implements))
return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Left.is(tok::kw_return))
+ return false; // Otherwise a semicolon is inserted.
if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
return false;
if (Left.is(TT_JsTypeColon))
return true;
+ if (Right.NestingLevel == 0 && Right.is(Keywords.kw_is))
+ return false;
}
if (Left.is(tok::at))
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index b8a6be0..5329f1f 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -86,6 +86,15 @@
return startsWith(First, Tokens...);
}
+ /// \c true if this line looks like a function definition instead of a
+ /// function declaration. Asserts MightBeFunctionDecl.
+ bool mightBeFunctionDefinition() const {
+ assert(MightBeFunctionDecl);
+ // FIXME: Line.Last points to other characters than tok::semi
+ // and tok::lbrace.
+ return !Last->isOneOf(tok::semi, tok::comment);
+ }
+
FormatToken *First;
FormatToken *Last;
@@ -156,6 +165,8 @@
bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
+ bool mustBreakForReturnType(const AnnotatedLine &Line) const;
+
void printDebugInfo(const AnnotatedLine &Line);
void calculateUnbreakableTailLengths(AnnotatedLine &Line);
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 04087e8..f650569 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -90,8 +90,8 @@
return 0;
if (RootToken.isAccessSpecifier(false) ||
RootToken.isObjCAccessSpecifier() ||
- (RootToken.is(Keywords.kw_signals) && RootToken.Next &&
- RootToken.Next->is(tok::colon)))
+ (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
+ RootToken.Next && RootToken.Next->is(tok::colon)))
return Style.AccessModifierOffset;
return 0;
}
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index ad54821..7b8f6e6 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -315,13 +315,14 @@
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
FormatToken *Tok = FormatTok;
+ const FormatToken *PrevTok = getPreviousToken();
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
// braced init list or a different block during the loop.
SmallVector<FormatToken *, 8> LBraceStack;
assert(Tok->Tok.is(tok::l_brace));
do {
- // Get next none-comment token.
+ // Get next non-comment token.
FormatToken *NextTok;
unsigned ReadTokens = 0;
do {
@@ -331,47 +332,53 @@
switch (Tok->Tok.getKind()) {
case tok::l_brace:
- Tok->BlockKind = BK_Unknown;
+ if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
+ PrevTok->is(tok::colon))
+ // In TypeScript's TypeMemberLists, there can be semicolons between the
+ // individual members.
+ Tok->BlockKind = BK_BracedInit;
+ else
+ Tok->BlockKind = BK_Unknown;
LBraceStack.push_back(Tok);
break;
case tok::r_brace:
- if (!LBraceStack.empty()) {
- if (LBraceStack.back()->BlockKind == BK_Unknown) {
- bool ProbablyBracedList = false;
- if (Style.Language == FormatStyle::LK_Proto) {
- ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
- } else {
- // Using OriginalColumn to distinguish between ObjC methods and
- // binary operators is a bit hacky.
- bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
- NextTok->OriginalColumn == 0;
+ if (LBraceStack.empty())
+ break;
+ if (LBraceStack.back()->BlockKind == BK_Unknown) {
+ bool ProbablyBracedList = false;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+ } else {
+ // Using OriginalColumn to distinguish between ObjC methods and
+ // binary operators is a bit hacky.
+ bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
+ NextTok->OriginalColumn == 0;
- // If there is a comma, semicolon or right paren after the closing
- // brace, we assume this is a braced initializer list. Note that
- // regardless how we mark inner braces here, we will overwrite the
- // BlockKind later if we parse a braced list (where all blocks
- // inside are by default braced lists), or when we explicitly detect
- // blocks (for example while parsing lambdas).
- //
- // We exclude + and - as they can be ObjC visibility modifiers.
- ProbablyBracedList =
- NextTok->isOneOf(tok::comma, tok::period, tok::colon,
- tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_paren, tok::ellipsis) ||
- (NextTok->is(tok::semi) &&
- (!ExpectClassBody || LBraceStack.size() != 1)) ||
- (NextTok->isBinaryOperator() && !NextIsObjCMethod);
- }
- if (ProbablyBracedList) {
- Tok->BlockKind = BK_BracedInit;
- LBraceStack.back()->BlockKind = BK_BracedInit;
- } else {
- Tok->BlockKind = BK_Block;
- LBraceStack.back()->BlockKind = BK_Block;
- }
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // BlockKind later if we parse a braced list (where all blocks
+ // inside are by default braced lists), or when we explicitly detect
+ // blocks (for example while parsing lambdas).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ ProbablyBracedList =
+ NextTok->isOneOf(tok::comma, tok::period, tok::colon,
+ tok::r_paren, tok::r_square, tok::l_brace,
+ tok::l_square, tok::l_paren, tok::ellipsis) ||
+ (NextTok->is(tok::semi) &&
+ (!ExpectClassBody || LBraceStack.size() != 1)) ||
+ (NextTok->isBinaryOperator() && !NextIsObjCMethod);
}
- LBraceStack.pop_back();
+ if (ProbablyBracedList) {
+ Tok->BlockKind = BK_BracedInit;
+ LBraceStack.back()->BlockKind = BK_BracedInit;
+ } else {
+ Tok->BlockKind = BK_Block;
+ LBraceStack.back()->BlockKind = BK_Block;
+ }
}
+ LBraceStack.pop_back();
break;
case tok::at:
case tok::semi:
@@ -381,14 +388,16 @@
case tok::kw_switch:
case tok::kw_try:
case tok::kw___try:
- if (!LBraceStack.empty())
+ if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown)
LBraceStack.back()->BlockKind = BK_Block;
break;
default:
break;
}
+ PrevTok = Tok;
Tok = NextTok;
} while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
+
// Assume other blocks for all unclosed opening braces.
for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
if (LBraceStack[i]->BlockKind == BK_Unknown)
@@ -403,6 +412,7 @@
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
"'{' or macro block token expected");
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
+ FormatTok->BlockKind = BK_Block;
unsigned InitialLevel = Line->Level;
nextToken();
@@ -421,6 +431,7 @@
if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
: !FormatTok->is(tok::r_brace)) {
Line->Level = InitialLevel;
+ FormatTok->BlockKind = BK_Block;
return;
}
@@ -648,7 +659,15 @@
}
void UnwrappedLineParser::parseStructuralElement() {
- assert(!FormatTok->Tok.is(tok::l_brace));
+ assert(!FormatTok->is(tok::l_brace));
+ if (Style.Language == FormatStyle::LK_TableGen &&
+ FormatTok->is(tok::pp_include)) {
+ nextToken();
+ if (FormatTok->is(tok::string_literal))
+ nextToken();
+ addUnwrappedLine();
+ return;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
@@ -784,7 +803,8 @@
parseJavaScriptEs6ImportExport();
return;
}
- if (FormatTok->is(Keywords.kw_signals)) {
+ if (FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
+ Keywords.kw_slots, Keywords.kw_qslots)) {
nextToken();
if (FormatTok->is(tok::colon)) {
nextToken();
@@ -807,7 +827,8 @@
case tok::kw_enum:
// parseEnum falls through and does not yet add an unwrapped line as an
// enum definition can start a structural element.
- parseEnum();
+ if (!parseEnum())
+ break;
// This only applies for C++.
if (Style.Language != FormatStyle::LK_Cpp) {
addUnwrappedLine();
@@ -829,6 +850,8 @@
// This does not apply for Java and JavaScript.
if (Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) {
+ if (FormatTok->is(tok::semi))
+ nextToken();
addUnwrappedLine();
return;
}
@@ -974,13 +997,11 @@
nextToken();
return false;
}
- // FIXME: This is a dirty way to access the previous token. Find a better
- // solution.
- if (!Line->Tokens.empty() &&
- (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator,
- tok::kw_new, tok::kw_delete) ||
- Line->Tokens.back().Tok->closesScope() ||
- Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
+ const FormatToken* Previous = getPreviousToken();
+ if (Previous &&
+ (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
+ tok::kw_delete) ||
+ Previous->closesScope() || Previous->isSimpleTypeSpecifier())) {
nextToken();
return false;
}
@@ -1162,6 +1183,14 @@
nextToken();
return !HasError;
case tok::semi:
+ // JavaScript (or more precisely TypeScript) can have semicolons in braced
+ // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
+ // used for error recovery if we have otherwise determined that this is
+ // a braced list.
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ nextToken();
+ break;
+ }
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
@@ -1513,11 +1542,17 @@
addUnwrappedLine();
}
-void UnwrappedLineParser::parseEnum() {
+bool UnwrappedLineParser::parseEnum() {
// Won't be 'enum' for NS_ENUMs.
if (FormatTok->Tok.is(tok::kw_enum))
nextToken();
+ // In TypeScript, "enum" can also be used as property name, e.g. in interface
+ // declarations. An "enum" keyword followed by a colon would be a syntax
+ // error and thus assume it is just an identifier.
+ if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(tok::colon))
+ return false;
+
// Eat up enum class ...
if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
nextToken();
@@ -1535,22 +1570,23 @@
// return type. In Java, this can be "implements", etc.
if (Style.Language == FormatStyle::LK_Cpp &&
FormatTok->is(tok::identifier))
- return;
+ return false;
}
}
// Just a declaration or something is wrong.
if (FormatTok->isNot(tok::l_brace))
- return;
+ return true;
FormatTok->BlockKind = BK_Block;
if (Style.Language == FormatStyle::LK_Java) {
// Java enums are different.
parseJavaEnumBody();
- return;
- } else if (Style.Language == FormatStyle::LK_Proto) {
+ return true;
+ }
+ if (Style.Language == FormatStyle::LK_Proto) {
parseBlock(/*MustBeDeclaration=*/true);
- return;
+ return true;
}
// Parse enum body.
@@ -1560,6 +1596,7 @@
nextToken();
addUnwrappedLine();
}
+ return true;
// There is no addUnwrappedLine() here so that we fall through to parsing a
// structural element afterwards. Thus, in "enum A {} n, m;",
@@ -1772,18 +1809,22 @@
return;
}
+ // Consume the "abstract" in "export abstract class".
+ if (FormatTok->is(Keywords.kw_abstract))
+ nextToken();
+
if (FormatTok->isOneOf(tok::kw_const, tok::kw_class, tok::kw_enum,
- Keywords.kw_let, Keywords.kw_var))
+ Keywords.kw_interface, Keywords.kw_let,
+ Keywords.kw_var))
return; // Fall through to parsing the corresponding structure.
- if (FormatTok->is(tok::l_brace)) {
- FormatTok->BlockKind = BK_Block;
- parseBracedList();
- }
-
- while (!eof() && FormatTok->isNot(tok::semi) &&
- FormatTok->isNot(tok::l_brace)) {
- nextToken();
+ while (!eof() && FormatTok->isNot(tok::semi)) {
+ if (FormatTok->is(tok::l_brace)) {
+ FormatTok->BlockKind = BK_Block;
+ parseBracedList();
+ } else {
+ nextToken();
+ }
}
}
@@ -1857,6 +1898,14 @@
readToken();
}
+const FormatToken *UnwrappedLineParser::getPreviousToken() {
+ // FIXME: This is a dirty way to access the previous token. Find a better
+ // solution.
+ if (!Line || Line->Tokens.empty())
+ return nullptr;
+ return Line->Tokens.back().Tok;
+}
+
void UnwrappedLineParser::readToken() {
bool CommentsInCurrentLine = true;
do {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index c2fa029..6d40ab4 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -96,7 +96,7 @@
void parseNamespace();
void parseNew();
void parseAccessSpecifier();
- void parseEnum();
+ bool parseEnum();
void parseJavaEnumBody();
void parseRecord();
void parseObjCProtocolList();
@@ -110,6 +110,7 @@
void addUnwrappedLine();
bool eof() const;
void nextToken();
+ const FormatToken *getPreviousToken();
void readToken();
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 3536132..d6e6ed2 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -30,7 +30,7 @@
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective,
- bool IsStartOfDeclName)
+ bool IsStartOfDeclName, bool IsInsideToken)
: CreateReplacement(CreateReplacement),
OriginalWhitespaceRange(OriginalWhitespaceRange),
StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
@@ -38,8 +38,8 @@
CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
ContinuesPPDirective(ContinuesPPDirective),
IsStartOfDeclName(IsStartOfDeclName), IndentLevel(IndentLevel),
- Spaces(Spaces), IsTrailingComment(false), TokenLength(0),
- PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
+ Spaces(Spaces), IsInsideToken(IsInsideToken), IsTrailingComment(false),
+ TokenLength(0), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
StartOfBlockComment(nullptr), IndentationOffset(0) {}
void WhitespaceManager::reset() {
@@ -55,20 +55,23 @@
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
Changes.push_back(
- Change(true, Tok.WhitespaceRange, IndentLevel, Spaces, StartOfTokenColumn,
- Newlines, "", "", Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Change(/*CreateReplacement=*/true, Tok.WhitespaceRange, IndentLevel,
+ Spaces, StartOfTokenColumn, Newlines, "", "", Tok.Tok.getKind(),
+ InPPDirective && !Tok.IsFirst,
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
bool InPPDirective) {
if (Tok.Finalized)
return;
- Changes.push_back(
- Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
- /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
- Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Changes.push_back(Change(
+ /*CreateReplacement=*/false, Tok.WhitespaceRange, /*IndentLevel=*/0,
+ /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
+ Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::replaceWhitespaceInToken(
@@ -81,15 +84,10 @@
Changes.push_back(Change(
true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
- CurrentPrefix,
- // If we don't add a newline this change doesn't start a comment. Thus,
- // when we align line comments, we don't need to treat this change as one.
- // FIXME: We still need to take this change in account to properly
- // calculate the new length of the comment and to calculate the changes
- // for which to do the alignment when aligning comments.
- Tok.is(TT_LineComment) && Newlines > 0 ? tok::comment : tok::unknown,
+ CurrentPrefix, Tok.is(TT_LineComment) ? tok::comment : tok::unknown,
InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/Newlines == 0));
}
const tooling::Replacements &WhitespaceManager::generateReplacements() {
@@ -109,6 +107,7 @@
void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
+ Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
unsigned OriginalWhitespaceStart =
SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
@@ -119,11 +118,20 @@
Changes[i].PreviousLinePostfix.size() +
Changes[i - 1].CurrentLinePrefix.size();
+ // If there are multiple changes in this token, sum up all the changes until
+ // the end of the line.
+ if (Changes[i - 1].IsInsideToken)
+ LastOutsideTokenChange->TokenLength +=
+ Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
+ else
+ LastOutsideTokenChange = &Changes[i - 1];
+
Changes[i].PreviousEndOfTokenColumn =
Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
Changes[i - 1].IsTrailingComment =
- (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof) &&
+ (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof ||
+ (Changes[i].IsInsideToken && Changes[i].Kind == tok::comment)) &&
Changes[i - 1].Kind == tok::comment;
}
// FIXME: The last token is currently not always an eof token; in those
@@ -133,6 +141,10 @@
const WhitespaceManager::Change *LastBlockComment = nullptr;
for (auto &Change : Changes) {
+ // Reset the IsTrailingComment flag for changes inside of trailing comments
+ // so they don't get realigned later.
+ if (Change.IsInsideToken)
+ Change.IsTrailingComment = false;
Change.StartOfBlockComment = nullptr;
Change.IndentationOffset = 0;
if (Change.Kind == tok::comment) {
@@ -148,241 +160,183 @@
}
}
-// Walk through all of the changes and find sequences of "=" to align. To do
-// so, keep track of the lines and whether or not an "=" was found on align. If
-// a "=" is found on a line, extend the current sequence. If the current line
-// cannot be part of a sequence, e.g. because there is an empty line before it
-// or it contains non-assignments, finalize the previous sequence.
-//
-// FIXME: The code between assignment and declaration alignment is mostly
-// duplicated and would benefit from factorization.
+// Align a single sequence of tokens, see AlignTokens below.
+template <typename F>
+static void
+AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
+ SmallVector<WhitespaceManager::Change, 16> &Changes) {
+ bool FoundMatchOnLine = false;
+ int Shift = 0;
+ for (unsigned i = Start; i != End; ++i) {
+ if (Changes[i].NewlinesBefore > 0) {
+ FoundMatchOnLine = false;
+ Shift = 0;
+ }
+
+ // If this is the first matching token to be aligned, remember by how many
+ // spaces it has to be shifted, so the rest of the changes on the line are
+ // shifted by the same amount
+ if (!FoundMatchOnLine && Matches(Changes[i])) {
+ FoundMatchOnLine = true;
+ Shift = Column - Changes[i].StartOfTokenColumn;
+ Changes[i].Spaces += Shift;
+ }
+
+ assert(Shift >= 0);
+ Changes[i].StartOfTokenColumn += Shift;
+ if (i + 1 != Changes.size())
+ Changes[i + 1].PreviousEndOfTokenColumn += Shift;
+ }
+}
+
+// Walk through all of the changes and find sequences of matching tokens to
+// align. To do so, keep track of the lines and whether or not a matching token
+// was found on a line. If a matching token is found, extend the current
+// sequence. If the current line cannot be part of a sequence, e.g. because
+// there is an empty line before it or it contains only non-matching tokens,
+// finalize the previous sequence.
+template <typename F>
+static void AlignTokens(const FormatStyle &Style, F &&Matches,
+ SmallVector<WhitespaceManager::Change, 16> &Changes) {
+ unsigned MinColumn = 0;
+ unsigned MaxColumn = UINT_MAX;
+
+ // Line number of the start and the end of the current token sequence.
+ unsigned StartOfSequence = 0;
+ unsigned EndOfSequence = 0;
+
+ // Keep track of the nesting level of matching tokens, i.e. the number of
+ // surrounding (), [], or {}. We will only align a sequence of matching
+ // token that share the same scope depth.
+ //
+ // FIXME: This could use FormatToken::NestingLevel information, but there is
+ // an outstanding issue wrt the brace scopes.
+ unsigned NestingLevelOfLastMatch = 0;
+ unsigned NestingLevel = 0;
+
+ // Keep track of the number of commas before the matching tokens, we will only
+ // align a sequence of matching tokens if they are preceded by the same number
+ // of commas.
+ unsigned CommasBeforeLastMatch = 0;
+ unsigned CommasBeforeMatch = 0;
+
+ // Whether a matching token has been found on the current line.
+ bool FoundMatchOnLine = false;
+
+ // Aligns a sequence of matching tokens, on the MinColumn column.
+ //
+ // Sequences start from the first matching token to align, and end at the
+ // first token of the first line that doesn't need to be aligned.
+ //
+ // We need to adjust the StartOfTokenColumn of each Change that is on a line
+ // containing any matching token to be aligned and located after such token.
+ auto AlignCurrentSequence = [&] {
+ if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
+ AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
+ Changes);
+ MinColumn = 0;
+ MaxColumn = UINT_MAX;
+ StartOfSequence = 0;
+ EndOfSequence = 0;
+ };
+
+ for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ if (Changes[i].NewlinesBefore != 0) {
+ CommasBeforeMatch = 0;
+ EndOfSequence = i;
+ // If there is a blank line, or if the last line didn't contain any
+ // matching token, the sequence ends here.
+ if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine)
+ AlignCurrentSequence();
+
+ FoundMatchOnLine = false;
+ }
+
+ if (Changes[i].Kind == tok::comma) {
+ ++CommasBeforeMatch;
+ } else if (Changes[i].Kind == tok::r_brace ||
+ Changes[i].Kind == tok::r_paren ||
+ Changes[i].Kind == tok::r_square) {
+ --NestingLevel;
+ } else if (Changes[i].Kind == tok::l_brace ||
+ Changes[i].Kind == tok::l_paren ||
+ Changes[i].Kind == tok::l_square) {
+ // We want sequences to skip over child scopes if possible, but not the
+ // other way around.
+ NestingLevelOfLastMatch = std::min(NestingLevelOfLastMatch, NestingLevel);
+ ++NestingLevel;
+ }
+
+ if (!Matches(Changes[i]))
+ continue;
+
+ // If there is more than one matching token per line, or if the number of
+ // preceding commas, or the scope depth, do not match anymore, end the
+ // sequence.
+ if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch ||
+ NestingLevel != NestingLevelOfLastMatch)
+ AlignCurrentSequence();
+
+ CommasBeforeLastMatch = CommasBeforeMatch;
+ NestingLevelOfLastMatch = NestingLevel;
+ FoundMatchOnLine = true;
+
+ if (StartOfSequence == 0)
+ StartOfSequence = i;
+
+ unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
+ int LineLengthAfter = -Changes[i].Spaces;
+ for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
+ LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
+ unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
+
+ // If we are restricted by the maximum column width, end the sequence.
+ if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
+ CommasBeforeLastMatch != CommasBeforeMatch) {
+ AlignCurrentSequence();
+ StartOfSequence = i;
+ }
+
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+
+ EndOfSequence = Changes.size();
+ AlignCurrentSequence();
+}
+
void WhitespaceManager::alignConsecutiveAssignments() {
if (!Style.AlignConsecutiveAssignments)
return;
- unsigned MinColumn = 0;
- unsigned MaxColumn = UINT_MAX;
- unsigned StartOfSequence = 0;
- unsigned EndOfSequence = 0;
- bool FoundAssignmentOnLine = false;
- bool FoundLeftBraceOnLine = false;
- bool FoundLeftParenOnLine = false;
+ AlignTokens(Style,
+ [&](const Change &C) {
+ // Do not align on equal signs that are first on a line.
+ if (C.NewlinesBefore > 0)
+ return false;
- // Aligns a sequence of assignment tokens, on the MinColumn column.
- //
- // Sequences start from the first assignment token to align, and end at the
- // first token of the first line that doesn't need to be aligned.
- //
- // We need to adjust the StartOfTokenColumn of each Change that is on a line
- // containing any assignment to be aligned and located after such assignment
- auto AlignSequence = [&] {
- if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
- alignConsecutiveAssignments(StartOfSequence, EndOfSequence, MinColumn);
- MinColumn = 0;
- MaxColumn = UINT_MAX;
- StartOfSequence = 0;
- EndOfSequence = 0;
- };
+ // Do not align on equal signs that are last on a line.
+ if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
+ return false;
- for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
- if (Changes[i].NewlinesBefore != 0) {
- EndOfSequence = i;
- // If there is a blank line, if the last line didn't contain any
- // assignment, or if we found an open brace or paren, the sequence ends
- // here.
- if (Changes[i].NewlinesBefore > 1 || !FoundAssignmentOnLine ||
- FoundLeftBraceOnLine || FoundLeftParenOnLine) {
- // NB: In the latter case, the sequence should end at the beggining of
- // the previous line, but it doesn't really matter as there is no
- // assignment on it
- AlignSequence();
- }
-
- FoundAssignmentOnLine = false;
- FoundLeftBraceOnLine = false;
- FoundLeftParenOnLine = false;
- }
-
- // If there is more than one "=" per line, or if the "=" appears first on
- // the line of if it appears last, end the sequence
- if (Changes[i].Kind == tok::equal &&
- (FoundAssignmentOnLine || Changes[i].NewlinesBefore > 0 ||
- Changes[i + 1].NewlinesBefore > 0)) {
- AlignSequence();
- } else if (Changes[i].Kind == tok::r_brace) {
- if (!FoundLeftBraceOnLine)
- AlignSequence();
- FoundLeftBraceOnLine = false;
- } else if (Changes[i].Kind == tok::l_brace) {
- FoundLeftBraceOnLine = true;
- if (!FoundAssignmentOnLine)
- AlignSequence();
- } else if (Changes[i].Kind == tok::r_paren) {
- if (!FoundLeftParenOnLine)
- AlignSequence();
- FoundLeftParenOnLine = false;
- } else if (Changes[i].Kind == tok::l_paren) {
- FoundLeftParenOnLine = true;
- if (!FoundAssignmentOnLine)
- AlignSequence();
- } else if (!FoundAssignmentOnLine && !FoundLeftBraceOnLine &&
- !FoundLeftParenOnLine && Changes[i].Kind == tok::equal) {
- FoundAssignmentOnLine = true;
- if (StartOfSequence == 0)
- StartOfSequence = i;
-
- unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- int LineLengthAfter = -Changes[i].Spaces;
- for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
- LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
- unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
-
- if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) {
- AlignSequence();
- StartOfSequence = i;
- }
-
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
- }
- }
-
- EndOfSequence = Changes.size();
- AlignSequence();
+ return C.Kind == tok::equal;
+ },
+ Changes);
}
-void WhitespaceManager::alignConsecutiveAssignments(unsigned Start,
- unsigned End,
- unsigned Column) {
- bool FoundAssignmentOnLine = false;
- int Shift = 0;
- for (unsigned i = Start; i != End; ++i) {
- if (Changes[i].NewlinesBefore > 0) {
- FoundAssignmentOnLine = false;
- Shift = 0;
- }
-
- // If this is the first assignment to be aligned, remember by how many
- // spaces it has to be shifted, so the rest of the changes on the line are
- // shifted by the same amount
- if (!FoundAssignmentOnLine && Changes[i].Kind == tok::equal) {
- FoundAssignmentOnLine = true;
- Shift = Column - Changes[i].StartOfTokenColumn;
- Changes[i].Spaces += Shift;
- }
-
- assert(Shift >= 0);
- Changes[i].StartOfTokenColumn += Shift;
- if (i + 1 != Changes.size())
- Changes[i + 1].PreviousEndOfTokenColumn += Shift;
- }
-}
-
-// Walk through all of the changes and find sequences of declaration names to
-// align. To do so, keep track of the lines and whether or not a name was found
-// on align. If a name is found on a line, extend the current sequence. If the
-// current line cannot be part of a sequence, e.g. because there is an empty
-// line before it or it contains non-declarations, finalize the previous
-// sequence.
-//
-// FIXME: The code between assignment and declaration alignment is mostly
-// duplicated and would benefit from factorization.
void WhitespaceManager::alignConsecutiveDeclarations() {
if (!Style.AlignConsecutiveDeclarations)
return;
- unsigned MinColumn = 0;
- unsigned MaxColumn = UINT_MAX;
- unsigned StartOfSequence = 0;
- unsigned EndOfSequence = 0;
- bool FoundDeclarationOnLine = false;
- bool FoundLeftBraceOnLine = false;
- bool FoundLeftParenOnLine = false;
+ // FIXME: Currently we don't handle properly the PointerAlignment: Right
+ // The * and & are not aligned and are left dangling. Something has to be done
+ // about it, but it raises the question of alignment of code like:
+ // const char* const* v1;
+ // float const* v2;
+ // SomeVeryLongType const& v3;
- auto AlignSequence = [&] {
- if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
- alignConsecutiveDeclarations(StartOfSequence, EndOfSequence, MinColumn);
- MinColumn = 0;
- MaxColumn = UINT_MAX;
- StartOfSequence = 0;
- EndOfSequence = 0;
- };
-
- for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
- if (Changes[i].NewlinesBefore != 0) {
- EndOfSequence = i;
- if (Changes[i].NewlinesBefore > 1 || !FoundDeclarationOnLine ||
- FoundLeftBraceOnLine || FoundLeftParenOnLine)
- AlignSequence();
- FoundDeclarationOnLine = false;
- FoundLeftBraceOnLine = false;
- FoundLeftParenOnLine = false;
- }
-
- if (Changes[i].Kind == tok::r_brace) {
- if (!FoundLeftBraceOnLine)
- AlignSequence();
- FoundLeftBraceOnLine = false;
- } else if (Changes[i].Kind == tok::l_brace) {
- FoundLeftBraceOnLine = true;
- if (!FoundDeclarationOnLine)
- AlignSequence();
- } else if (Changes[i].Kind == tok::r_paren) {
- if (!FoundLeftParenOnLine)
- AlignSequence();
- FoundLeftParenOnLine = false;
- } else if (Changes[i].Kind == tok::l_paren) {
- FoundLeftParenOnLine = true;
- if (!FoundDeclarationOnLine)
- AlignSequence();
- } else if (!FoundDeclarationOnLine && !FoundLeftBraceOnLine &&
- !FoundLeftParenOnLine && Changes[i].IsStartOfDeclName) {
- FoundDeclarationOnLine = true;
- if (StartOfSequence == 0)
- StartOfSequence = i;
-
- unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- int LineLengthAfter = -Changes[i].Spaces;
- for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
- LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
- unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
-
- if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) {
- AlignSequence();
- StartOfSequence = i;
- }
-
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
- }
- }
-
- EndOfSequence = Changes.size();
- AlignSequence();
-}
-
-void WhitespaceManager::alignConsecutiveDeclarations(unsigned Start,
- unsigned End,
- unsigned Column) {
- bool FoundDeclarationOnLine = false;
- int Shift = 0;
- for (unsigned i = Start; i != End; ++i) {
- if (Changes[i].NewlinesBefore != 0) {
- FoundDeclarationOnLine = false;
- Shift = 0;
- }
-
- if (!FoundDeclarationOnLine && Changes[i].IsStartOfDeclName) {
- FoundDeclarationOnLine = true;
- Shift = Column - Changes[i].StartOfTokenColumn;
- Changes[i].Spaces += Shift;
- }
-
- assert(Shift >= 0);
- Changes[i].StartOfTokenColumn += Shift;
- if (i + 1 != Changes.size())
- Changes[i + 1].PreviousEndOfTokenColumn += Shift;
- }
+ AlignTokens(Style, [](Change const &C) { return C.IsStartOfDeclName; },
+ Changes);
}
void WhitespaceManager::alignTrailingComments() {
@@ -400,6 +354,12 @@
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+
+ // If we don't create a replacement for this change, we have to consider
+ // it to be immovable.
+ if (!Changes[i].CreateReplacement)
+ ChangeMaxColumn = ChangeMinColumn;
+
if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
ChangeMaxColumn -= 2;
// If this comment follows an } in column 0, it probably documents the
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 4075911..9ca9db6 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -81,7 +81,6 @@
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
-private:
/// \brief Represents a change before a token, a break inside a token,
/// or the layout of an unchanged token (or whitespace within).
struct Change {
@@ -110,7 +109,8 @@
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind,
- bool ContinuesPPDirective, bool IsStartOfDeclName);
+ bool ContinuesPPDirective, bool IsStartOfDeclName,
+ bool IsInsideToken);
bool CreateReplacement;
// Changes might be in the middle of a token, so we cannot just keep the
@@ -140,6 +140,10 @@
// comments. Uncompensated negative offset is truncated to 0.
int Spaces;
+ // If this change is inside of a token but not at the start of the token or
+ // directly after a newline.
+ bool IsInsideToken;
+
// \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
// \c EscapedNewlineColumn will be calculated in
// \c calculateLineBreakInformation.
@@ -160,6 +164,7 @@
int IndentationOffset;
};
+private:
/// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens
/// or token parts in a line and \c PreviousEndOfTokenColumn and
/// \c EscapedNewlineColumn for the first tokens or token parts in a line.
@@ -168,20 +173,9 @@
/// \brief Align consecutive assignments over all \c Changes.
void alignConsecutiveAssignments();
- /// \brief Align consecutive assignments from change \p Start to change \p End
- /// at
- /// the specified \p Column.
- void alignConsecutiveAssignments(unsigned Start, unsigned End,
- unsigned Column);
-
/// \brief Align consecutive declarations over all \c Changes.
void alignConsecutiveDeclarations();
- /// \brief Align consecutive declarations from change \p Start to change \p
- /// End at the specified \p Column.
- void alignConsecutiveDeclarations(unsigned Start, unsigned End,
- unsigned Column);
-
/// \brief Align trailing comments over all \c Changes.
void alignTrailingComments();
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 0d5dd53..e6ba292 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -1725,9 +1725,10 @@
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTFrontendAction *Action,
ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
- bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble,
- bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
- bool UserFilesAreVolatile, std::unique_ptr<ASTUnit> *ErrAST) {
+ bool OnlyLocalDecls, bool CaptureDiagnostics,
+ unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults,
+ bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile,
+ std::unique_ptr<ASTUnit> *ErrAST) {
assert(CI && "A CompilerInvocation is required");
std::unique_ptr<ASTUnit> OwnAST;
@@ -1746,8 +1747,8 @@
}
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
- if (PrecompilePreamble)
- AST->PreambleRebuildCounter = 2;
+ if (PrecompilePreambleAfterNParses > 0)
+ AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses;
AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->IncludeBriefCommentsInCodeCompletion
@@ -1864,7 +1865,7 @@
bool ASTUnit::LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool PrecompilePreamble) {
+ unsigned PrecompilePreambleAfterNParses) {
if (!Invocation)
return true;
@@ -1874,8 +1875,8 @@
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (PrecompilePreamble) {
- PreambleRebuildCounter = 2;
+ if (PrecompilePreambleAfterNParses > 0) {
+ PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
}
@@ -1894,9 +1895,10 @@
CompilerInvocation *CI,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
- bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble,
- TranslationUnitKind TUKind, bool CacheCodeCompletionResults,
- bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) {
+ bool OnlyLocalDecls, bool CaptureDiagnostics,
+ unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
+ bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
+ bool UserFilesAreVolatile) {
// Create the AST unit.
std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
@@ -1919,7 +1921,8 @@
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.get());
- if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble))
+ if (AST->LoadFromCompilerInvocation(PCHContainerOps,
+ PrecompilePreambleAfterNParses))
return nullptr;
return AST;
}
@@ -1930,12 +1933,11 @@
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
bool OnlyLocalDecls, bool CaptureDiagnostics,
ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName,
- bool PrecompilePreamble, TranslationUnitKind TUKind,
+ unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
bool UserFilesAreVolatile, bool ForSerialization,
- llvm::Optional<StringRef> ModuleFormat,
- std::unique_ptr<ASTUnit> *ErrAST) {
+ llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -2002,7 +2004,8 @@
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
- if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble)) {
+ if (AST->LoadFromCompilerInvocation(PCHContainerOps,
+ PrecompilePreambleAfterNParses)) {
// Some error occurred, if caller wants to examine diagnostics, pass it the
// ASTUnit.
if (ErrAST) {
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index af42a90..4768120 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -43,6 +43,7 @@
DEPENDS
ClangDriverOptions
+ intrinsics_gen
LINK_LIBS
clangAST
diff --git a/lib/Frontend/CodeGenOptions.cpp b/lib/Frontend/CodeGenOptions.cpp
index 75ee47f..50bb9f9 100644
--- a/lib/Frontend/CodeGenOptions.cpp
+++ b/lib/Frontend/CodeGenOptions.cpp
@@ -21,4 +21,12 @@
memcpy(CoverageVersion, "402*", 4);
}
+bool CodeGenOptions::isNoBuiltinFunc(const char *Name) const {
+ StringRef FuncName(Name);
+ for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i)
+ if (FuncName.equals(NoBuiltinFuncs[i]))
+ return true;
+ return false;
+}
+
} // end namespace clang
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 57ec9c4..d33b631 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -155,7 +155,6 @@
<< DiagOpts->DiagnosticLogFile << EC.message();
} else {
FileOS->SetUnbuffered();
- FileOS->SetUseAtomicWrites(true);
OS = FileOS.get();
StreamOwner = std::move(FileOS);
}
@@ -831,13 +830,13 @@
if (getFrontendOpts().ShowStats)
llvm::EnableStatistics();
- for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
+ for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
// Reset the ID tables if we are reusing the SourceManager and parsing
// regular files.
if (hasSourceManager() && !Act.isModelParsingAction())
getSourceManager().clearIDTables();
- if (Act.BeginSourceFile(*this, getFrontendOpts().Inputs[i])) {
+ if (Act.BeginSourceFile(*this, FIF)) {
Act.Execute();
Act.EndSourceFile();
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 720f222..d6d1c79 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,13 +8,14 @@
//===----------------------------------------------------------------------===//
#include "TestModuleFileExtension.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Util.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/Utils.h"
@@ -135,6 +136,20 @@
}
}
+static void getAllNoBuiltinFuncValues(ArgList &Args,
+ std::vector<std::string> &Funcs) {
+ SmallVector<const char *, 8> Values;
+ for (const auto &Arg : Args) {
+ const Option &O = Arg->getOption();
+ if (O.matches(options::OPT_fno_builtin_)) {
+ const char *FuncName = Arg->getValue();
+ if (Builtin::Context::isBuiltinFunc(FuncName))
+ Values.push_back(FuncName);
+ }
+ }
+ Funcs.insert(Funcs.end(), Values.begin(), Values.end());
+}
+
static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
using namespace options;
@@ -365,6 +380,7 @@
const TargetOptions &TargetOpts) {
using namespace options;
bool Success = true;
+ llvm::Triple Triple = llvm::Triple(TargetOpts.Triple);
unsigned OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
// TODO: This could be done in Driver
@@ -398,17 +414,36 @@
}
if (Arg *A = Args.getLastArg(OPT_debug_info_kind_EQ)) {
- Opts.setDebugInfo(
- llvm::StringSwitch<CodeGenOptions::DebugInfoKind>(A->getValue())
+ unsigned Val =
+ llvm::StringSwitch<unsigned>(A->getValue())
.Case("line-tables-only", CodeGenOptions::DebugLineTablesOnly)
.Case("limited", CodeGenOptions::LimitedDebugInfo)
- .Case("standalone", CodeGenOptions::FullDebugInfo));
+ .Case("standalone", CodeGenOptions::FullDebugInfo)
+ .Default(~0U);
+ if (Val == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+ << A->getValue();
+ else
+ Opts.setDebugInfo(static_cast<CodeGenOptions::DebugInfoKind>(Val));
+ }
+ if (Arg *A = Args.getLastArg(OPT_debugger_tuning_EQ)) {
+ unsigned Val = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("gdb", CodeGenOptions::DebuggerKindGDB)
+ .Case("lldb", CodeGenOptions::DebuggerKindLLDB)
+ .Case("sce", CodeGenOptions::DebuggerKindSCE)
+ .Default(~0U);
+ if (Val == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+ << A->getValue();
+ else
+ Opts.setDebuggerTuning(static_cast<CodeGenOptions::DebuggerKind>(Val));
}
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags);
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.EmitCodeView = Args.hasArg(OPT_gcodeview);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
+ Opts.DebugExplicitImport = Triple.isPS4CPU();
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
@@ -432,6 +467,8 @@
Opts.OptimizeSize = getOptimizationLevelSize(Args);
Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
Args.hasArg(OPT_ffreestanding));
+ if (Opts.SimplifyLibCalls)
+ getAllNoBuiltinFuncValues(Args, Opts.NoBuiltinFuncs);
Opts.UnrollLoops =
Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
(Opts.OptimizationLevel > 1 && !Opts.OptimizeSize));
@@ -453,7 +490,8 @@
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = getCodeModel(Args, Diags);
Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
- Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
+ Opts.DisableFPElim =
+ (Args.hasArg(OPT_mdisable_fp_elim) || Args.hasArg(OPT_pg));
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
@@ -489,6 +527,8 @@
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
+ Opts.IncrementalLinkerCompatible =
+ Args.hasArg(OPT_mincremental_linker_compatible);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
@@ -520,6 +560,12 @@
Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ);
Opts.EmitFunctionSummary = A && A->containsValue("thin");
+ if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
+ if (IK != IK_LLVM_IR)
+ Diags.Report(diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-x ir";
+ Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ);
+ }
Opts.MSVolatile = Args.hasArg(OPT_fms_volatile);
@@ -576,6 +622,8 @@
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeMemoryUseAfterDtor =
Args.hasArg(OPT_fsanitize_memory_use_after_dtor);
+ Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
+ Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -650,6 +698,7 @@
}
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
+ Opts.LinkerOptions = Args.getAllArgValues(OPT_linker_option);
bool NeedLocTracking = false;
if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {
@@ -1016,6 +1065,7 @@
Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file);
Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file);
Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ);
+ Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files);
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
@@ -1628,8 +1678,6 @@
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
Opts.ModulesLocalVisibility =
Args.hasArg(OPT_fmodules_local_submodule_visibility);
- Opts.ModulesHideInternalLinkage =
- !Args.hasArg(OPT_fno_modules_hide_internal_linkage);
Opts.ModulesSearchAll = Opts.Modules &&
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
@@ -1641,6 +1689,8 @@
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+ if (!Opts.NoBuiltin)
+ getAllNoBuiltinFuncValues(Args, Opts.NoBuiltinFuncs);
Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation);
@@ -1768,6 +1818,30 @@
Opts.OpenMP = Args.hasArg(options::OPT_fopenmp);
Opts.OpenMPUseTLS =
Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls);
+ Opts.OpenMPIsDevice =
+ Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device);
+
+ // Get the OpenMP target triples if any.
+ if (Arg *A = Args.getLastArg(options::OPT_omptargets_EQ)) {
+
+ for (unsigned i = 0; i < A->getNumValues(); ++i) {
+ llvm::Triple TT(A->getValue(i));
+
+ if (TT.getArch() == llvm::Triple::UnknownArch)
+ Diags.Report(clang::diag::err_drv_invalid_omp_target) << A->getValue(i);
+ else
+ Opts.OMPTargetTriples.push_back(TT);
+ }
+ }
+
+ // Get OpenMP host file path if any and report if a non existent file is
+ // found
+ if (Arg *A = Args.getLastArg(options::OPT_omp_host_ir_file_path)) {
+ Opts.OMPHostIRFile = A->getValue();
+ if (!llvm::sys::fs::exists(Opts.OMPHostIRFile))
+ Diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found)
+ << Opts.OMPHostIRFile;
+ }
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
@@ -2139,8 +2213,11 @@
code = hash_combine(code, I->first, I->second);
}
- // Extend the signature with the sysroot.
- code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
+ // Extend the signature with the sysroot and other header search options.
+ code = hash_combine(code, hsOpts.Sysroot,
+ hsOpts.ModuleFormat,
+ hsOpts.UseDebugInfo,
+ hsOpts.UseBuiltinIncludes,
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
hsOpts.UseLibcxx);
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 2afd23f..3019164 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -39,15 +39,13 @@
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
}
- SmallVector<const char *, 16> Args;
- Args.push_back("<clang>"); // FIXME: Remove dummy argument.
- Args.insert(Args.end(), ArgList.begin(), ArgList.end());
+ SmallVector<const char *, 16> Args(ArgList.begin(), ArgList.end());
// FIXME: Find a cleaner way to force the driver into restricted modes.
Args.push_back("-fsyntax-only");
// FIXME: We shouldn't have to pass in the path info.
- driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
+ driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
*Diags);
// Don't check that inputs exist, they may have been remapped.
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 6ef9a89..caf1f0d 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -308,34 +308,77 @@
/// A recursive function to trace all possible backtrace locations
/// to match the \p CaretLocFileID.
-static SourceLocation retrieveMacroLocation(SourceLocation Loc,
- FileID MacroFileID,
- FileID CaretFileID,
- bool getBeginLoc,
- const SourceManager *SM) {
- if (MacroFileID == CaretFileID) return Loc;
- if (!Loc.isMacroID()) return SourceLocation();
+static SourceLocation
+retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID,
+ FileID CaretFileID,
+ const SmallVectorImpl<FileID> &CommonArgExpansions,
+ bool IsBegin, const SourceManager *SM) {
+ assert(SM->getFileID(Loc) == MacroFileID);
+ if (MacroFileID == CaretFileID)
+ return Loc;
+ if (!Loc.isMacroID())
+ return SourceLocation();
SourceLocation MacroLocation, MacroArgLocation;
if (SM->isMacroArgExpansion(Loc)) {
- MacroLocation = SM->getImmediateSpellingLoc(Loc);
- MacroArgLocation = getBeginLoc ? SM->getImmediateExpansionRange(Loc).first
- : SM->getImmediateExpansionRange(Loc).second;
+ // Only look at the immediate spelling location of this macro argument if
+ // the other location in the source range is also present in that expansion.
+ if (std::binary_search(CommonArgExpansions.begin(),
+ CommonArgExpansions.end(), MacroFileID))
+ MacroLocation = SM->getImmediateSpellingLoc(Loc);
+ MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
} else {
- MacroLocation = getBeginLoc ? SM->getImmediateExpansionRange(Loc).first
- : SM->getImmediateExpansionRange(Loc).second;
+ MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
MacroArgLocation = SM->getImmediateSpellingLoc(Loc);
}
- MacroFileID = SM->getFileID(MacroLocation);
- MacroLocation = retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
- getBeginLoc, SM);
- if (MacroLocation.isValid()) return MacroLocation;
+ if (MacroLocation.isValid()) {
+ MacroFileID = SM->getFileID(MacroLocation);
+ MacroLocation =
+ retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
+ CommonArgExpansions, IsBegin, SM);
+ if (MacroLocation.isValid())
+ return MacroLocation;
+ }
MacroFileID = SM->getFileID(MacroArgLocation);
return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
- getBeginLoc, SM);
+ CommonArgExpansions, IsBegin, SM);
+}
+
+/// Walk up the chain of macro expansions and collect the FileIDs identifying the
+/// expansions.
+static void getMacroArgExpansionFileIDs(SourceLocation Loc,
+ SmallVectorImpl<FileID> &IDs,
+ bool IsBegin, const SourceManager *SM) {
+ while (Loc.isMacroID()) {
+ if (SM->isMacroArgExpansion(Loc)) {
+ IDs.push_back(SM->getFileID(Loc));
+ Loc = SM->getImmediateSpellingLoc(Loc);
+ } else {
+ auto ExpRange = SM->getImmediateExpansionRange(Loc);
+ Loc = IsBegin ? ExpRange.first : ExpRange.second;
+ }
+ }
+}
+
+/// Collect the expansions of the begin and end locations and compute the set
+/// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
+static void computeCommonMacroArgExpansionFileIDs(
+ SourceLocation Begin, SourceLocation End, const SourceManager *SM,
+ SmallVectorImpl<FileID> &CommonArgExpansions) {
+ SmallVector<FileID, 4> BeginArgExpansions;
+ SmallVector<FileID, 4> EndArgExpansions;
+ getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
+ getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
+ std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
+ std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
+ std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
+ EndArgExpansions.begin(), EndArgExpansions.end(),
+ std::back_inserter(CommonArgExpansions));
}
// Helper function to fix up source ranges. It takes in an array of ranges,
@@ -387,10 +430,12 @@
}
// Do the backtracking.
+ SmallVector<FileID, 4> CommonArgExpansions;
+ computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
- true /*getBeginLoc*/, SM);
+ CommonArgExpansions, /*IsBegin=*/true, SM);
End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
- false /*getBeginLoc*/, SM);
+ CommonArgExpansions, /*IsBegin=*/false, SM);
if (Begin.isInvalid() || End.isInvalid()) continue;
// Return the spelling location of the beginning and end of the range.
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 8b0eff2..0a70bbb 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -187,15 +187,17 @@
return std::error_code();
// Add includes for each of these headers.
- for (Module::Header &H : Module->Headers[Module::HK_Normal]) {
- Module->addTopHeader(H.Entry);
- // Use the path as specified in the module map file. We'll look for this
- // file relative to the module build directory (the directory containing
- // the module map file) so this will find the same file that we found
- // while parsing the module map.
- if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
- LangOpts, Module->IsExternC))
- return Err;
+ for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+ for (Module::Header &H : Module->Headers[HK]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
+ LangOpts, Module->IsExternC))
+ return Err;
+ }
}
// Note that Module->PrivateHeaders will not be a TopHeader.
@@ -277,6 +279,17 @@
return false;
}
+ // Set up embedding for any specified files. Do this before we load any
+ // source files, including the primary module map for the compilation.
+ for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+ if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+ CI.getSourceManager().setFileIsTransient(FE);
+ else
+ CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+ }
+ if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+ CI.getSourceManager().setAllFilesAreTransient(true);
+
// Parse the module map file.
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
if (HS.loadModuleMapFile(ModuleMap, IsSystem))
@@ -292,14 +305,6 @@
return false;
}
- // Set up embedding for any specified files.
- for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
- CI.getSourceManager().embedFileContentsInModule(FE);
- else
- CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
- }
-
// If we're being run from the command-line, the module build stack will not
// have been filled in yet, so complete it now in order to allow us to detect
// module cycles.
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 9123d53..0bc1169 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -92,7 +92,6 @@
delete OS;
} else {
OS->SetUnbuffered();
- OS->SetUseAtomicWrites(true);
OutputFile = OS;
OwnsOutputFile = true;
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 1de4627..26bab0d 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Config/config.h" // C_INCLUDE_DIRS
+#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -216,6 +217,7 @@
case llvm::Triple::Bitrig:
case llvm::Triple::NaCl:
case llvm::Triple::PS4:
+ case llvm::Triple::ELFIAMCU:
break;
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
@@ -318,6 +320,7 @@
case llvm::Triple::CloudABI:
case llvm::Triple::RTEMS:
case llvm::Triple::NaCl:
+ case llvm::Triple::ELFIAMCU:
break;
case llvm::Triple::PS4: {
// <isysroot> gets prepended later in AddPath().
@@ -408,10 +411,7 @@
}
break;
case llvm::Triple::DragonFly:
- if (llvm::sys::fs::exists("/usr/lib/gcc47"))
- AddPath("/usr/include/c++/4.7", CXXSystem, false);
- else
- AddPath("/usr/include/c++/4.4", CXXSystem, false);
+ AddPath("/usr/include/c++/5.0", CXXSystem, false);
break;
case llvm::Triple::OpenBSD: {
std::string t = triple.getTriple();
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index c82e897..15aa546 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -411,6 +411,8 @@
// Not "standard" per se, but available even with the -undef flag.
if (LangOpts.AsmPreprocessor)
Builder.defineMacro("__ASSEMBLER__");
+ if (LangOpts.CUDA)
+ Builder.defineMacro("__CUDA__");
}
/// Initialize the predefined C++ language feature test macros defined in
@@ -867,6 +869,8 @@
LangOpts.getGC() != LangOptions::NonGC) {
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
+ Builder.defineMacro("__autoreleasing", "");
+ Builder.defineMacro("__unsafe_unretained", "");
} else if (LangOpts.ObjC1) {
Builder.defineMacro("__weak", "__attribute__((objc_ownership(weak)))");
Builder.defineMacro("__strong", "__attribute__((objc_ownership(strong)))");
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 12c8524..fdeb04f 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -119,6 +119,7 @@
const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
+ void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
@@ -193,6 +194,11 @@
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->StaticDataMemberInstantiated(D);
}
+void MultiplexASTMutationListener::DefaultArgumentInstantiated(
+ const ParmVarDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DefaultArgumentInstantiated(D);
+}
void MultiplexASTMutationListener::AddedObjCCategoryToInterface(
const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {
@@ -311,9 +317,9 @@
Consumer->HandleImplicitImportDecl(D);
}
-void MultiplexConsumer::HandleLinkerOptionPragma(llvm::StringRef Opts) {
+void MultiplexConsumer::HandleLinkerOption(llvm::StringRef Opts) {
for (auto &Consumer : Consumers)
- Consumer->HandleLinkerOptionPragma(Opts);
+ Consumer->HandleLinkerOption(Opts);
}
void MultiplexConsumer::HandleDetectMismatch(llvm::StringRef Name, llvm::StringRef Value) {
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index be68d42..9fae7f0 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -1147,7 +1147,7 @@
ReplaceText(LocStart, 0, "// ");
}
- for (auto *I : CatDecl->properties())
+ for (auto *I : CatDecl->instance_properties())
RewriteProperty(I);
for (auto *I : CatDecl->instance_methods())
@@ -1171,7 +1171,7 @@
RewriteMethodDeclaration(I);
for (auto *I : PDecl->class_methods())
RewriteMethodDeclaration(I);
- for (auto *I : PDecl->properties())
+ for (auto *I : PDecl->instance_properties())
RewriteProperty(I);
// Lastly, comment out the @end.
@@ -1417,7 +1417,7 @@
// Mark this typedef as having been written into its c++ equivalent.
ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl());
- for (auto *I : ClassDecl->properties())
+ for (auto *I : ClassDecl->instance_properties())
RewriteProperty(I);
for (auto *I : ClassDecl->instance_methods())
RewriteMethodDeclaration(I);
@@ -6995,7 +6995,8 @@
PDecl->getNameAsString(), false);
// Protocol's property metadata.
- SmallVector<ObjCPropertyDecl *, 8> ProtocolProperties(PDecl->properties());
+ SmallVector<ObjCPropertyDecl *, 8> ProtocolProperties(
+ PDecl->instance_properties());
Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties,
/* Container */nullptr,
"_OBJC_PROTOCOL_PROPERTIES_",
@@ -7208,7 +7209,8 @@
IDecl->getNameAsString());
// Protocol's property metadata.
- SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties());
+ SmallVector<ObjCPropertyDecl *, 8> ClassProperties(
+ CDecl->instance_properties());
Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
/* Container */IDecl,
"_OBJC_$_PROP_LIST_",
@@ -7453,7 +7455,8 @@
FullCategoryName);
// Protocol's property metadata.
- SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties());
+ SmallVector<ObjCPropertyDecl *, 8> ClassProperties(
+ CDecl->instance_properties());
Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
/* Container */IDecl,
"_OBJC_$_PROP_LIST_",
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index e0ddadb..67b2bde 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -969,7 +969,7 @@
// FIXME: handle category headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
- for (auto *I : CatDecl->properties())
+ for (auto *I : CatDecl->instance_properties())
RewriteProperty(I);
for (auto *I : CatDecl->instance_methods())
RewriteMethodDeclaration(I);
@@ -992,7 +992,7 @@
RewriteMethodDeclaration(I);
for (auto *I : PDecl->class_methods())
RewriteMethodDeclaration(I);
- for (auto *I : PDecl->properties())
+ for (auto *I : PDecl->instance_properties())
RewriteProperty(I);
// Lastly, comment out the @end.
@@ -1210,7 +1210,7 @@
}
RewriteObjCInternalStruct(ClassDecl, ResultStr);
- for (auto *I : ClassDecl->properties())
+ for (auto *I : ClassDecl->instance_properties())
RewriteProperty(I);
for (auto *I : ClassDecl->instance_methods())
RewriteMethodDeclaration(I);
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 55df936..7331d77 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -186,9 +186,7 @@
Regex(RegexStr) { }
bool isValid(std::string &Error) override {
- if (Regex.isValid(Error))
- return true;
- return false;
+ return Regex.isValid(Error);
}
bool match(StringRef S) override {
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 8c06b27..bbe0688 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -12,9 +12,11 @@
avx512vlintrin.h
avx512dqintrin.h
avx512vldqintrin.h
+ pkuintrin.h
avxintrin.h
bmi2intrin.h
bmiintrin.h
+ __clang_cuda_runtime_wrapper.h
cpuid.h
cuda_builtin_vars.h
emmintrin.h
diff --git a/lib/Headers/__clang_cuda_runtime_wrapper.h b/lib/Headers/__clang_cuda_runtime_wrapper.h
new file mode 100644
index 0000000..8e5f033
--- /dev/null
+++ b/lib/Headers/__clang_cuda_runtime_wrapper.h
@@ -0,0 +1,216 @@
+/*===---- __clang_cuda_runtime_wrapper.h - CUDA runtime support -------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/*
+ * WARNING: This header is intended to be directly -include'd by
+ * the compiler and is not supposed to be included by users.
+ *
+ * CUDA headers are implemented in a way that currently makes it
+ * impossible for user code to #include directly when compiling with
+ * Clang. They present different view of CUDA-supplied functions
+ * depending on where in NVCC's compilation pipeline the headers are
+ * included. Neither of these modes provides function definitions with
+ * correct attributes, so we use preprocessor to force the headers
+ * into a form that Clang can use.
+ *
+ * Similarly to NVCC which -include's cuda_runtime.h, Clang -include's
+ * this file during every CUDA compilation.
+ */
+
+#ifndef __CLANG_CUDA_RUNTIME_WRAPPER_H__
+#define __CLANG_CUDA_RUNTIME_WRAPPER_H__
+
+#if defined(__CUDA__) && defined(__clang__)
+
+// Include some standard headers to avoid CUDA headers including them
+// while some required macros (like __THROW) are in a weird state.
+#include <stdlib.h>
+#include <cmath>
+
+// Preserve common macros that will be changed below by us or by CUDA
+// headers.
+#pragma push_macro("__THROW")
+#pragma push_macro("__CUDA_ARCH__")
+
+// WARNING: Preprocessor hacks below are based on specific details of
+// CUDA-7.x headers and are not expected to work with any other
+// version of CUDA headers.
+#include "cuda.h"
+#if !defined(CUDA_VERSION)
+#error "cuda.h did not define CUDA_VERSION"
+#elif CUDA_VERSION < 7000 || CUDA_VERSION > 7050
+#error "Unsupported CUDA version!"
+#endif
+
+// Make largest subset of device functions available during host
+// compilation -- SM_35 for the time being.
+#ifndef __CUDA_ARCH__
+#define __CUDA_ARCH__ 350
+#endif
+
+#include "cuda_builtin_vars.h"
+
+// No need for device_launch_parameters.h as cuda_builtin_vars.h above
+// has taken care of builtin variables declared in the file.
+#define __DEVICE_LAUNCH_PARAMETERS_H__
+
+// {math,device}_functions.h only have declarations of the
+// functions. We don't need them as we're going to pull in their
+// definitions from .hpp files.
+#define __DEVICE_FUNCTIONS_H__
+#define __MATH_FUNCTIONS_H__
+
+#undef __CUDACC__
+#define __CUDABE__
+// Disables definitions of device-side runtime support stubs in
+// cuda_device_runtime_api.h
+#define __CUDADEVRT_INTERNAL__
+#include "host_config.h"
+#include "host_defines.h"
+#include "driver_types.h"
+#include "common_functions.h"
+#undef __CUDADEVRT_INTERNAL__
+
+#undef __CUDABE__
+#define __CUDACC__
+#include "cuda_runtime.h"
+
+#undef __CUDACC__
+#define __CUDABE__
+
+// CUDA headers use __nvvm_memcpy and __nvvm_memset which Clang does
+// not have at the moment. Emulate them with a builtin memcpy/memset.
+#define __nvvm_memcpy(s,d,n,a) __builtin_memcpy(s,d,n)
+#define __nvvm_memset(d,c,n,a) __builtin_memset(d,c,n)
+
+#include "crt/host_runtime.h"
+#include "crt/device_runtime.h"
+// device_runtime.h defines __cxa_* macros that will conflict with
+// cxxabi.h.
+// FIXME: redefine these as __device__ functions.
+#undef __cxa_vec_ctor
+#undef __cxa_vec_cctor
+#undef __cxa_vec_dtor
+#undef __cxa_vec_new2
+#undef __cxa_vec_new3
+#undef __cxa_vec_delete2
+#undef __cxa_vec_delete
+#undef __cxa_vec_delete3
+#undef __cxa_pure_virtual
+
+// We need decls for functions in CUDA's libdevice with __device__
+// attribute only. Alas they come either as __host__ __device__ or
+// with no attributes at all. To work around that, define __CUDA_RTC__
+// which produces HD variant and undef __host__ which gives us desided
+// decls with __device__ attribute.
+#pragma push_macro("__host__")
+#define __host__
+#define __CUDACC_RTC__
+#include "device_functions_decls.h"
+#undef __CUDACC_RTC__
+
+// Temporarily poison __host__ macro to ensure it's not used by any of
+// the headers we're about to include.
+#define __host__ UNEXPECTED_HOST_ATTRIBUTE
+
+// device_functions.hpp and math_functions*.hpp use 'static
+// __forceinline__' (with no __device__) for definitions of device
+// functions. Temporarily redefine __forceinline__ to include
+// __device__.
+#pragma push_macro("__forceinline__")
+#define __forceinline__ __device__ __inline__ __attribute__((always_inline))
+#include "device_functions.hpp"
+#include "math_functions.hpp"
+#include "math_functions_dbl_ptx3.hpp"
+#pragma pop_macro("__forceinline__")
+
+// Pull in host-only functions that are only available when neither
+// __CUDACC__ nor __CUDABE__ are defined.
+#undef __MATH_FUNCTIONS_HPP__
+#undef __CUDABE__
+#include "math_functions.hpp"
+// Alas, additional overloads for these functions are hard to get to.
+// Considering that we only need these overloads for a few functions,
+// we can provide them here.
+static inline float rsqrt(float a) { return rsqrtf(a); }
+static inline float rcbrt(float a) { return rcbrtf(a); }
+static inline float sinpi(float a) { return sinpif(a); }
+static inline float cospi(float a) { return cospif(a); }
+static inline void sincospi(float a, float *b, float *c) {
+ return sincospi(a, b, c);
+}
+static inline float erfcinv(float a) { return erfcinvf(a); }
+static inline float normcdfinv(float a) { return normcdfinvf(a); }
+static inline float normcdf(float a) { return normcdff(a); }
+static inline float erfcx(float a) { return erfcxf(a); }
+
+// For some reason single-argument variant is not always declared by
+// CUDA headers. Alas, device_functions.hpp included below needs it.
+static inline __device__ void __brkpt(int c) { __brkpt(); }
+
+// Now include *.hpp with definitions of various GPU functions. Alas,
+// a lot of thins get declared/defined with __host__ attribute which
+// we don't want and we have to define it out. We also have to include
+// {device,math}_functions.hpp again in order to extract the other
+// branch of #if/else inside.
+
+#define __host__
+#undef __CUDABE__
+#define __CUDACC__
+#undef __DEVICE_FUNCTIONS_HPP__
+#include "device_functions.hpp"
+#include "device_atomic_functions.hpp"
+#include "sm_20_atomic_functions.hpp"
+#include "sm_32_atomic_functions.hpp"
+#include "sm_20_intrinsics.hpp"
+// sm_30_intrinsics.h has declarations that use default argument, so
+// we have to include it and it will in turn include .hpp
+#include "sm_30_intrinsics.h"
+#include "sm_32_intrinsics.hpp"
+#undef __MATH_FUNCTIONS_HPP__
+#include "math_functions.hpp"
+#pragma pop_macro("__host__")
+
+#include "texture_indirect_functions.h"
+
+// Restore state of __CUDA_ARCH__ and __THROW we had on entry.
+#pragma pop_macro("__CUDA_ARCH__")
+#pragma pop_macro("__THROW")
+
+// Set up compiler macros expected to be seen during compilation.
+#undef __CUDABE__
+#define __CUDACC__
+#define __NVCC__
+
+#if defined(__CUDA_ARCH__)
+// We need to emit IR declaration for non-existing __nvvm_reflect() to
+// let backend know that it should be treated as const nothrow
+// function which is what NVVMReflect pass expects to see.
+extern "C" __device__ __attribute__((const)) int __nvvm_reflect(const void *);
+static __device__ __attribute__((used)) int __nvvm_reflect_anchor() {
+ return __nvvm_reflect("NONE");
+}
+#endif
+
+#endif // __CUDA__
+#endif // __CLANG_CUDA_RUNTIME_WRAPPER_H__
diff --git a/lib/Headers/__wmmintrin_aes.h b/lib/Headers/__wmmintrin_aes.h
index 81b2b8d..100799e 100644
--- a/lib/Headers/__wmmintrin_aes.h
+++ b/lib/Headers/__wmmintrin_aes.h
@@ -59,7 +59,7 @@
}
#define _mm_aeskeygenassist_si128(C, R) \
- __builtin_ia32_aeskeygenassist128((C), (R))
+ (__m128i)__builtin_ia32_aeskeygenassist128((__v2di)(__m128i)(C), (int)(R))
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/__wmmintrin_pclmul.h b/lib/Headers/__wmmintrin_pclmul.h
index 48a85d2..68e944e 100644
--- a/lib/Headers/__wmmintrin_pclmul.h
+++ b/lib/Headers/__wmmintrin_pclmul.h
@@ -1,4 +1,4 @@
-/*===---- __wmmintrin_pclmul.h - AES intrinsics ----------------------------===
+/*===---- __wmmintrin_pclmul.h - PCMUL intrinsics ---------------------------===
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index c39156e..a5b4f74 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -27,7 +27,7 @@
#error "AltiVec support not enabled"
#endif
-/* constants for mapping CR6 bits to predicate result. */
+/* Constants for mapping CR6 bits to predicate result. */
#define __CR6_EQ 0
#define __CR6_EQ_REV 1
@@ -1891,6 +1891,22 @@
return __builtin_altivec_vcfux((vector int)__a, __b);
}
+#ifdef __VSX__
+static vector double __ATTRS_o_ai vec_ctf(vector unsigned long long __a,
+ int __b) {
+ vector double __ret = __builtin_convertvector(__a, vector double);
+ __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
+ return __ret;
+}
+
+static vector double __ATTRS_o_ai vec_ctf(vector signed long long __a,
+ int __b) {
+ vector double __ret = __builtin_convertvector(__a, vector double);
+ __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
+ return __ret;
+}
+#endif
+
/* vec_vcfsx */
static vector float __attribute__((__always_inline__))
@@ -1907,11 +1923,18 @@
/* vec_cts */
-static vector int __attribute__((__always_inline__))
-vec_cts(vector float __a, int __b) {
+static vector int __ATTRS_o_ai vec_cts(vector float __a, int __b) {
return __builtin_altivec_vctsxs(__a, __b);
}
+#ifdef __VSX__
+static vector signed long long __ATTRS_o_ai vec_cts(vector double __a,
+ int __b) {
+ __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
+ return __builtin_convertvector(__a, vector signed long long);
+}
+#endif
+
/* vec_vctsxs */
static vector int __attribute__((__always_inline__))
@@ -1921,11 +1944,18 @@
/* vec_ctu */
-static vector unsigned int __attribute__((__always_inline__))
-vec_ctu(vector float __a, int __b) {
+static vector unsigned int __ATTRS_o_ai vec_ctu(vector float __a, int __b) {
return __builtin_altivec_vctuxs(__a, __b);
}
+#ifdef __VSX__
+static vector unsigned long long __ATTRS_o_ai vec_ctu(vector double __a,
+ int __b) {
+ __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
+ return __builtin_convertvector(__a, vector unsigned long long);
+}
+#endif
+
/* vec_vctuxs */
static vector unsigned int __attribute__((__always_inline__))
diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h
index 73a7e76..4be1d09 100644
--- a/lib/Headers/arm_acle.h
+++ b/lib/Headers/arm_acle.h
@@ -175,14 +175,18 @@
return __ror(__rev(t), 16);
}
-static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
- __rev16l(unsigned long t) {
- return __rorl(__revl(t), sizeof(long) / 2);
-}
-
static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
__rev16ll(uint64_t t) {
- return __rorll(__revll(t), 32);
+ return (((uint64_t)__rev16(t >> 32)) << 32) | __rev16(t);
+}
+
+static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
+ __rev16l(unsigned long t) {
+#if __SIZEOF_LONG__ == 4
+ return __rev16(t);
+#else
+ return __rev16ll(t);
+#endif
}
/* REVSH */
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index b2a92f1..f786572 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -124,10 +124,9 @@
return (__m256i)__builtin_ia32_paddusw256((__v16hi)__a, (__v16hi)__b);
}
-#define _mm256_alignr_epi8(a, b, n) __extension__ ({ \
- __m256i __a = (a); \
- __m256i __b = (b); \
- (__m256i)__builtin_ia32_palignr256((__v32qi)__a, (__v32qi)__b, (n)); })
+#define _mm256_alignr_epi8(a, b, n) __extension__ ({ \
+ (__m256i)__builtin_ia32_palignr256((__v32qi)(__m256i)(a), \
+ (__v32qi)(__m256i)(b), (n)); })
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_and_si256(__m256i __a, __m256i __b)
@@ -160,20 +159,19 @@
(__v32qi)__M);
}
-#define _mm256_blend_epi16(V1, V2, M) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m256i __V2 = (V2); \
- (__m256i)__builtin_shufflevector((__v16hi)__V1, (__v16hi)__V2, \
- (((M) & 0x01) ? 16 : 0), \
- (((M) & 0x02) ? 17 : 1), \
- (((M) & 0x04) ? 18 : 2), \
- (((M) & 0x08) ? 19 : 3), \
- (((M) & 0x10) ? 20 : 4), \
- (((M) & 0x20) ? 21 : 5), \
- (((M) & 0x40) ? 22 : 6), \
- (((M) & 0x80) ? 23 : 7), \
- (((M) & 0x01) ? 24 : 8), \
- (((M) & 0x02) ? 25 : 9), \
+#define _mm256_blend_epi16(V1, V2, M) __extension__ ({ \
+ (__m256i)__builtin_shufflevector((__v16hi)(__m256i)(V1), \
+ (__v16hi)(__m256i)(V2), \
+ (((M) & 0x01) ? 16 : 0), \
+ (((M) & 0x02) ? 17 : 1), \
+ (((M) & 0x04) ? 18 : 2), \
+ (((M) & 0x08) ? 19 : 3), \
+ (((M) & 0x10) ? 20 : 4), \
+ (((M) & 0x20) ? 21 : 5), \
+ (((M) & 0x40) ? 22 : 6), \
+ (((M) & 0x80) ? 23 : 7), \
+ (((M) & 0x01) ? 24 : 8), \
+ (((M) & 0x02) ? 25 : 9), \
(((M) & 0x04) ? 26 : 10), \
(((M) & 0x08) ? 27 : 11), \
(((M) & 0x10) ? 28 : 12), \
@@ -490,8 +488,8 @@
}
#define _mm256_shuffle_epi32(a, imm) __extension__ ({ \
- __m256i __a = (a); \
- (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)_mm256_set1_epi32(0), \
+ (__m256i)__builtin_shufflevector((__v8si)(__m256i)(a), \
+ (__v8si)_mm256_setzero_si256(), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
4 + (((imm) & 0x03) >> 0), \
@@ -500,8 +498,8 @@
4 + (((imm) & 0xc0) >> 6)); })
#define _mm256_shufflehi_epi16(a, imm) __extension__ ({ \
- __m256i __a = (a); \
- (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)_mm256_set1_epi16(0), \
+ (__m256i)__builtin_shufflevector((__v16hi)(__m256i)(a), \
+ (__v16hi)_mm256_setzero_si256(), \
0, 1, 2, 3, \
4 + (((imm) & 0x03) >> 0), \
4 + (((imm) & 0x0c) >> 2), \
@@ -514,8 +512,8 @@
12 + (((imm) & 0xc0) >> 6)); })
#define _mm256_shufflelo_epi16(a, imm) __extension__ ({ \
- __m256i __a = (a); \
- (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)_mm256_set1_epi16(0), \
+ (__m256i)__builtin_shufflevector((__v16hi)(__m256i)(a), \
+ (__v16hi)_mm256_setzero_si256(), \
(imm) & 0x3,((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
4, 5, 6, 7, \
@@ -544,8 +542,7 @@
}
#define _mm256_slli_si256(a, count) __extension__ ({ \
- __m256i __a = (a); \
- (__m256i)__builtin_ia32_pslldqi256(__a, (count)*8); })
+ (__m256i)__builtin_ia32_pslldqi256((__m256i)(a), (count)*8); })
#define _mm256_bslli_epi128(a, count) _mm256_slli_si256((a), (count))
@@ -610,8 +607,7 @@
}
#define _mm256_srli_si256(a, count) __extension__ ({ \
- __m256i __a = (a); \
- (__m256i)__builtin_ia32_psrldqi256(__a, (count)*8); })
+ (__m256i)__builtin_ia32_psrldqi256((__m256i)(a), (count)*8); })
#define _mm256_bsrli_epi128(a, count) _mm256_srli_si256((a), (count))
@@ -790,18 +786,16 @@
}
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
- __m128i __V1 = (V1); \
- __m128i __V2 = (V2); \
- (__m128i)__builtin_shufflevector((__v4si)__V1, (__v4si)__V2, \
+ (__m128i)__builtin_shufflevector((__v4si)(__m128i)(V1), \
+ (__v4si)(__m128i)(V2), \
(((M) & 0x01) ? 4 : 0), \
(((M) & 0x02) ? 5 : 1), \
(((M) & 0x04) ? 6 : 2), \
(((M) & 0x08) ? 7 : 3)); })
#define _mm256_blend_epi32(V1, V2, M) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m256i __V2 = (V2); \
- (__m256i)__builtin_shufflevector((__v8si)__V1, (__v8si)__V2, \
+ (__m256i)__builtin_shufflevector((__v8si)(__m256i)(V1), \
+ (__v8si)(__m256i)(V2), \
(((M) & 0x01) ? 8 : 0), \
(((M) & 0x02) ? 9 : 1), \
(((M) & 0x04) ? 10 : 2), \
@@ -867,43 +861,39 @@
}
#define _mm256_permute4x64_pd(V, M) __extension__ ({ \
- __m256d __V = (V); \
- (__m256d)__builtin_shufflevector((__v4df)__V, (__v4df) _mm256_setzero_pd(), \
+ (__m256d)__builtin_shufflevector((__v4df)(__m256d)(V), \
+ (__v4df)_mm256_setzero_pd(), \
(M) & 0x3, ((M) & 0xc) >> 2, \
((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); })
static __inline__ __m256 __DEFAULT_FN_ATTRS
-_mm256_permutevar8x32_ps(__m256 __a, __m256 __b)
+_mm256_permutevar8x32_ps(__m256 __a, __m256i __b)
{
- return (__m256)__builtin_ia32_permvarsf256((__v8sf)__a, (__v8sf)__b);
+ return (__m256)__builtin_ia32_permvarsf256((__v8sf)__a, (__v8si)__b);
}
#define _mm256_permute4x64_epi64(V, M) __extension__ ({ \
- __m256i __V = (V); \
- (__m256i)__builtin_shufflevector((__v4di)__V, (__v4di) _mm256_setzero_si256(), \
+ (__m256i)__builtin_shufflevector((__v4di)(__m256i)(V), \
+ (__v4di)_mm256_setzero_si256(), \
(M) & 0x3, ((M) & 0xc) >> 2, \
((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); })
#define _mm256_permute2x128_si256(V1, V2, M) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m256i __V2 = (V2); \
- (__m256i)__builtin_ia32_permti256(__V1, __V2, (M)); })
+ (__m256i)__builtin_ia32_permti256((__m256i)(V1), (__m256i)(V2), (M)); })
#define _mm256_extracti128_si256(V, M) __extension__ ({ \
- (__m128i)__builtin_shufflevector( \
- (__v4di)(V), \
- (__v4di)(_mm256_setzero_si256()), \
- (((M) & 1) ? 2 : 0), \
- (((M) & 1) ? 3 : 1) );})
+ (__m128i)__builtin_shufflevector((__v4di)(__m256i)(V), \
+ (__v4di)_mm256_setzero_si256(), \
+ (((M) & 1) ? 2 : 0), \
+ (((M) & 1) ? 3 : 1) ); })
#define _mm256_inserti128_si256(V1, V2, M) __extension__ ({ \
- (__m256i)__builtin_shufflevector( \
- (__v4di)(V1), \
- (__v4di)_mm256_castsi128_si256((__m128i)(V2)), \
- (((M) & 1) ? 0 : 4), \
- (((M) & 1) ? 1 : 5), \
- (((M) & 1) ? 4 : 2), \
- (((M) & 1) ? 5 : 3) );})
+ (__m256i)__builtin_shufflevector((__v4di)(__m256i)(V1), \
+ (__v4di)_mm256_castsi128_si256((__m128i)(V2)), \
+ (((M) & 1) ? 0 : 4), \
+ (((M) & 1) ? 1 : 5), \
+ (((M) & 1) ? 4 : 2), \
+ (((M) & 1) ? 5 : 3) ); })
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskload_epi32(int const *__X, __m256i __M)
@@ -1014,244 +1004,211 @@
}
#define _mm_mask_i32gather_pd(a, m, i, mask, s) __extension__ ({ \
- __m128d __a = (a); \
- double const *__m = (m); \
- __m128i __i = (i); \
- __m128d __mask = (mask); \
- (__m128d)__builtin_ia32_gatherd_pd((__v2df)__a, (const __v2df *)__m, \
- (__v4si)__i, (__v2df)__mask, (s)); })
+ (__m128d)__builtin_ia32_gatherd_pd((__v2df)(__m128i)(a), \
+ (double const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v2df)(__m128d)(mask), (s)); })
#define _mm256_mask_i32gather_pd(a, m, i, mask, s) __extension__ ({ \
- __m256d __a = (a); \
- double const *__m = (m); \
- __m128i __i = (i); \
- __m256d __mask = (mask); \
- (__m256d)__builtin_ia32_gatherd_pd256((__v4df)__a, (const __v4df *)__m, \
- (__v4si)__i, (__v4df)__mask, (s)); })
+ (__m256d)__builtin_ia32_gatherd_pd256((__v4df)(__m256d)(a), \
+ (double const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4df)(__m256d)(mask), (s)); })
#define _mm_mask_i64gather_pd(a, m, i, mask, s) __extension__ ({ \
- __m128d __a = (a); \
- double const *__m = (m); \
- __m128i __i = (i); \
- __m128d __mask = (mask); \
- (__m128d)__builtin_ia32_gatherq_pd((__v2df)__a, (const __v2df *)__m, \
- (__v2di)__i, (__v2df)__mask, (s)); })
+ (__m128d)__builtin_ia32_gatherq_pd((__v2df)(__m128d)(a), \
+ (double const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v2df)(__m128d)(mask), (s)); })
#define _mm256_mask_i64gather_pd(a, m, i, mask, s) __extension__ ({ \
- __m256d __a = (a); \
- double const *__m = (m); \
- __m256i __i = (i); \
- __m256d __mask = (mask); \
- (__m256d)__builtin_ia32_gatherq_pd256((__v4df)__a, (const __v4df *)__m, \
- (__v4di)__i, (__v4df)__mask, (s)); })
+ (__m256d)__builtin_ia32_gatherq_pd256((__v4df)(__m256d)(a), \
+ (double const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4df)(__m256d)(mask), (s)); })
#define _mm_mask_i32gather_ps(a, m, i, mask, s) __extension__ ({ \
- __m128 __a = (a); \
- float const *__m = (m); \
- __m128i __i = (i); \
- __m128 __mask = (mask); \
- (__m128)__builtin_ia32_gatherd_ps((__v4sf)__a, (const __v4sf *)__m, \
- (__v4si)__i, (__v4sf)__mask, (s)); })
+ (__m128)__builtin_ia32_gatherd_ps((__v4sf)(__m128)(a), \
+ (float const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4sf)(__m128)(mask), (s)); })
#define _mm256_mask_i32gather_ps(a, m, i, mask, s) __extension__ ({ \
- __m256 __a = (a); \
- float const *__m = (m); \
- __m256i __i = (i); \
- __m256 __mask = (mask); \
- (__m256)__builtin_ia32_gatherd_ps256((__v8sf)__a, (const __v8sf *)__m, \
- (__v8si)__i, (__v8sf)__mask, (s)); })
+ (__m256)__builtin_ia32_gatherd_ps256((__v8sf)(__m256)(a), \
+ (float const *)(m), \
+ (__v8si)(__m256i)(i), \
+ (__v8sf)(__m256)(mask), (s)); })
#define _mm_mask_i64gather_ps(a, m, i, mask, s) __extension__ ({ \
- __m128 __a = (a); \
- float const *__m = (m); \
- __m128i __i = (i); \
- __m128 __mask = (mask); \
- (__m128)__builtin_ia32_gatherq_ps((__v4sf)__a, (const __v4sf *)__m, \
- (__v2di)__i, (__v4sf)__mask, (s)); })
+ (__m128)__builtin_ia32_gatherq_ps((__v4sf)(__m128)(a), \
+ (float const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v4sf)(__m128)(mask), (s)); })
#define _mm256_mask_i64gather_ps(a, m, i, mask, s) __extension__ ({ \
- __m128 __a = (a); \
- float const *__m = (m); \
- __m256i __i = (i); \
- __m128 __mask = (mask); \
- (__m128)__builtin_ia32_gatherq_ps256((__v4sf)__a, (const __v4sf *)__m, \
- (__v4di)__i, (__v4sf)__mask, (s)); })
+ (__m128)__builtin_ia32_gatherq_ps256((__v4sf)(__m128)(a), \
+ (float const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4sf)(__m128)(mask), (s)); })
#define _mm_mask_i32gather_epi32(a, m, i, mask, s) __extension__ ({ \
- __m128i __a = (a); \
- int const *__m = (m); \
- __m128i __i = (i); \
- __m128i __mask = (mask); \
- (__m128i)__builtin_ia32_gatherd_d((__v4si)__a, (const __v4si *)__m, \
- (__v4si)__i, (__v4si)__mask, (s)); })
+ (__m128i)__builtin_ia32_gatherd_d((__v4si)(__m128i)(a), \
+ (int const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4si)(__m128i)(mask), (s)); })
#define _mm256_mask_i32gather_epi32(a, m, i, mask, s) __extension__ ({ \
- __m256i __a = (a); \
- int const *__m = (m); \
- __m256i __i = (i); \
- __m256i __mask = (mask); \
- (__m256i)__builtin_ia32_gatherd_d256((__v8si)__a, (const __v8si *)__m, \
- (__v8si)__i, (__v8si)__mask, (s)); })
+ (__m256i)__builtin_ia32_gatherd_d256((__v8si)(__m256i)(a), \
+ (int const *)(m), \
+ (__v8si)(__m256i)(i), \
+ (__v8si)(__m256i)(mask), (s)); })
#define _mm_mask_i64gather_epi32(a, m, i, mask, s) __extension__ ({ \
- __m128i __a = (a); \
- int const *__m = (m); \
- __m128i __i = (i); \
- __m128i __mask = (mask); \
- (__m128i)__builtin_ia32_gatherq_d((__v4si)__a, (const __v4si *)__m, \
- (__v2di)__i, (__v4si)__mask, (s)); })
+ (__m128i)__builtin_ia32_gatherq_d((__v4si)(__m128i)(a), \
+ (int const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v4si)(__m128i)(mask), (s)); })
#define _mm256_mask_i64gather_epi32(a, m, i, mask, s) __extension__ ({ \
- __m128i __a = (a); \
- int const *__m = (m); \
- __m256i __i = (i); \
- __m128i __mask = (mask); \
- (__m128i)__builtin_ia32_gatherq_d256((__v4si)__a, (const __v4si *)__m, \
- (__v4di)__i, (__v4si)__mask, (s)); })
+ (__m128i)__builtin_ia32_gatherq_d256((__v4si)(__m128i)(a), \
+ (int const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4si)(__m128i)(mask), (s)); })
#define _mm_mask_i32gather_epi64(a, m, i, mask, s) __extension__ ({ \
- __m128i __a = (a); \
- long long const *__m = (m); \
- __m128i __i = (i); \
- __m128i __mask = (mask); \
- (__m128i)__builtin_ia32_gatherd_q((__v2di)__a, (const __v2di *)__m, \
- (__v4si)__i, (__v2di)__mask, (s)); })
+ (__m128i)__builtin_ia32_gatherd_q((__v2di)(__m128i)(a), \
+ (long long const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v2di)(__m128i)(mask), (s)); })
#define _mm256_mask_i32gather_epi64(a, m, i, mask, s) __extension__ ({ \
- __m256i __a = (a); \
- long long const *__m = (m); \
- __m128i __i = (i); \
- __m256i __mask = (mask); \
- (__m256i)__builtin_ia32_gatherd_q256((__v4di)__a, (const __v4di *)__m, \
- (__v4si)__i, (__v4di)__mask, (s)); })
+ (__m256i)__builtin_ia32_gatherd_q256((__v4di)(__m256i)(a), \
+ (long long const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4di)(__m256i)(mask), (s)); })
#define _mm_mask_i64gather_epi64(a, m, i, mask, s) __extension__ ({ \
- __m128i __a = (a); \
- long long const *__m = (m); \
- __m128i __i = (i); \
- __m128i __mask = (mask); \
- (__m128i)__builtin_ia32_gatherq_q((__v2di)__a, (const __v2di *)__m, \
- (__v2di)__i, (__v2di)__mask, (s)); })
+ (__m128i)__builtin_ia32_gatherq_q((__v2di)(__m128i)(a), \
+ (long long const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v2di)(__m128i)(mask), (s)); })
#define _mm256_mask_i64gather_epi64(a, m, i, mask, s) __extension__ ({ \
- __m256i __a = (a); \
- long long const *__m = (m); \
- __m256i __i = (i); \
- __m256i __mask = (mask); \
- (__m256i)__builtin_ia32_gatherq_q256((__v4di)__a, (const __v4di *)__m, \
- (__v4di)__i, (__v4di)__mask, (s)); })
+ (__m256i)__builtin_ia32_gatherq_q256((__v4di)(__m256i)(a), \
+ (long long const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4di)(__m256i)(mask), (s)); })
#define _mm_i32gather_pd(m, i, s) __extension__ ({ \
- double const *__m = (m); \
- __m128i __i = (i); \
- (__m128d)__builtin_ia32_gatherd_pd((__v2df)_mm_setzero_pd(), \
- (const __v2df *)__m, (__v4si)__i, \
- (__v2df)_mm_set1_pd((double)(long long int)-1), (s)); })
+ (__m128d)__builtin_ia32_gatherd_pd((__v2df)_mm_undefined_pd(), \
+ (double const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \
+ _mm_setzero_pd()), \
+ (s)); })
#define _mm256_i32gather_pd(m, i, s) __extension__ ({ \
- double const *__m = (m); \
- __m128i __i = (i); \
- (__m256d)__builtin_ia32_gatherd_pd256((__v4df)_mm256_setzero_pd(), \
- (const __v4df *)__m, (__v4si)__i, \
- (__v4df)_mm256_set1_pd((double)(long long int)-1), (s)); })
+ (__m256d)__builtin_ia32_gatherd_pd256((__v4df)_mm256_undefined_pd(), \
+ (double const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \
+ _mm256_setzero_pd(), \
+ _CMP_EQ_OQ), \
+ (s)); })
#define _mm_i64gather_pd(m, i, s) __extension__ ({ \
- double const *__m = (m); \
- __m128i __i = (i); \
- (__m128d)__builtin_ia32_gatherq_pd((__v2df)_mm_setzero_pd(), \
- (const __v2df *)__m, (__v2di)__i, \
- (__v2df)_mm_set1_pd((double)(long long int)-1), (s)); })
+ (__m128d)__builtin_ia32_gatherq_pd((__v2df)_mm_undefined_pd(), \
+ (double const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \
+ _mm_setzero_pd()), \
+ (s)); })
#define _mm256_i64gather_pd(m, i, s) __extension__ ({ \
- double const *__m = (m); \
- __m256i __i = (i); \
- (__m256d)__builtin_ia32_gatherq_pd256((__v4df)_mm256_setzero_pd(), \
- (const __v4df *)__m, (__v4di)__i, \
- (__v4df)_mm256_set1_pd((double)(long long int)-1), (s)); })
+ (__m256d)__builtin_ia32_gatherq_pd256((__v4df)_mm256_undefined_pd(), \
+ (double const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \
+ _mm256_setzero_pd(), \
+ _CMP_EQ_OQ), \
+ (s)); })
#define _mm_i32gather_ps(m, i, s) __extension__ ({ \
- float const *__m = (m); \
- __m128i __i = (i); \
- (__m128)__builtin_ia32_gatherd_ps((__v4sf)_mm_setzero_ps(), \
- (const __v4sf *)__m, (__v4si)__i, \
- (__v4sf)_mm_set1_ps((float)(int)-1), (s)); })
+ (__m128)__builtin_ia32_gatherd_ps((__v4sf)_mm_undefined_ps(), \
+ (float const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \
+ _mm_setzero_ps()), \
+ (s)); })
#define _mm256_i32gather_ps(m, i, s) __extension__ ({ \
- float const *__m = (m); \
- __m256i __i = (i); \
- (__m256)__builtin_ia32_gatherd_ps256((__v8sf)_mm256_setzero_ps(), \
- (const __v8sf *)__m, (__v8si)__i, \
- (__v8sf)_mm256_set1_ps((float)(int)-1), (s)); })
+ (__m256)__builtin_ia32_gatherd_ps256((__v8sf)_mm256_undefined_ps(), \
+ (float const *)(m), \
+ (__v8si)(__m256i)(i), \
+ (__v8sf)_mm256_cmp_ps(_mm256_setzero_ps(), \
+ _mm256_setzero_ps(), \
+ _CMP_EQ_OQ), \
+ (s)); })
#define _mm_i64gather_ps(m, i, s) __extension__ ({ \
- float const *__m = (m); \
- __m128i __i = (i); \
- (__m128)__builtin_ia32_gatherq_ps((__v4sf)_mm_setzero_ps(), \
- (const __v4sf *)__m, (__v2di)__i, \
- (__v4sf)_mm_set1_ps((float)(int)-1), (s)); })
+ (__m128)__builtin_ia32_gatherq_ps((__v4sf)_mm_undefined_ps(), \
+ (float const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \
+ _mm_setzero_ps()), \
+ (s)); })
#define _mm256_i64gather_ps(m, i, s) __extension__ ({ \
- float const *__m = (m); \
- __m256i __i = (i); \
- (__m128)__builtin_ia32_gatherq_ps256((__v4sf)_mm_setzero_ps(), \
- (const __v4sf *)__m, (__v4di)__i, \
- (__v4sf)_mm_set1_ps((float)(int)-1), (s)); })
+ (__m128)__builtin_ia32_gatherq_ps256((__v4sf)_mm_undefined_ps(), \
+ (float const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \
+ _mm_setzero_ps()), \
+ (s)); })
#define _mm_i32gather_epi32(m, i, s) __extension__ ({ \
- int const *__m = (m); \
- __m128i __i = (i); \
- (__m128i)__builtin_ia32_gatherd_d((__v4si)_mm_setzero_si128(), \
- (const __v4si *)__m, (__v4si)__i, \
- (__v4si)_mm_set1_epi32(-1), (s)); })
+ (__m128i)__builtin_ia32_gatherd_d((__v4si)_mm_undefined_si128(), \
+ (int const *)(m), (__v4si)(__m128i)(i), \
+ (__v4si)_mm_set1_epi32(-1), (s)); })
#define _mm256_i32gather_epi32(m, i, s) __extension__ ({ \
- int const *__m = (m); \
- __m256i __i = (i); \
- (__m256i)__builtin_ia32_gatherd_d256((__v8si)_mm256_setzero_si256(), \
- (const __v8si *)__m, (__v8si)__i, \
- (__v8si)_mm256_set1_epi32(-1), (s)); })
+ (__m256i)__builtin_ia32_gatherd_d256((__v8si)_mm256_undefined_si256(), \
+ (int const *)(m), (__v8si)(__m256i)(i), \
+ (__v8si)_mm256_set1_epi32(-1), (s)); })
#define _mm_i64gather_epi32(m, i, s) __extension__ ({ \
- int const *__m = (m); \
- __m128i __i = (i); \
- (__m128i)__builtin_ia32_gatherq_d((__v4si)_mm_setzero_si128(), \
- (const __v4si *)__m, (__v2di)__i, \
- (__v4si)_mm_set1_epi32(-1), (s)); })
+ (__m128i)__builtin_ia32_gatherq_d((__v4si)_mm_undefined_si128(), \
+ (int const *)(m), (__v2di)(__m128i)(i), \
+ (__v4si)_mm_set1_epi32(-1), (s)); })
#define _mm256_i64gather_epi32(m, i, s) __extension__ ({ \
- int const *__m = (m); \
- __m256i __i = (i); \
- (__m128i)__builtin_ia32_gatherq_d256((__v4si)_mm_setzero_si128(), \
- (const __v4si *)__m, (__v4di)__i, \
- (__v4si)_mm_set1_epi32(-1), (s)); })
+ (__m128i)__builtin_ia32_gatherq_d256((__v4si)_mm_undefined_si128(), \
+ (int const *)(m), (__v4di)(__m256i)(i), \
+ (__v4si)_mm_set1_epi32(-1), (s)); })
#define _mm_i32gather_epi64(m, i, s) __extension__ ({ \
- long long const *__m = (m); \
- __m128i __i = (i); \
- (__m128i)__builtin_ia32_gatherd_q((__v2di)_mm_setzero_si128(), \
- (const __v2di *)__m, (__v4si)__i, \
- (__v2di)_mm_set1_epi64x(-1), (s)); })
+ (__m128i)__builtin_ia32_gatherd_q((__v2di)_mm_undefined_si128(), \
+ (long long const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v2di)_mm_set1_epi64x(-1), (s)); })
#define _mm256_i32gather_epi64(m, i, s) __extension__ ({ \
- long long const *__m = (m); \
- __m128i __i = (i); \
- (__m256i)__builtin_ia32_gatherd_q256((__v4di)_mm256_setzero_si256(), \
- (const __v4di *)__m, (__v4si)__i, \
- (__v4di)_mm256_set1_epi64x(-1), (s)); })
+ (__m256i)__builtin_ia32_gatherd_q256((__v4di)_mm256_undefined_si256(), \
+ (long long const *)(m), \
+ (__v4si)(__m128i)(i), \
+ (__v4di)_mm256_set1_epi64x(-1), (s)); })
#define _mm_i64gather_epi64(m, i, s) __extension__ ({ \
- long long const *__m = (m); \
- __m128i __i = (i); \
- (__m128i)__builtin_ia32_gatherq_q((__v2di)_mm_setzero_si128(), \
- (const __v2di *)__m, (__v2di)__i, \
- (__v2di)_mm_set1_epi64x(-1), (s)); })
+ (__m128i)__builtin_ia32_gatherq_q((__v2di)_mm_undefined_si128(), \
+ (long long const *)(m), \
+ (__v2di)(__m128i)(i), \
+ (__v2di)_mm_set1_epi64x(-1), (s)); })
#define _mm256_i64gather_epi64(m, i, s) __extension__ ({ \
- long long const *__m = (m); \
- __m256i __i = (i); \
- (__m256i)__builtin_ia32_gatherq_q256((__v4di)_mm256_setzero_si256(), \
- (const __v4di *)__m, (__v4di)__i, \
- (__v4di)_mm256_set1_epi64x(-1), (s)); })
+ (__m256i)__builtin_ia32_gatherq_q256((__v4di)_mm256_undefined_si256(), \
+ (long long const *)(m), \
+ (__v4di)(__m256i)(i), \
+ (__v4di)_mm256_set1_epi64x(-1), (s)); })
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512erintrin.h b/lib/Headers/avx512erintrin.h
index 607f2c0..40a9121 100644
--- a/lib/Headers/avx512erintrin.h
+++ b/lib/Headers/avx512erintrin.h
@@ -126,19 +126,19 @@
_mm512_maskz_rsqrt28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION)
#define _mm_rsqrt28_round_ss(A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rsqrt28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rsqrt28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)_mm_setzero_ps(), \
(__mmask8)-1, (R)); })
#define _mm_mask_rsqrt28_round_ss(S, M, A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rsqrt28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rsqrt28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)(__m128)(S), \
(__mmask8)(M), (R)); })
#define _mm_maskz_rsqrt28_round_ss(M, A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rsqrt28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rsqrt28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)_mm_setzero_ps(), \
(__mmask8)(M), (R)); })
@@ -153,19 +153,19 @@
_mm_maskz_rsqrt28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION)
#define _mm_rsqrt28_round_sd(A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rsqrt28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rsqrt28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)_mm_setzero_pd(), \
(__mmask8)-1, (R)); })
#define _mm_mask_rsqrt28_round_sd(S, M, A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rsqrt28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rsqrt28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)(__m128d)(S), \
(__mmask8)(M), (R)); })
#define _mm_maskz_rsqrt28_round_sd(M, A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rsqrt28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rsqrt28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)_mm_setzero_pd(), \
(__mmask8)(M), (R)); })
@@ -229,19 +229,19 @@
_mm512_maskz_rcp28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION)
#define _mm_rcp28_round_ss(A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rcp28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rcp28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)_mm_setzero_ps(), \
(__mmask8)-1, (R)); })
#define _mm_mask_rcp28_round_ss(S, M, A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rcp28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rcp28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)(__m128)(S), \
(__mmask8)(M), (R)); })
#define _mm_maskz_rcp28_round_ss(M, A, B, R) __extension__ ({ \
- (__m128)__builtin_ia32_rcp28ss_mask((__v4sf)(__m128)(A), \
+ (__m128)__builtin_ia32_rcp28ss_round((__v4sf)(__m128)(A), \
(__v4sf)(__m128)(B), \
(__v4sf)_mm_setzero_ps(), \
(__mmask8)(M), (R)); })
@@ -256,19 +256,19 @@
_mm_maskz_rcp28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION)
#define _mm_rcp28_round_sd(A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rcp28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rcp28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)_mm_setzero_pd(), \
(__mmask8)-1, (R)); })
#define _mm_mask_rcp28_round_sd(S, M, A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rcp28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rcp28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)(__m128d)(S), \
(__mmask8)(M), (R)); })
#define _mm_maskz_rcp28_round_sd(M, A, B, R) __extension__ ({ \
- (__m128d)__builtin_ia32_rcp28sd_mask((__v2df)(__m128d)(A), \
+ (__m128d)__builtin_ia32_rcp28sd_round((__v2df)(__m128d)(A), \
(__v2df)(__m128d)(B), \
(__v2df)_mm_setzero_pd(), \
(__mmask8)(M), (R)); })
diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
index 9d31da7..5a976cc 100644
--- a/lib/Headers/avx512fintrin.h
+++ b/lib/Headers/avx512fintrin.h
@@ -569,7 +569,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_max_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_maxss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_maxss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -578,7 +578,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_max_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_maxss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_maxss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
@@ -586,20 +586,20 @@
}
#define _mm_max_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_maxss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_maxss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_max_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_maxss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_maxss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_max_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_maxss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_maxss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_max_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_maxsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_maxsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -608,7 +608,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_max_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_maxsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_maxsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
@@ -616,15 +616,15 @@
}
#define _mm_max_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_maxsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_maxsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_max_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_maxsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_maxsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_max_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_maxsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_maxsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline __m512i
@@ -692,7 +692,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_min_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_minss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_minss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -701,7 +701,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_min_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_minss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_minss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
@@ -709,20 +709,20 @@
}
#define _mm_min_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_minss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_minss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_min_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_minss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_minss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_min_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_minss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_minss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_min_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_minsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_minsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -731,7 +731,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_min_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_minsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_minsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
@@ -739,15 +739,15 @@
}
#define _mm_min_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_minsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_minsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_min_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_minsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_minsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_min_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_minsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_minsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline __m512i
@@ -909,7 +909,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_rsqrt14_ss(__m128 __A, __m128 __B)
{
- return (__m128) __builtin_ia32_rsqrt14ss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_rsqrt14ss ((__v4sf) __A,
(__v4sf) __B,
(__v4sf)
_mm_setzero_ps (),
@@ -919,7 +919,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_rsqrt14_sd(__m128d __A, __m128d __B)
{
- return (__m128d) __builtin_ia32_rsqrt14sd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_rsqrt14sd ((__v2df) __A,
(__v2df) __B,
(__v2df)
_mm_setzero_pd (),
@@ -946,7 +946,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_rcp14_ss(__m128 __A, __m128 __B)
{
- return (__m128) __builtin_ia32_rcp14ss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_rcp14ss ((__v4sf) __A,
(__v4sf) __B,
(__v4sf)
_mm_setzero_ps (),
@@ -956,7 +956,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_rcp14_sd(__m128d __A, __m128d __B)
{
- return (__m128d) __builtin_ia32_rcp14sd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_rcp14sd ((__v2df) __A,
(__v2df) __B,
(__v2df)
_mm_setzero_pd (),
@@ -1019,7 +1019,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_add_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_addss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_addss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -1028,7 +1028,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_add_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_addss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_addss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
@@ -1036,20 +1036,20 @@
}
#define _mm_add_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_addss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_addss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_add_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_addss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_addss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_add_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_addss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_addss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_add_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_addsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_addsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -1058,22 +1058,22 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_add_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_addsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_addsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
_MM_FROUND_CUR_DIRECTION);
}
#define _mm_add_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_addsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_addsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_add_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_addsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_addsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_add_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_addsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_addsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -1138,7 +1138,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_sub_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_subss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_subss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -1147,27 +1147,27 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_sub_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_subss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_subss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
_MM_FROUND_CUR_DIRECTION);
}
#define _mm_sub_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_subss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_subss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_sub_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_subss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_subss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_sub_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_subss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_subss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_sub_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_subsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_subsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -1176,7 +1176,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_sub_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_subsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_subsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
@@ -1184,15 +1184,15 @@
}
#define _mm_sub_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_subsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_subsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_sub_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_subsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_subsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_sub_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_subsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_subsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -1259,7 +1259,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_mul_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_mulss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_mulss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -1268,27 +1268,27 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_mul_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_mulss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_mulss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
_MM_FROUND_CUR_DIRECTION);
}
#define _mm_mul_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_mulss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_mulss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_mul_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_mulss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_mulss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_mul_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_mulss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_mulss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_mul_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_mulsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_mulsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -1297,7 +1297,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_mul_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_mulsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_mulsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
@@ -1305,15 +1305,15 @@
}
#define _mm_mul_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_mulsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_mulsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_mul_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_mulsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_mulsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_mul_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_mulsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_mulsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -1380,7 +1380,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_div_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_divss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_divss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) __W,
(__mmask8) __U,
@@ -1389,7 +1389,7 @@
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_div_ss(__mmask8 __U,__m128 __A, __m128 __B) {
- return (__m128) __builtin_ia32_divss_mask ((__v4sf) __A,
+ return (__m128) __builtin_ia32_divss_round ((__v4sf) __A,
(__v4sf) __B,
(__v4sf) _mm_setzero_ps (),
(__mmask8) __U,
@@ -1397,20 +1397,20 @@
}
#define _mm_div_round_ss(__A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_divss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_divss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) -1, __R); })
#define _mm_mask_div_round_ss(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_divss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_divss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) __W, (__mmask8) __U,__R); })
#define _mm_maskz_div_round_ss(__U, __A, __B, __R) __extension__ ({ \
- (__m128) __builtin_ia32_divss_mask ((__v4sf) __A, (__v4sf) __B, \
+ (__m128) __builtin_ia32_divss_round ((__v4sf) __A, (__v4sf) __B, \
(__v4sf) _mm_setzero_ps(), (__mmask8) __U,__R); })
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_div_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_divsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_divsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) __W,
(__mmask8) __U,
@@ -1419,7 +1419,7 @@
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_div_sd(__mmask8 __U,__m128d __A, __m128d __B) {
- return (__m128d) __builtin_ia32_divsd_mask ((__v2df) __A,
+ return (__m128d) __builtin_ia32_divsd_round ((__v2df) __A,
(__v2df) __B,
(__v2df) _mm_setzero_pd (),
(__mmask8) __U,
@@ -1427,15 +1427,15 @@
}
#define _mm_div_round_sd(__A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_divsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_divsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) -1, __R); })
#define _mm_mask_div_round_sd(__W, __U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_divsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_divsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) __W, (__mmask8) __U,__R); })
#define _mm_maskz_div_round_sd(__U, __A, __B, __R) __extension__ ({ \
- (__m128d) __builtin_ia32_divsd_mask ((__v2df) __A, (__v2df) __B, \
+ (__m128d) __builtin_ia32_divsd_round ((__v2df) __A, (__v2df) __B, \
(__v2df) _mm_setzero_pd(), (__mmask8) __U,__R); })
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -2333,17 +2333,15 @@
/* Vector Extract */
#define _mm512_extractf64x4_pd(A, I) __extension__ ({ \
- __m512d __A = (A); \
(__m256d) \
- __builtin_ia32_extractf64x4_mask((__v8df)__A, \
+ __builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), \
(I), \
(__v4df)_mm256_setzero_si256(), \
(__mmask8) -1); })
#define _mm512_extractf32x4_ps(A, I) __extension__ ({ \
- __m512 __A = (A); \
(__m128) \
- __builtin_ia32_extractf32x4_mask((__v16sf)__A, \
+ __builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), \
(I), \
(__v4sf)_mm_setzero_ps(), \
(__mmask8) -1); })
@@ -2650,7 +2648,7 @@
}
static __inline __m512 __DEFAULT_FN_ATTRS
-_mm512_load_ps(double const *__p)
+_mm512_load_ps(float const *__p)
{
return (__m512) __builtin_ia32_loadaps512_mask ((const __v16sf *)__p,
(__v16sf)
@@ -2659,7 +2657,7 @@
}
static __inline __m512d __DEFAULT_FN_ATTRS
-_mm512_load_pd(float const *__p)
+_mm512_load_pd(double const *__p)
{
return (__m512d) __builtin_ia32_loadapd512_mask ((const __v8df *)__p,
(__v8df)
@@ -3032,51 +3030,43 @@
}
#define _mm512_cmp_epi32_mask(a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, (p), \
+ (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \
+ (__v16si)(__m512i)(b), (p), \
(__mmask16)-1); })
#define _mm512_cmp_epu32_mask(a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, (p), \
+ (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \
+ (__v16si)(__m512i)(b), (p), \
(__mmask16)-1); })
#define _mm512_cmp_epi64_mask(a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, (p), \
+ (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \
+ (__v8di)(__m512i)(b), (p), \
(__mmask8)-1); })
#define _mm512_cmp_epu64_mask(a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, (p), \
+ (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \
+ (__v8di)(__m512i)(b), (p), \
(__mmask8)-1); })
#define _mm512_mask_cmp_epi32_mask(m, a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, (p), \
+ (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \
+ (__v16si)(__m512i)(b), (p), \
(__mmask16)(m)); })
#define _mm512_mask_cmp_epu32_mask(m, a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, (p), \
+ (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \
+ (__v16si)(__m512i)(b), (p), \
(__mmask16)(m)); })
#define _mm512_mask_cmp_epi64_mask(m, a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, (p), \
+ (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \
+ (__v8di)(__m512i)(b), (p), \
(__mmask8)(m)); })
#define _mm512_mask_cmp_epu64_mask(m, a, b, p) __extension__ ({ \
- __m512i __a = (a); \
- __m512i __b = (b); \
- (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, (p), \
+ (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \
+ (__v8di)(__m512i)(b), (p), \
(__mmask8)(m)); })
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512vlbwintrin.h b/lib/Headers/avx512vlbwintrin.h
index 5b61c2b..b4542d6 100644
--- a/lib/Headers/avx512vlbwintrin.h
+++ b/lib/Headers/avx512vlbwintrin.h
@@ -1,4 +1,4 @@
-/*===---- avx512vlbwintrin.h - AVX512VL and AVX512BW intrinsics ----------===
+/*===---- avx512vlbwintrin.h - AVX512VL and AVX512BW intrinsics ------------===
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/lib/Headers/avx512vldqintrin.h b/lib/Headers/avx512vldqintrin.h
index 8f48b0b..dfd858e 100644
--- a/lib/Headers/avx512vldqintrin.h
+++ b/lib/Headers/avx512vldqintrin.h
@@ -1,4 +1,4 @@
-/*===---- avx512vldqintrin.h - AVX512VL and AVX512DQ intrinsics ---------------------------===
+/*===---- avx512vldqintrin.h - AVX512VL and AVX512DQ intrinsics ------------===
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 0041365..6d1ca54 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -156,12 +156,10 @@
}
#define _mm256_round_pd(V, M) __extension__ ({ \
- __m256d __V = (V); \
- (__m256d)__builtin_ia32_roundpd256((__v4df)__V, (M)); })
+ (__m256d)__builtin_ia32_roundpd256((__v4df)(__m256d)(V), (M)); })
#define _mm256_round_ps(V, M) __extension__ ({ \
- __m256 __V = (V); \
- (__m256)__builtin_ia32_roundps256((__v8sf)__V, (M)); })
+ (__m256)__builtin_ia32_roundps256((__v8sf)(__m256)(V), (M)); })
#define _mm256_ceil_pd(V) _mm256_round_pd((V), _MM_FROUND_CEIL)
#define _mm256_floor_pd(V) _mm256_round_pd((V), _MM_FROUND_FLOOR)
@@ -268,26 +266,26 @@
}
#define _mm_permute_pd(A, C) __extension__ ({ \
- __m128d __A = (A); \
- (__m128d)__builtin_shufflevector((__v2df)__A, (__v2df) _mm_setzero_pd(), \
+ (__m128d)__builtin_shufflevector((__v2df)(__m128d)(A), \
+ (__v2df)_mm_setzero_pd(), \
(C) & 0x1, ((C) & 0x2) >> 1); })
#define _mm256_permute_pd(A, C) __extension__ ({ \
- __m256d __A = (A); \
- (__m256d)__builtin_shufflevector((__v4df)__A, (__v4df) _mm256_setzero_pd(), \
+ (__m256d)__builtin_shufflevector((__v4df)(__m256d)(A), \
+ (__v4df)_mm256_setzero_pd(), \
(C) & 0x1, ((C) & 0x2) >> 1, \
2 + (((C) & 0x4) >> 2), \
2 + (((C) & 0x8) >> 3)); })
#define _mm_permute_ps(A, C) __extension__ ({ \
- __m128 __A = (A); \
- (__m128)__builtin_shufflevector((__v4sf)__A, (__v4sf) _mm_setzero_ps(), \
+ (__m128)__builtin_shufflevector((__v4sf)(__m128)(A), \
+ (__v4sf)_mm_setzero_ps(), \
(C) & 0x3, ((C) & 0xc) >> 2, \
((C) & 0x30) >> 4, ((C) & 0xc0) >> 6); })
#define _mm256_permute_ps(A, C) __extension__ ({ \
- __m256 __A = (A); \
- (__m256)__builtin_shufflevector((__v8sf)__A, (__v8sf) _mm256_setzero_ps(), \
+ (__m256)__builtin_shufflevector((__v8sf)(__m256)(A), \
+ (__v8sf)_mm256_setzero_ps(), \
(C) & 0x3, ((C) & 0xc) >> 2, \
((C) & 0x30) >> 4, ((C) & 0xc0) >> 6, \
4 + (((C) & 0x03) >> 0), \
@@ -296,34 +294,29 @@
4 + (((C) & 0xc0) >> 6)); })
#define _mm256_permute2f128_pd(V1, V2, M) __extension__ ({ \
- __m256d __V1 = (V1); \
- __m256d __V2 = (V2); \
- (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)__V1, (__v4df)__V2, (M)); })
+ (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)(__m256d)(V1), \
+ (__v4df)(__m256d)(V2), (M)); })
#define _mm256_permute2f128_ps(V1, V2, M) __extension__ ({ \
- __m256 __V1 = (V1); \
- __m256 __V2 = (V2); \
- (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
+ (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)(__m256)(V1), \
+ (__v8sf)(__m256)(V2), (M)); })
#define _mm256_permute2f128_si256(V1, V2, M) __extension__ ({ \
- __m256i __V1 = (V1); \
- __m256i __V2 = (V2); \
- (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)__V1, (__v8si)__V2, (M)); })
+ (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)(__m256i)(V1), \
+ (__v8si)(__m256i)(V2), (M)); })
/* Vector Blend */
#define _mm256_blend_pd(V1, V2, M) __extension__ ({ \
- __m256d __V1 = (V1); \
- __m256d __V2 = (V2); \
- (__m256d)__builtin_shufflevector((__v4df)__V1, (__v4df)__V2, \
+ (__m256d)__builtin_shufflevector((__v4df)(__m256d)(V1), \
+ (__v4df)(__m256d)(V2), \
(((M) & 0x01) ? 4 : 0), \
(((M) & 0x02) ? 5 : 1), \
(((M) & 0x04) ? 6 : 2), \
(((M) & 0x08) ? 7 : 3)); })
#define _mm256_blend_ps(V1, V2, M) __extension__ ({ \
- __m256 __V1 = (V1); \
- __m256 __V2 = (V2); \
- (__m256)__builtin_shufflevector((__v8sf)__V1, (__v8sf)__V2, \
+ (__m256)__builtin_shufflevector((__v8sf)(__m256)(V1), \
+ (__v8sf)(__m256)(V2), \
(((M) & 0x01) ? 8 : 0), \
(((M) & 0x02) ? 9 : 1), \
(((M) & 0x04) ? 10 : 2), \
@@ -349,28 +342,29 @@
/* Vector Dot Product */
#define _mm256_dp_ps(V1, V2, M) __extension__ ({ \
- __m256 __V1 = (V1); \
- __m256 __V2 = (V2); \
- (__m256)__builtin_ia32_dpps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
+ (__m256)__builtin_ia32_dpps256((__v8sf)(__m256)(V1), \
+ (__v8sf)(__m256)(V2), (M)); })
/* Vector shuffle */
#define _mm256_shuffle_ps(a, b, mask) __extension__ ({ \
- __m256 __a = (a); \
- __m256 __b = (b); \
- (__m256)__builtin_shufflevector((__v8sf)__a, (__v8sf)__b, \
- (mask) & 0x3, ((mask) & 0xc) >> 2, \
- (((mask) & 0x30) >> 4) + 8, (((mask) & 0xc0) >> 6) + 8, \
- ((mask) & 0x3) + 4, (((mask) & 0xc) >> 2) + 4, \
- (((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12); })
+ (__m256)__builtin_shufflevector((__v8sf)(__m256)(a), \
+ (__v8sf)(__m256)(b), \
+ (mask) & 0x3, \
+ ((mask) & 0xc) >> 2, \
+ (((mask) & 0x30) >> 4) + 8, \
+ (((mask) & 0xc0) >> 6) + 8, \
+ ((mask) & 0x3) + 4, \
+ (((mask) & 0xc) >> 2) + 4, \
+ (((mask) & 0x30) >> 4) + 12, \
+ (((mask) & 0xc0) >> 6) + 12); })
#define _mm256_shuffle_pd(a, b, mask) __extension__ ({ \
- __m256d __a = (a); \
- __m256d __b = (b); \
- (__m256d)__builtin_shufflevector((__v4df)__a, (__v4df)__b, \
- (mask) & 0x1, \
- (((mask) & 0x2) >> 1) + 4, \
- (((mask) & 0x4) >> 2) + 2, \
- (((mask) & 0x8) >> 3) + 6); })
+ (__m256d)__builtin_shufflevector((__v4df)(__m256d)(a), \
+ (__v4df)(__m256d)(b), \
+ (mask) & 0x1, \
+ (((mask) & 0x2) >> 1) + 4, \
+ (((mask) & 0x4) >> 2) + 2, \
+ (((mask) & 0x8) >> 3) + 6); })
/* Compare */
#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */
@@ -407,34 +401,28 @@
#define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */
#define _mm_cmp_pd(a, b, c) __extension__ ({ \
- __m128d __a = (a); \
- __m128d __b = (b); \
- (__m128d)__builtin_ia32_cmppd((__v2df)__a, (__v2df)__b, (c)); })
+ (__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \
+ (__v2df)(__m128d)(b), (c)); })
#define _mm_cmp_ps(a, b, c) __extension__ ({ \
- __m128 __a = (a); \
- __m128 __b = (b); \
- (__m128)__builtin_ia32_cmpps((__v4sf)__a, (__v4sf)__b, (c)); })
+ (__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \
+ (__v4sf)(__m128)(b), (c)); })
#define _mm256_cmp_pd(a, b, c) __extension__ ({ \
- __m256d __a = (a); \
- __m256d __b = (b); \
- (__m256d)__builtin_ia32_cmppd256((__v4df)__a, (__v4df)__b, (c)); })
+ (__m256d)__builtin_ia32_cmppd256((__v4df)(__m256d)(a), \
+ (__v4df)(__m256d)(b), (c)); })
#define _mm256_cmp_ps(a, b, c) __extension__ ({ \
- __m256 __a = (a); \
- __m256 __b = (b); \
- (__m256)__builtin_ia32_cmpps256((__v8sf)__a, (__v8sf)__b, (c)); })
+ (__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \
+ (__v8sf)(__m256)(b), (c)); })
#define _mm_cmp_sd(a, b, c) __extension__ ({ \
- __m128d __a = (a); \
- __m128d __b = (b); \
- (__m128d)__builtin_ia32_cmpsd((__v2df)__a, (__v2df)__b, (c)); })
+ (__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \
+ (__v2df)(__m128d)(b), (c)); })
#define _mm_cmp_ss(a, b, c) __extension__ ({ \
- __m128 __a = (a); \
- __m128 __b = (b); \
- (__m128)__builtin_ia32_cmpss((__v4sf)__a, (__v4sf)__b, (c)); })
+ (__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \
+ (__v4sf)(__m128)(b), (c)); })
static __inline int __DEFAULT_FN_ATTRS
_mm256_extract_epi32(__m256i __a, const int __imm)
@@ -1169,7 +1157,7 @@
*/
#define _mm256_insertf128_ps(V1, V2, M) __extension__ ({ \
(__m256)__builtin_shufflevector( \
- (__v8sf)(V1), \
+ (__v8sf)(__m256)(V1), \
(__v8sf)_mm256_castps128_ps256((__m128)(V2)), \
(((M) & 1) ? 0 : 8), \
(((M) & 1) ? 1 : 9), \
@@ -1182,7 +1170,7 @@
#define _mm256_insertf128_pd(V1, V2, M) __extension__ ({ \
(__m256d)__builtin_shufflevector( \
- (__v4df)(V1), \
+ (__v4df)(__m256d)(V1), \
(__v4df)_mm256_castpd128_pd256((__m128d)(V2)), \
(((M) & 1) ? 0 : 4), \
(((M) & 1) ? 1 : 5), \
@@ -1191,7 +1179,7 @@
#define _mm256_insertf128_si256(V1, V2, M) __extension__ ({ \
(__m256i)__builtin_shufflevector( \
- (__v4di)(V1), \
+ (__v4di)(__m256i)(V1), \
(__v4di)_mm256_castsi128_si256((__m128i)(V2)), \
(((M) & 1) ? 0 : 4), \
(((M) & 1) ? 1 : 5), \
@@ -1205,7 +1193,7 @@
*/
#define _mm256_extractf128_ps(V, M) __extension__ ({ \
(__m128)__builtin_shufflevector( \
- (__v8sf)(V), \
+ (__v8sf)(__m256)(V), \
(__v8sf)(_mm256_setzero_ps()), \
(((M) & 1) ? 4 : 0), \
(((M) & 1) ? 5 : 1), \
@@ -1214,14 +1202,14 @@
#define _mm256_extractf128_pd(V, M) __extension__ ({ \
(__m128d)__builtin_shufflevector( \
- (__v4df)(V), \
+ (__v4df)(__m256d)(V), \
(__v4df)(_mm256_setzero_pd()), \
(((M) & 1) ? 2 : 0), \
(((M) & 1) ? 3 : 1) );})
#define _mm256_extractf128_si256(V, M) __extension__ ({ \
(__m128i)__builtin_shufflevector( \
- (__v4di)(V), \
+ (__v4di)(__m256i)(V), \
(__v4di)(_mm256_setzero_si256()), \
(((M) & 1) ? 2 : 0), \
(((M) & 1) ? 3 : 1) );})
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
index dc2f83f..da98792 100644
--- a/lib/Headers/bmiintrin.h
+++ b/lib/Headers/bmiintrin.h
@@ -39,7 +39,12 @@
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi")))
-static __inline__ unsigned short __DEFAULT_FN_ATTRS
+/* Allow using the tzcnt intrinsics even for non-BMI targets. Since the TZCNT
+ instruction behaves as BSF on non-BMI targets, there is code that expects
+ to use it as a potentially faster version of BSF. */
+#define __RELAXED_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ unsigned short __RELAXED_FN_ATTRS
__tzcnt_u16(unsigned short __X)
{
return __X ? __builtin_ctzs(__X) : 16;
@@ -83,7 +88,7 @@
return __X & (__X - 1);
}
-static __inline__ unsigned int __DEFAULT_FN_ATTRS
+static __inline__ unsigned int __RELAXED_FN_ATTRS
__tzcnt_u32(unsigned int __X)
{
return __X ? __builtin_ctz(__X) : 32;
@@ -136,7 +141,7 @@
return __X & (__X - 1);
}
-static __inline__ unsigned long long __DEFAULT_FN_ATTRS
+static __inline__ unsigned long long __RELAXED_FN_ATTRS
__tzcnt_u64(unsigned long long __X)
{
return __X ? __builtin_ctzll(__X) : 64;
@@ -145,5 +150,6 @@
#endif /* __x86_64__ */
#undef __DEFAULT_FN_ATTRS
+#undef __RELAXED_FN_ATTRS
#endif /* __BMIINTRIN_H */
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 47eaf09..cfc2c71 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -647,7 +647,7 @@
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_add_si64(__m64 __a, __m64 __b)
{
- return __a + __b;
+ return (__m64)__builtin_ia32_paddq(__a, __b);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
@@ -779,7 +779,7 @@
static __inline__ __m64 __DEFAULT_FN_ATTRS
_mm_sub_si64(__m64 __a, __m64 __b)
{
- return __a - __b;
+ return (__m64)__builtin_ia32_psubq(__a, __b);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
@@ -1334,20 +1334,20 @@
#define _mm_shuffle_epi32(a, imm) __extension__ ({ \
(__m128i)__builtin_shufflevector((__v4si)(__m128i)(a), \
- (__v4si)_mm_set1_epi32(0), \
+ (__v4si)_mm_setzero_si128(), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6); })
#define _mm_shufflelo_epi16(a, imm) __extension__ ({ \
(__m128i)__builtin_shufflevector((__v8hi)(__m128i)(a), \
- (__v8hi)_mm_set1_epi16(0), \
+ (__v8hi)_mm_setzero_si128(), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
4, 5, 6, 7); })
#define _mm_shufflehi_epi16(a, imm) __extension__ ({ \
(__m128i)__builtin_shufflevector((__v8hi)(__m128i)(a), \
- (__v8hi)_mm_set1_epi16(0), \
+ (__v8hi)_mm_setzero_si128(), \
0, 1, 2, 3, \
4 + (((imm) & 0x03) >> 0), \
4 + (((imm) & 0x0c) >> 2), \
@@ -1439,8 +1439,8 @@
}
#define _mm_shuffle_pd(a, b, i) __extension__ ({ \
- __builtin_shufflevector((__m128d)(a), (__m128d)(b), \
- (i) & 1, (((i) & 2) >> 1) + 2); })
+ (__m128d)__builtin_shufflevector((__v2df)(__m128d)(a), (__v2df)(__m128d)(b), \
+ (i) & 1, (((i) & 2) >> 1) + 2); })
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_castpd_ps(__m128d __a)
@@ -1481,7 +1481,7 @@
static __inline__ void __DEFAULT_FN_ATTRS
_mm_pause(void)
{
- __asm__ volatile ("pause");
+ __builtin_ia32_pause();
}
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index 9fb4545..c655d98 100644
--- a/lib/Headers/f16cintrin.h
+++ b/lib/Headers/f16cintrin.h
@@ -28,19 +28,11 @@
#ifndef __F16CINTRIN_H
#define __F16CINTRIN_H
-typedef float __v8sf __attribute__ ((__vector_size__ (32)));
-typedef float __m256 __attribute__ ((__vector_size__ (32)));
-
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("f16c")))
#define _mm_cvtps_ph(a, imm) __extension__ ({ \
- __m128 __a = (a); \
- (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)__a, (imm)); })
-
-#define _mm256_cvtps_ph(a, imm) __extension__ ({ \
- __m256 __a = (a); \
- (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); })
+ (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)(__m128)(a), (imm)); })
static __inline __m128 __DEFAULT_FN_ATTRS
_mm_cvtph_ps(__m128i __a)
@@ -48,12 +40,6 @@
return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)__a);
}
-static __inline __m256 __DEFAULT_FN_ATTRS
-_mm256_cvtph_ps(__m128i __a)
-{
- return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)__a);
-}
-
#undef __DEFAULT_FN_ATTRS
#endif /* __F16CINTRIN_H */
diff --git a/lib/Headers/ia32intrin.h b/lib/Headers/ia32intrin.h
index 5adf3f1..b2f82bb 100644
--- a/lib/Headers/ia32intrin.h
+++ b/lib/Headers/ia32intrin.h
@@ -32,50 +32,26 @@
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__readeflags(void)
{
- unsigned long long __res = 0;
- __asm__ __volatile__ ("pushf\n\t"
- "popq %0\n"
- :"=r"(__res)
- :
- :
- );
- return __res;
+ return __builtin_ia32_readeflags_u64();
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
__writeeflags(unsigned long long __f)
{
- __asm__ __volatile__ ("pushq %0\n\t"
- "popf\n"
- :
- :"r"(__f)
- :"flags"
- );
+ __builtin_ia32_writeeflags_u64(__f);
}
#else /* !__x86_64__ */
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__readeflags(void)
{
- unsigned int __res = 0;
- __asm__ __volatile__ ("pushf\n\t"
- "popl %0\n"
- :"=r"(__res)
- :
- :
- );
- return __res;
+ return __builtin_ia32_readeflags_u32();
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
__writeeflags(unsigned int __f)
{
- __asm__ __volatile__ ("pushl %0\n\t"
- "popf\n"
- :
- :"r"(__f)
- :"flags"
- );
+ __builtin_ia32_writeeflags_u32(__f);
}
#endif /* !__x86_64__ */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index a28222b..6376461 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -42,6 +42,19 @@
#include <avx2intrin.h>
+/* The 256-bit versions of functions in f16cintrin.h.
+ Intel documents these as being in immintrin.h, and
+ they depend on typedefs from avxintrin.h. */
+
+#define _mm256_cvtps_ph(a, imm) __extension__ ({ \
+ (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)(__m256)(a), (imm)); })
+
+static __inline __m256 __attribute__((__always_inline__, __nodebug__, __target__("f16c")))
+_mm256_cvtph_ps(__m128i __a)
+{
+ return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)__a);
+}
+
#include <bmiintrin.h>
#include <bmi2intrin.h>
@@ -66,6 +79,8 @@
#include <avx512erintrin.h>
+#include <pkuintrin.h>
+
static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
_rdrand16_step(unsigned short *__p)
{
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index 1a9eb10..162cb1a 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -443,7 +443,9 @@
/* Aliases for compatibility. */
#define _m_empty _mm_empty
#define _m_from_int _mm_cvtsi32_si64
+#define _m_from_int64 _mm_cvtsi64_m64
#define _m_to_int _mm_cvtsi64_si32
+#define _m_to_int64 _mm_cvtm64_si64
#define _m_packsswb _mm_packs_pi16
#define _m_packssdw _mm_packs_pi32
#define _m_packuswb _mm_packs_pu16
diff --git a/lib/Headers/pkuintrin.h b/lib/Headers/pkuintrin.h
new file mode 100644
index 0000000..ad12348
--- /dev/null
+++ b/lib/Headers/pkuintrin.h
@@ -0,0 +1,48 @@
+/*===------------- pkuintrin.h - PKU intrinsics ------------------===
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+#ifndef __IMMINTRIN_H
+#error "Never use <pkuintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __PKUINTRIN_H
+#define __PKUINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("pku")))
+
+static __inline__ unsigned int __DEFAULT_FN_ATTRS
+_rdpkru_u32(void)
+{
+ return __builtin_ia32_rdpkru();
+}
+
+static __inline__ void __DEFAULT_FN_ATTRS
+_wrpkru(unsigned int val)
+{
+ return __builtin_ia32_wrpkru(val);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif
diff --git a/lib/Headers/popcntintrin.h b/lib/Headers/popcntintrin.h
index 29c074b..6fcda65 100644
--- a/lib/Headers/popcntintrin.h
+++ b/lib/Headers/popcntintrin.h
@@ -33,12 +33,24 @@
return __builtin_popcount(__A);
}
+static __inline__ int __DEFAULT_FN_ATTRS
+_popcnt32(int __A)
+{
+ return __builtin_popcount(__A);
+}
+
#ifdef __x86_64__
static __inline__ long long __DEFAULT_FN_ATTRS
_mm_popcnt_u64(unsigned long long __A)
{
return __builtin_popcountll(__A);
}
+
+static __inline__ long long __DEFAULT_FN_ATTRS
+_popcnt64(long long __A)
+{
+ return __builtin_popcountll(__A);
+}
#endif /* __x86_64__ */
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/shaintrin.h b/lib/Headers/shaintrin.h
index 8602d02..9b5d218 100644
--- a/lib/Headers/shaintrin.h
+++ b/lib/Headers/shaintrin.h
@@ -32,7 +32,7 @@
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sha")))
#define _mm_sha1rnds4_epu32(V1, V2, M) __extension__ ({ \
- __builtin_ia32_sha1rnds4((V1), (V2), (M)); })
+ __builtin_ia32_sha1rnds4((__v4si)(__m128i)(V1), (__v4si)(__m128i)(V2), (M)); })
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_sha1nexte_epu32(__m128i __X, __m128i __Y)
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 89db27f..69ad07f 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -57,35 +57,28 @@
#define _mm_floor_sd(X, Y) _mm_round_sd((X), (Y), _MM_FROUND_FLOOR)
#define _mm_round_ps(X, M) __extension__ ({ \
- __m128 __X = (X); \
- (__m128) __builtin_ia32_roundps((__v4sf)__X, (M)); })
+ (__m128)__builtin_ia32_roundps((__v4sf)(__m128)(X), (M)); })
#define _mm_round_ss(X, Y, M) __extension__ ({ \
- __m128 __X = (X); \
- __m128 __Y = (Y); \
- (__m128) __builtin_ia32_roundss((__v4sf)__X, (__v4sf)__Y, (M)); })
+ (__m128)__builtin_ia32_roundss((__v4sf)(__m128)(X), \
+ (__v4sf)(__m128)(Y), (M)); })
#define _mm_round_pd(X, M) __extension__ ({ \
- __m128d __X = (X); \
- (__m128d) __builtin_ia32_roundpd((__v2df)__X, (M)); })
+ (__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M)); })
#define _mm_round_sd(X, Y, M) __extension__ ({ \
- __m128d __X = (X); \
- __m128d __Y = (Y); \
- (__m128d) __builtin_ia32_roundsd((__v2df)__X, (__v2df)__Y, (M)); })
+ (__m128d)__builtin_ia32_roundsd((__v2df)(__m128d)(X), \
+ (__v2df)(__m128d)(Y), (M)); })
/* SSE4 Packed Blending Intrinsics. */
#define _mm_blend_pd(V1, V2, M) __extension__ ({ \
- __m128d __V1 = (V1); \
- __m128d __V2 = (V2); \
- (__m128d)__builtin_shufflevector((__v2df)__V1, (__v2df)__V2, \
+ (__m128d)__builtin_shufflevector((__v2df)(__m128d)(V1), \
+ (__v2df)(__m128d)(V2), \
(((M) & 0x01) ? 2 : 0), \
(((M) & 0x02) ? 3 : 1)); })
#define _mm_blend_ps(V1, V2, M) __extension__ ({ \
- __m128 __V1 = (V1); \
- __m128 __V2 = (V2); \
- (__m128)__builtin_shufflevector((__v4sf)__V1, (__v4sf)__V2, \
+ (__m128)__builtin_shufflevector((__v4sf)(__m128)(V1), (__v4sf)(__m128)(V2), \
(((M) & 0x01) ? 4 : 0), \
(((M) & 0x02) ? 5 : 1), \
(((M) & 0x04) ? 6 : 2), \
@@ -113,9 +106,8 @@
}
#define _mm_blend_epi16(V1, V2, M) __extension__ ({ \
- __m128i __V1 = (V1); \
- __m128i __V2 = (V2); \
- (__m128i)__builtin_shufflevector((__v8hi)__V1, (__v8hi)__V2, \
+ (__m128i)__builtin_shufflevector((__v8hi)(__m128i)(V1), \
+ (__v8hi)(__m128i)(V2), \
(((M) & 0x01) ? 8 : 0), \
(((M) & 0x02) ? 9 : 1), \
(((M) & 0x04) ? 10 : 2), \
@@ -140,14 +132,12 @@
/* SSE4 Floating Point Dot Product Instructions. */
#define _mm_dp_ps(X, Y, M) __extension__ ({ \
- __m128 __X = (X); \
- __m128 __Y = (Y); \
- (__m128) __builtin_ia32_dpps((__v4sf)__X, (__v4sf)__Y, (M)); })
+ (__m128) __builtin_ia32_dpps((__v4sf)(__m128)(X), \
+ (__v4sf)(__m128)(Y), (M)); })
#define _mm_dp_pd(X, Y, M) __extension__ ({\
- __m128d __X = (X); \
- __m128d __Y = (Y); \
- (__m128d) __builtin_ia32_dppd((__v2df)__X, (__v2df)__Y, (M)); })
+ (__m128d) __builtin_ia32_dppd((__v2df)(__m128d)(X), \
+ (__v2df)(__m128d)(Y), (M)); })
/* SSE4 Streaming Load Hint Instruction. */
static __inline__ __m128i __DEFAULT_FN_ATTRS
@@ -209,7 +199,7 @@
#define _mm_insert_ps(X, Y, N) __builtin_ia32_insertps128((X), (Y), (N))
#define _mm_extract_ps(X, N) (__extension__ \
({ union { int __i; float __f; } __t; \
- __v4sf __a = (__v4sf)(X); \
+ __v4sf __a = (__v4sf)(__m128)(X); \
__t.__f = __a[(N) & 3]; \
__t.__i;}))
@@ -227,29 +217,34 @@
_MM_MK_INSERTPS_NDX((N), 0, 0x0e))
/* Insert int into packed integer array at index. */
-#define _mm_insert_epi8(X, I, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- __a[(N) & 15] = (I); \
- __a;}))
-#define _mm_insert_epi32(X, I, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- __a[(N) & 3] = (I); \
- __a;}))
+#define _mm_insert_epi8(X, I, N) (__extension__ \
+ ({ __v16qi __a = (__v16qi)(__m128i)(X); \
+ __a[(N) & 15] = (I); \
+ __a;}))
+#define _mm_insert_epi32(X, I, N) (__extension__ \
+ ({ __v4si __a = (__v4si)(__m128i)(X); \
+ __a[(N) & 3] = (I); \
+ __a;}))
#ifdef __x86_64__
-#define _mm_insert_epi64(X, I, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[(N) & 1] = (I); \
- __a;}))
+#define _mm_insert_epi64(X, I, N) (__extension__ \
+ ({ __v2di __a = (__v2di)(__m128i)(X); \
+ __a[(N) & 1] = (I); \
+ __a;}))
#endif /* __x86_64__ */
/* Extract int from packed integer array at index. This returns the element
* as a zero extended value, so it is unsigned.
*/
-#define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- (int)(unsigned char) \
- __a[(N) & 15];}))
-#define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- __a[(N) & 3];}))
+#define _mm_extract_epi8(X, N) (__extension__ \
+ ({ __v16qi __a = (__v16qi)(__m128i)(X); \
+ (int)(unsigned char) __a[(N) & 15];}))
+#define _mm_extract_epi32(X, N) (__extension__ \
+ ({ __v4si __a = (__v4si)(__m128i)(X); \
+ (int)__a[(N) & 3];}))
#ifdef __x86_64__
-#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[(N) & 1];}))
+#define _mm_extract_epi64(X, N) (__extension__ \
+ ({ __v2di __a = (__v2di)(__m128i)(X); \
+ (long long)__a[(N) & 1];}))
#endif /* __x86_64 */
/* SSE4 128-bit Packed Integer Comparisons. */
@@ -372,9 +367,8 @@
/* SSE4 Multiple Packed Sums of Absolute Difference. */
#define _mm_mpsadbw_epu8(X, Y, M) __extension__ ({ \
- __m128i __X = (X); \
- __m128i __Y = (Y); \
- (__m128i) __builtin_ia32_mpsadbw128((__v16qi)__X, (__v16qi)__Y, (M)); })
+ (__m128i) __builtin_ia32_mpsadbw128((__v16qi)(__m128i)(X), \
+ (__v16qi)(__m128i)(Y), (M)); })
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_minpos_epu16(__m128i __V)
@@ -417,36 +411,59 @@
#define _SIDD_UNIT_MASK 0x40
/* SSE4.2 Packed Comparison Intrinsics. */
-#define _mm_cmpistrm(A, B, M) __builtin_ia32_pcmpistrm128((A), (B), (M))
-#define _mm_cmpistri(A, B, M) __builtin_ia32_pcmpistri128((A), (B), (M))
+#define _mm_cmpistrm(A, B, M) \
+ (__m128i)__builtin_ia32_pcmpistrm128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
+#define _mm_cmpistri(A, B, M) \
+ (int)__builtin_ia32_pcmpistri128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpestrm(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestrm128((A), (LA), (B), (LB), (M))
+ (__m128i)__builtin_ia32_pcmpestrm128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
#define _mm_cmpestri(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestri128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestri128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */
#define _mm_cmpistra(A, B, M) \
- __builtin_ia32_pcmpistria128((A), (B), (M))
+ (int)__builtin_ia32_pcmpistria128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpistrc(A, B, M) \
- __builtin_ia32_pcmpistric128((A), (B), (M))
+ (int)__builtin_ia32_pcmpistric128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpistro(A, B, M) \
- __builtin_ia32_pcmpistrio128((A), (B), (M))
+ (int)__builtin_ia32_pcmpistrio128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpistrs(A, B, M) \
- __builtin_ia32_pcmpistris128((A), (B), (M))
+ (int)__builtin_ia32_pcmpistris128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpistrz(A, B, M) \
- __builtin_ia32_pcmpistriz128((A), (B), (M))
+ (int)__builtin_ia32_pcmpistriz128((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (int)(M))
#define _mm_cmpestra(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestria128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestria128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
#define _mm_cmpestrc(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestric128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
#define _mm_cmpestro(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestrio128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestrio128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
#define _mm_cmpestrs(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestris128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestris128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
#define _mm_cmpestrz(A, LA, B, LB, M) \
- __builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M))
+ (int)__builtin_ia32_pcmpestriz128((__v16qi)(__m128i)(A), (int)(LA), \
+ (__v16qi)(__m128i)(B), (int)(LB), \
+ (int)(M))
/* SSE4.2 Compare Packed Data -- Greater Than. */
static __inline__ __m128i __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/tbmintrin.h b/lib/Headers/tbmintrin.h
index 62f613f..785961c 100644
--- a/lib/Headers/tbmintrin.h
+++ b/lib/Headers/tbmintrin.h
@@ -31,7 +31,9 @@
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("tbm")))
-#define __bextri_u32(a, b) (__builtin_ia32_bextri_u32((a), (b)))
+#define __bextri_u32(a, b) \
+ ((unsigned int)__builtin_ia32_bextri_u32((unsigned int)(a), \
+ (unsigned int)(b)))
static __inline__ unsigned int __DEFAULT_FN_ATTRS
__blcfill_u32(unsigned int a)
@@ -88,7 +90,9 @@
}
#ifdef __x86_64__
-#define __bextri_u64(a, b) (__builtin_ia32_bextri_u64((a), (int)(b)))
+#define __bextri_u64(a, b) \
+ ((unsigned long long)__builtin_ia32_bextri_u64((unsigned long long)(a), \
+ (unsigned long long)(b)))
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
__blcfill_u64(unsigned long long a)
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 8a6dfcb..0002890 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -66,14 +66,11 @@
}
#define _mm_alignr_epi8(a, b, n) __extension__ ({ \
- __m128i __a = (a); \
- __m128i __b = (b); \
- (__m128i)__builtin_ia32_palignr128((__v16qi)__a, (__v16qi)__b, (n)); })
+ (__m128i)__builtin_ia32_palignr128((__v16qi)(__m128i)(a), \
+ (__v16qi)(__m128i)(b), (n)); })
#define _mm_alignr_pi8(a, b, n) __extension__ ({ \
- __m64 __a = (a); \
- __m64 __b = (b); \
- (__m64)__builtin_ia32_palignr((__v8qi)__a, (__v8qi)__b, (n)); })
+ (__m64)__builtin_ia32_palignr((__v8qi)(__m64)(a), (__v8qi)(__m64)(b), (n)); })
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_hadd_epi16(__m128i __a, __m128i __b)
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 06c2e24..ae0b2cd 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -754,8 +754,7 @@
}
#define _mm_shuffle_pi16(a, n) __extension__ ({ \
- __m64 __a = (a); \
- (__m64)__builtin_ia32_pshufw((__v4hi)__a, (n)); })
+ (__m64)__builtin_ia32_pshufw((__v4hi)(__m64)(a), (n)); })
static __inline__ void __DEFAULT_FN_ATTRS
_mm_maskmove_si64(__m64 __d, __m64 __n, char *__p)
@@ -794,9 +793,7 @@
}
#define _mm_shuffle_ps(a, b, mask) __extension__ ({ \
- __m128 __a = (a); \
- __m128 __b = (b); \
- (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__b, \
+ (__m128)__builtin_shufflevector((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), \
(mask) & 0x3, ((mask) & 0xc) >> 2, \
(((mask) & 0x30) >> 4) + 4, \
(((mask) & 0xc0) >> 6) + 4); })
diff --git a/lib/Headers/xopintrin.h b/lib/Headers/xopintrin.h
index 86188bb..f07f51c 100644
--- a/lib/Headers/xopintrin.h
+++ b/lib/Headers/xopintrin.h
@@ -238,20 +238,16 @@
}
#define _mm_roti_epi8(A, N) __extension__ ({ \
- __m128i __A = (A); \
- (__m128i)__builtin_ia32_vprotbi((__v16qi)__A, (N)); })
+ (__m128i)__builtin_ia32_vprotbi((__v16qi)(__m128i)(A), (N)); })
#define _mm_roti_epi16(A, N) __extension__ ({ \
- __m128i __A = (A); \
- (__m128i)__builtin_ia32_vprotwi((__v8hi)__A, (N)); })
+ (__m128i)__builtin_ia32_vprotwi((__v8hi)(__m128i)(A), (N)); })
#define _mm_roti_epi32(A, N) __extension__ ({ \
- __m128i __A = (A); \
- (__m128i)__builtin_ia32_vprotdi((__v4si)__A, (N)); })
+ (__m128i)__builtin_ia32_vprotdi((__v4si)(__m128i)(A), (N)); })
#define _mm_roti_epi64(A, N) __extension__ ({ \
- __m128i __A = (A); \
- (__m128i)__builtin_ia32_vprotqi((__v2di)__A, (N)); })
+ (__m128i)__builtin_ia32_vprotqi((__v2di)(__m128i)(A), (N)); })
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_shl_epi8(__m128i __A, __m128i __B)
@@ -302,44 +298,36 @@
}
#define _mm_com_epu8(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomub((__v16qi)__A, (__v16qi)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomub((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (N)); })
#define _mm_com_epu16(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomuw((__v8hi)__A, (__v8hi)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomuw((__v8hi)(__m128i)(A), \
+ (__v8hi)(__m128i)(B), (N)); })
#define _mm_com_epu32(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomud((__v4si)__A, (__v4si)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomud((__v4si)(__m128i)(A), \
+ (__v4si)(__m128i)(B), (N)); })
#define _mm_com_epu64(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomuq((__v2di)__A, (__v2di)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomuq((__v2di)(__m128i)(A), \
+ (__v2di)(__m128i)(B), (N)); })
#define _mm_com_epi8(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomb((__v16qi)__A, (__v16qi)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomb((__v16qi)(__m128i)(A), \
+ (__v16qi)(__m128i)(B), (N)); })
#define _mm_com_epi16(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomw((__v8hi)__A, (__v8hi)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomw((__v8hi)(__m128i)(A), \
+ (__v8hi)(__m128i)(B), (N)); })
#define _mm_com_epi32(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomd((__v4si)__A, (__v4si)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomd((__v4si)(__m128i)(A), \
+ (__v4si)(__m128i)(B), (N)); })
#define _mm_com_epi64(A, B, N) __extension__ ({ \
- __m128i __A = (A); \
- __m128i __B = (B); \
- (__m128i)__builtin_ia32_vpcomq((__v2di)__A, (__v2di)__B, (N)); })
+ (__m128i)__builtin_ia32_vpcomq((__v2di)(__m128i)(A), \
+ (__v2di)(__m128i)(B), (N)); })
#define _MM_PCOMCTRL_LT 0
#define _MM_PCOMCTRL_LE 1
@@ -735,32 +723,23 @@
}
#define _mm_permute2_pd(X, Y, C, I) __extension__ ({ \
- __m128d __X = (X); \
- __m128d __Y = (Y); \
- __m128i __C = (C); \
- (__m128d)__builtin_ia32_vpermil2pd((__v2df)__X, (__v2df)__Y, \
- (__v2di)__C, (I)); })
+ (__m128d)__builtin_ia32_vpermil2pd((__v2df)(__m128d)(X), \
+ (__v2df)(__m128d)(Y), \
+ (__v2di)(__m128i)(C), (I)); })
#define _mm256_permute2_pd(X, Y, C, I) __extension__ ({ \
- __m256d __X = (X); \
- __m256d __Y = (Y); \
- __m256i __C = (C); \
- (__m256d)__builtin_ia32_vpermil2pd256((__v4df)__X, (__v4df)__Y, \
- (__v4di)__C, (I)); })
+ (__m256d)__builtin_ia32_vpermil2pd256((__v4df)(__m256d)(X), \
+ (__v4df)(__m256d)(Y), \
+ (__v4di)(__m256i)(C), (I)); })
#define _mm_permute2_ps(X, Y, C, I) __extension__ ({ \
- __m128 __X = (X); \
- __m128 __Y = (Y); \
- __m128i __C = (C); \
- (__m128)__builtin_ia32_vpermil2ps((__v4sf)__X, (__v4sf)__Y, \
- (__v4si)__C, (I)); })
+ (__m128)__builtin_ia32_vpermil2ps((__v4sf)(__m128)(X), (__v4sf)(__m128)(Y), \
+ (__v4si)(__m128i)(C), (I)); })
#define _mm256_permute2_ps(X, Y, C, I) __extension__ ({ \
- __m256 __X = (X); \
- __m256 __Y = (Y); \
- __m256i __C = (C); \
- (__m256)__builtin_ia32_vpermil2ps256((__v8sf)__X, (__v8sf)__Y, \
- (__v8si)__C, (I)); })
+ (__m256)__builtin_ia32_vpermil2ps256((__v8sf)(__m256)(X), \
+ (__v8sf)(__m256)(Y), \
+ (__v8si)(__m256i)(C), (I)); })
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_frcz_ss(__m128 __A)
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 8a686a7..2d005dd 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -153,8 +153,7 @@
auto FileName = llvm::sys::path::filename(ModuleMapPath);
llvm::hash_code Hash =
- llvm::hash_combine(DirName.lower(), FileName.lower(),
- HSOpts->ModuleFormat, HSOpts->UseDebugInfo);
+ llvm::hash_combine(DirName.lower(), FileName.lower());
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a3ec1b3..27b0feb 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1354,7 +1354,9 @@
}
static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
- if (LangOpts.CPlusPlus11 || LangOpts.C11) {
+ if (LangOpts.AsmPreprocessor) {
+ return false;
+ } else if (LangOpts.CPlusPlus11 || LangOpts.C11) {
static const llvm::sys::UnicodeCharSet C11AllowedIDChars(
C11AllowedIDCharRanges);
return C11AllowedIDChars.contains(C);
@@ -1371,7 +1373,9 @@
static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
assert(isAllowedIDChar(C, LangOpts));
- if (LangOpts.CPlusPlus11 || LangOpts.C11) {
+ if (LangOpts.AsmPreprocessor) {
+ return false;
+ } else if (LangOpts.CPlusPlus11 || LangOpts.C11) {
static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars(
C11DisallowedInitialIDCharRanges);
return !C11DisallowedInitialIDChars.contains(C);
@@ -1732,7 +1736,7 @@
if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
- Diag(BufferPtr, diag::ext_unterminated_string);
+ Diag(BufferPtr, diag::ext_unterminated_char_or_string) << 1;
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return true;
}
@@ -1756,7 +1760,7 @@
// If a nul character existed in the string, warn about it.
if (NulCharacter && !isLexingRawMode())
- Diag(NulCharacter, diag::null_in_string);
+ Diag(NulCharacter, diag::null_in_char_or_string) << 1;
// Update the location of the token as well as the BufferPtr instance var.
const char *TokStart = BufferPtr;
@@ -1872,7 +1876,7 @@
// If a nul character existed in the string, warn about it.
if (NulCharacter && !isLexingRawMode())
- Diag(NulCharacter, diag::null_in_string);
+ Diag(NulCharacter, diag::null_in_char_or_string) << 1;
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
@@ -1914,7 +1918,7 @@
if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
- Diag(BufferPtr, diag::ext_unterminated_char);
+ Diag(BufferPtr, diag::ext_unterminated_char_or_string) << 0;
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return true;
}
@@ -1938,7 +1942,7 @@
// If a nul character existed in the character, warn about it.
if (NulCharacter && !isLexingRawMode())
- Diag(NulCharacter, diag::null_in_char);
+ Diag(NulCharacter, diag::null_in_char_or_string) << 0;
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
@@ -2956,8 +2960,11 @@
case 26: // DOS & CP/M EOF: "^Z".
// If we're in Microsoft extensions mode, treat this as end of file.
- if (LangOpts.MicrosoftExt)
+ if (LangOpts.MicrosoftExt) {
+ if (!isLexingRawMode())
+ Diag(CurPtr-1, diag::ext_ctrl_z_eof_microsoft);
return LexEndOfFile(Result, CurPtr-1);
+ }
// If Microsoft extensions are disabled, this is just random garbage.
Kind = tok::unknown;
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 1a1b281..5b1c493 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -159,7 +159,7 @@
// Check for overflow.
if (Overflow && Diags) // Too many digits to fit in
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::err_hex_escape_too_large);
+ diag::err_escape_too_large) << 0;
break;
}
case '0': case '1': case '2': case '3':
@@ -182,7 +182,7 @@
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::err_octal_escape_too_large);
+ diag::err_escape_too_large) << 1;
ResultChar &= ~0U >> (32-CharWidth);
}
break;
@@ -538,7 +538,7 @@
// Done.
} else if (isHexDigit(*s) && !(*s == 'e' || *s == 'E')) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
- diag::err_invalid_decimal_digit) << StringRef(s, 1);
+ diag::err_invalid_digit) << StringRef(s, 1) << 0;
hadError = true;
return;
} else if (*s == '.') {
@@ -680,9 +680,8 @@
// Report an error if there are any.
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
- isFPConstant ? diag::err_invalid_suffix_float_constant :
- diag::err_invalid_suffix_integer_constant)
- << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
+ diag::err_invalid_suffix_constant)
+ << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin) << isFPConstant;
hadError = true;
return;
}
@@ -767,7 +766,7 @@
if (noSignificand) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
- diag::err_hexconstant_requires_digits);
+ diag::err_hexconstant_requires) << 1;
hadError = true;
return;
}
@@ -794,7 +793,7 @@
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_hexconstant_requires_exponent);
+ diag::err_hexconstant_requires) << 0;
hadError = true;
}
return;
@@ -818,7 +817,7 @@
// Done.
} else if (isHexDigit(*s)) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_binary_digit) << StringRef(s, 1);
+ diag::err_invalid_digit) << StringRef(s, 1) << 2;
hadError = true;
}
// Other suffixes will be diagnosed by the caller.
@@ -848,7 +847,7 @@
// the code is using an incorrect base.
if (isHexDigit(*s) && *s != 'e' && *s != 'E') {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_octal_digit) << StringRef(s, 1);
+ diag::err_invalid_digit) << StringRef(s, 1) << 1;
hadError = true;
return;
}
@@ -984,6 +983,7 @@
/// u' c-char-sequence '
/// U' c-char-sequence '
/// L' c-char-sequence '
+/// u8' c-char-sequence ' [C++1z lex.ccon]
/// c-char-sequence:
/// c-char
/// c-char-sequence c-char
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index bd48ae6..4742aae 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -116,3 +116,29 @@
}
}
}
+
+bool Preprocessor::IsPreviousCachedToken(const Token &Tok) const {
+ // There's currently no cached token...
+ if (!CachedLexPos)
+ return false;
+
+ const Token LastCachedTok = CachedTokens[CachedLexPos - 1];
+ if (LastCachedTok.getKind() != Tok.getKind())
+ return false;
+
+ int RelOffset = 0;
+ if ((!getSourceManager().isInSameSLocAddrSpace(
+ Tok.getLocation(), getLastCachedTokenLocation(), &RelOffset)) ||
+ RelOffset)
+ return false;
+
+ return true;
+}
+
+void Preprocessor::ReplacePreviousCachedToken(ArrayRef<Token> NewToks) {
+ assert(CachedLexPos != 0 && "Expected to have some cached tokens");
+ CachedTokens.insert(CachedTokens.begin() + CachedLexPos - 1, NewToks.begin(),
+ NewToks.end());
+ CachedTokens.erase(CachedTokens.begin() + CachedLexPos - 1 + NewToks.size());
+ CachedLexPos += NewToks.size() - 1;
+}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 01f680c..105288b 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -650,8 +650,7 @@
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
IncludeStackInfo &ISEntry = IncludeMacroStack[e - i - 1];
if (IsFileLexer(ISEntry))
- if ((FileEnt = SourceMgr.getFileEntryForID(
- ISEntry.ThePPLexer->getFileID())))
+ if ((FileEnt = ISEntry.ThePPLexer->getFileEntry()))
Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
}
}
@@ -696,7 +695,7 @@
// to one of the headers on the #include stack. Walk the list of the current
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
- if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) {
+ if ((CurFileEnt = CurPPLexer->getFileEntry())) {
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
SearchPath, RelativePath,
RequestingModule,
@@ -712,8 +711,7 @@
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1];
if (IsFileLexer(ISEntry)) {
- if ((CurFileEnt =
- SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) {
+ if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) {
if ((FE = HeaderInfo.LookupSubframeworkHeader(
Filename, CurFileEnt, SearchPath, RelativePath,
RequestingModule, SuggestedModule))) {
@@ -2049,13 +2047,9 @@
}
// #define inline
- if (MacroName.isOneOf(tok::kw_extern, tok::kw_inline, tok::kw_static,
- tok::kw_const) &&
- MI->getNumTokens() == 0) {
- return true;
- }
-
- return false;
+ return MacroName.isOneOf(tok::kw_extern, tok::kw_inline, tok::kw_static,
+ tok::kw_const) &&
+ MI->getNumTokens() == 0;
}
/// HandleDefineDirective - Implements \#define. This consumes the entire macro
@@ -2270,6 +2264,30 @@
// Finally, if this identifier already had a macro defined for it, verify that
// the macro bodies are identical, and issue diagnostics if they are not.
if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) {
+ // In Objective-C, ignore attempts to directly redefine the builtin
+ // definitions of the ownership qualifiers. It's still possible to
+ // #undef them.
+ auto isObjCProtectedMacro = [](const IdentifierInfo *II) -> bool {
+ return II->isStr("__strong") ||
+ II->isStr("__weak") ||
+ II->isStr("__unsafe_unretained") ||
+ II->isStr("__autoreleasing");
+ };
+ if (getLangOpts().ObjC1 &&
+ SourceMgr.getFileID(OtherMI->getDefinitionLoc())
+ == getPredefinesFileID() &&
+ isObjCProtectedMacro(MacroNameTok.getIdentifierInfo())) {
+ // Warn if it changes the tokens.
+ if ((!getDiagnostics().getSuppressSystemWarnings() ||
+ !SourceMgr.isInSystemHeader(DefineTok.getLocation())) &&
+ !MI->isIdenticalTo(*OtherMI, *this,
+ /*Syntactic=*/LangOpts.MicrosoftExt)) {
+ Diag(MI->getDefinitionLoc(), diag::warn_pp_objc_macro_redef_ignored);
+ }
+ assert(!OtherMI->isWarnIfUnused());
+ return;
+ }
+
// It is very common for system headers to have tons of macro redefinitions
// and for warnings to be disabled in system headers. If this is the case,
// then don't bother calling MacroInfo::isIdenticalTo.
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index d2156d4..c40598c 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -549,12 +549,12 @@
// value was negative, warn about it.
if (ValueLive && Res.isUnsigned()) {
if (!LHS.isUnsigned() && LHS.Val.isNegative())
- PP.Diag(OpLoc, diag::warn_pp_convert_lhs_to_positive)
+ PP.Diag(OpLoc, diag::warn_pp_convert_to_positive) << 0
<< LHS.Val.toString(10, true) + " to " +
LHS.Val.toString(10, false)
<< LHS.getRange() << RHS.getRange();
if (!RHS.isUnsigned() && RHS.Val.isNegative())
- PP.Diag(OpLoc, diag::warn_pp_convert_rhs_to_positive)
+ PP.Diag(OpLoc, diag::warn_pp_convert_to_positive) << 1
<< RHS.Val.toString(10, true) + " to " +
RHS.Val.toString(10, false)
<< LHS.getRange() << RHS.getRange();
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index d43db1c..2f09841 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -301,8 +301,7 @@
if (const IdentifierInfo *ControllingMacro =
CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
// Okay, this has a controlling macro, remember in HeaderFileInfo.
- if (const FileEntry *FE =
- SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) {
+ if (const FileEntry *FE = CurPPLexer->getFileEntry()) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
if (MacroInfo *MI =
getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
@@ -562,7 +561,6 @@
void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
assert(CurTokenLexer && !CurPPLexer &&
"Pasted comment can only be formed from macro");
-
// We handle this by scanning for the closest real lexer, switching it to
// raw mode and preprocessor mode. This will cause it to return \n as an
// explicit EOD token.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index e168d0d..c11e37f 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -597,9 +597,7 @@
Brackets.pop_back();
}
}
- if (!Brackets.empty())
- return false;
- return true;
+ return Brackets.empty();
}
/// GenerateNewArgTokens - Returns true if OldTokens can be converted to a new
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 3134790..afb41a2 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -876,6 +876,22 @@
Crasher.setKind(tok::annot_pragma_parser_crash);
Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
PP.EnterToken(Crasher);
+ } else if (II->isStr("dump")) {
+ Token Identifier;
+ PP.LexUnexpandedToken(Identifier);
+ if (auto *DumpII = Identifier.getIdentifierInfo()) {
+ Token DumpAnnot;
+ DumpAnnot.startToken();
+ DumpAnnot.setKind(tok::annot_pragma_dump);
+ DumpAnnot.setAnnotationRange(
+ SourceRange(Tok.getLocation(), Identifier.getLocation()));
+ DumpAnnot.setAnnotationValue(DumpII);
+ PP.DiscardUntilEndOfDirective();
+ PP.EnterToken(DumpAnnot);
+ } else {
+ PP.Diag(Identifier, diag::warn_pragma_debug_missing_argument)
+ << II->getName();
+ }
} else if (II->isStr("llvm_fatal_error")) {
llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
} else if (II->isStr("llvm_unreachable")) {
@@ -887,7 +903,8 @@
if (MacroII)
PP.dumpMacroInfo(MacroII);
else
- PP.Diag(MacroName, diag::warn_pragma_diagnostic_invalid);
+ PP.Diag(MacroName, diag::warn_pragma_debug_missing_argument)
+ << II->getName();
} else if (II->isStr("overflow_stack")) {
DebugOverflowStack();
} else if (II->isStr("handle_crash")) {
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index e7512fa..ed2b8cd 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -305,6 +305,7 @@
// identifier.
ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
NextTokGetsSpace);
+ ResultToks[FirstResult].setFlagValue(Token::StartOfLine, false);
NextTokGetsSpace = false;
}
continue;
@@ -624,21 +625,22 @@
// error. This occurs with "x ## +" and other stuff. Return with Tok
// unmodified and with RHS as the next token to lex.
if (isInvalid) {
+ // Explicitly convert the token location to have proper expansion
+ // information so that the user knows where it came from.
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation Loc =
+ SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2);
+
// Test for the Microsoft extension of /##/ turning into // here on the
// error path.
if (PP.getLangOpts().MicrosoftExt && Tok.is(tok::slash) &&
RHS.is(tok::slash)) {
- HandleMicrosoftCommentPaste(Tok);
+ HandleMicrosoftCommentPaste(Tok, Loc);
return true;
}
// Do not emit the error when preprocessing assembler code.
if (!PP.getLangOpts().AsmPreprocessor) {
- // Explicitly convert the token location to have proper expansion
- // information so that the user knows where it came from.
- SourceManager &SM = PP.getSourceManager();
- SourceLocation Loc =
- SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2);
// If we're in microsoft extensions mode, downgrade this from a hard
// error to an extension that defaults to an error. This allows
// disabling it.
@@ -719,7 +721,9 @@
/// macro, other active macros, and anything left on the current physical
/// source line of the expanded buffer. Handle this by returning the
/// first token on the next line.
-void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
+void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok, SourceLocation OpLoc) {
+ PP.Diag(OpLoc, diag::ext_comment_paste_microsoft);
+
// We 'comment out' the rest of this macro by just ignoring the rest of the
// tokens that have not been lexed yet, if any.
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 5084aee..2d94619 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -68,8 +68,9 @@
SourceLocation KWEndLoc = Tok.getEndLoc().getLocWithOffset(-1);
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_deleted_function
- : diag::ext_deleted_function);
+ ? diag::warn_cxx98_compat_defaulted_deleted_function
+ : diag::ext_defaulted_deleted_function)
+ << 1 /* deleted */;
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
@@ -77,8 +78,9 @@
}
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_defaulted_function
- : diag::ext_defaulted_function);
+ ? diag::warn_cxx98_compat_defaulted_deleted_function
+ : diag::ext_defaulted_deleted_function)
+ << 0 /* defaulted */;
Actions.SetDeclDefaulted(FnD, KWLoc);
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
DeclAsFunction->setRangeEnd(KWEndLoc);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 51b4eee..7b7adac 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -24,6 +24,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -1464,15 +1465,13 @@
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
ProhibitAttributes(attrs);
SourceLocation InlineLoc = ConsumeToken();
- SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc);
- break;
+ return ParseNamespace(Context, DeclEnd, InlineLoc);
}
return ParseSimpleDeclaration(Context, DeclEnd, attrs,
true);
case tok::kw_namespace:
ProhibitAttributes(attrs);
- SingleDecl = ParseNamespace(Context, DeclEnd);
- break;
+ return ParseNamespace(Context, DeclEnd);
case tok::kw_using:
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
DeclEnd, attrs, &OwnedType);
@@ -1523,7 +1522,7 @@
// may get this far before the problem becomes obvious.
if (DS.hasTagDefinition() &&
DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext))
- return DeclGroupPtrTy();
+ return nullptr;
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -1702,7 +1701,7 @@
// Bail out if the first declarator didn't seem well-formed.
if (!D.hasName() && !D.mayOmitIdentifier()) {
SkipMalformedDecl();
- return DeclGroupPtrTy();
+ return nullptr;
}
// Save late-parsed attributes for now; they need to be parsed in the
@@ -1767,19 +1766,19 @@
} else {
Diag(Tok, diag::err_expected_fn_body);
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
} else {
if (Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_function_definition_not_allowed);
SkipMalformedDecl();
- return DeclGroupPtrTy();
+ return nullptr;
}
}
}
if (ParseAsmAttributesAfterDeclarator(D))
- return DeclGroupPtrTy();
+ return nullptr;
// C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we
// must parse and analyze the for-range-initializer before the declaration is
@@ -1975,8 +1974,8 @@
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
- 0, LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
+ LAngleLoc));
ThisDecl =
Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
@@ -2157,7 +2156,7 @@
DS.ClearStorageClassSpecs();
}
- // Issue diagnostic and remove function specfier if present.
+ // Issue diagnostic and remove function specifier if present.
if (Specs & DeclSpec::PQ_FunctionSpecifier) {
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
@@ -2670,7 +2669,7 @@
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
- DS.Finish(Diags, PP, Policy);
+ DS.Finish(Actions, Policy);
return;
case tok::l_square:
@@ -2785,8 +2784,8 @@
// arguments. Complain, then parse it as a type as the user
// intended.
Diag(TemplateId->TemplateNameLoc,
- diag::err_out_of_line_template_id_names_constructor)
- << TemplateId->Name;
+ diag::err_out_of_line_template_id_type_names_constructor)
+ << TemplateId->Name << 0 /* template name */;
}
DS.getTypeSpecScope() = SS;
@@ -2831,16 +2830,16 @@
// looked at the declarator, and the user probably meant this
// to be a type. Complain that it isn't supposed to be treated
// as a type, then proceed to parse it as a type.
- Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
- << Next.getIdentifierInfo();
+ Diag(Next.getLocation(),
+ diag::err_out_of_line_template_id_type_names_constructor)
+ << Next.getIdentifierInfo() << 1 /* type */;
}
- ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
- Next.getLocation(),
- getCurScope(), &SS,
- false, false, ParsedType(),
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialSourceInfo=*/true);
+ ParsedType TypeRep =
+ Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
+ getCurScope(), &SS, false, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialSourceInfo=*/true);
// If the referenced identifier is not a type, then this declspec is
// erroneous: We already checked about that it has no type specifier, and
@@ -3138,6 +3137,11 @@
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
+ case tok::kw___auto_type:
+ Diag(Tok, diag::ext_auto_type);
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto_type, Loc, PrevSpec,
+ DiagID, Policy);
+ break;
case tok::kw_register:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
PrevSpec, DiagID, Policy);
@@ -3321,6 +3325,15 @@
case tok::kw___bool:
isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
break;
+ case tok::kw_pipe:
+ if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) {
+ // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should
+ // support the "pipe" word as identifier.
+ Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
+ goto DoneWithDeclSpec;
+ }
+ isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
+ break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID, Policy);
@@ -3582,8 +3595,8 @@
SmallVector<Decl *, 32> FieldDecls;
// While we still have something to read, read the declarations in the struct.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one struct-declaration.
// Check for extraneous top-level semicolon.
@@ -3774,7 +3787,7 @@
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
CXXScopeSpec Spec;
- if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(),
+ if (ParseOptionalCXXScopeSpecifier(Spec, nullptr,
/*EnteringContext=*/true))
return;
@@ -4396,6 +4409,9 @@
switch (Tok.getKind()) {
default: return false;
+ case tok::kw_pipe:
+ return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200);
+
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLangOpts().ObjC1 && NextToken().is(tok::period))
@@ -4440,6 +4456,7 @@
case tok::kw___private_extern__:
case tok::kw_static:
case tok::kw_auto:
+ case tok::kw___auto_type:
case tok::kw_register:
case tok::kw___thread:
case tok::kw_thread_local:
@@ -4570,7 +4587,7 @@
// Parse the C++ scope specifier.
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/true)) {
TPA.Revert();
return false;
@@ -4813,7 +4830,7 @@
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
// qualifiers. First verify that DeclSpec's are consistent.
- DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy());
+ DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
if (EndLoc.isValid())
DS.SetRangeEnd(EndLoc);
return;
@@ -4841,6 +4858,9 @@
if (Kind == tok::star || Kind == tok::caret)
return true;
+ if ((Kind == tok::kw_pipe) && Lang.OpenCL && (Lang.OpenCLVersion >= 200))
+ return true;
+
if (!Lang.CPlusPlus)
return false;
@@ -4859,6 +4879,17 @@
return false;
}
+// Indicates whether the given declarator is a pipe declarator.
+static bool isPipeDeclerator(const Declarator &D) {
+ const unsigned NumTypes = D.getNumTypeObjects();
+
+ for (unsigned Idx = 0; Idx != NumTypes; ++Idx)
+ if (DeclaratorChunk::Pipe == D.getTypeObject(Idx).Kind)
+ return true;
+
+ return false;
+}
+
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
/// is parsed by the function passed to it. Pass null, and the direct-declarator
/// isn't parsed at all, making this function effectively parse the C++
@@ -4900,7 +4931,7 @@
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext);
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
@@ -4935,6 +4966,15 @@
}
tok::TokenKind Kind = Tok.getKind();
+
+ if (D.getDeclSpec().isTypeSpecPipe() && !isPipeDeclerator(D)) {
+ DeclSpec &DS = D.getMutableDeclSpec();
+
+ D.AddTypeInfo(
+ DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()),
+ DS.getAttributes(), SourceLocation());
+ }
+
// Not a pointer, C++ reference, or block.
if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) {
if (DirectDeclParser)
@@ -5106,7 +5146,7 @@
if (D.getCXXScopeSpec().isEmpty()) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(),
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), nullptr,
EnteringContext);
}
@@ -5167,11 +5207,8 @@
bool HadScope = D.getCXXScopeSpec().isValid();
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
- /*AllowDestructorName=*/true,
- AllowConstructorName,
- ParsedType(),
- TemplateKWLoc,
- D.getName()) ||
+ /*AllowDestructorName=*/true, AllowConstructorName,
+ nullptr, TemplateKWLoc, D.getName()) ||
// Once we're past the identifier, if the scope was bad, mark the
// whole declarator bad.
D.getCXXScopeSpec().isInvalid()) {
@@ -5192,6 +5229,15 @@
}
goto PastIdentifier;
}
+
+ if (D.getCXXScopeSpec().isNotEmpty()) {
+ // We have a scope specifier but no following unqualified-id.
+ Diag(PP.getLocForEndOfToken(D.getCXXScopeSpec().getEndLoc()),
+ diag::err_expected_unqualified_id)
+ << /*C++*/1;
+ D.SetIdentifier(nullptr, Tok.getLocation());
+ goto PastIdentifier;
+ }
} else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
assert(!getLangOpts().CPlusPlus &&
"There's a C++-specific check for tok::identifier above");
@@ -6077,6 +6123,7 @@
case DeclaratorChunk::Reference:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
NeedParens = true;
break;
case DeclaratorChunk::Array:
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index c24d6a5..b2337b2 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -55,9 +55,9 @@
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
///
-Decl *Parser::ParseNamespace(unsigned Context,
- SourceLocation &DeclEnd,
- SourceLocation InlineLoc) {
+Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context,
+ SourceLocation &DeclEnd,
+ SourceLocation InlineLoc) {
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
ObjCDeclContextSwitch ObjCDC(*this);
@@ -116,8 +116,9 @@
if (InlineLoc.isValid())
Diag(InlineLoc, diag::err_inline_namespace_alias)
<< FixItHint::CreateRemoval(InlineLoc);
- return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
- }
+ Decl *NSAlias = ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
+ return Actions.ConvertDeclToDeclGroup(NSAlias);
+}
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
@@ -180,10 +181,11 @@
// Enter a scope for the namespace.
ParseScope NamespaceScope(this, Scope::DeclScope);
+ UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc,
IdentLoc, Ident, T.getOpenLocation(),
- attrs.getList());
+ attrs.getList(), ImplicitUsingDirectiveDecl);
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
@@ -198,8 +200,9 @@
DeclEnd = T.getCloseLocation();
Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd);
-
- return NamespcDecl;
+
+ return Actions.ConvertDeclToDeclGroup(NamespcDecl,
+ ImplicitUsingDirectiveDecl);
}
/// ParseInnerNamespace - Parse the contents of a namespace.
@@ -210,8 +213,8 @@
ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
@@ -229,17 +232,19 @@
// FIXME: Preserve the source information through to the AST rather than
// desugaring it here.
ParseScope NamespaceScope(this, Scope::DeclScope);
+ UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl =
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
NamespaceLoc[index], IdentLoc[index],
Ident[index], Tracker.getOpenLocation(),
- attrs.getList());
+ attrs.getList(), ImplicitUsingDirectiveDecl);
+ assert(!ImplicitUsingDirectiveDecl &&
+ "nested namespace definition cannot define anonymous namespace");
ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
attrs, Tracker);
NamespaceScope.Exit();
-
Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation());
}
@@ -262,7 +267,7 @@
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@@ -280,8 +285,8 @@
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name))
SkipUntil(tok::semi);
- return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc, Alias,
- SS, IdentLoc, Ident);
+ return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc,
+ Alias, SS, IdentLoc, Ident);
}
/// ParseLinkage - We know that the current token is a string_literal
@@ -394,8 +399,8 @@
// Template parameters are always an error here.
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
- Diag(UsingLoc, diag::err_templated_using_directive)
- << R << FixItHint::CreateRemoval(R);
+ Diag(UsingLoc, diag::err_templated_using_directive_declaration)
+ << 0 /* directive */ << R << FixItHint::CreateRemoval(R);
}
return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
@@ -437,7 +442,7 @@
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
IdentifierInfo *NamespcName = nullptr;
SourceLocation IdentLoc = SourceLocation();
@@ -512,7 +517,7 @@
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
/*MayBePseudoDtor=*/nullptr,
/*IsTypename=*/false,
/*LastII=*/&LastII);
@@ -549,7 +554,7 @@
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
NextToken().is(tok::equal)),
- ParsedType(), TemplateKWLoc, Name)) {
+ nullptr, TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -645,8 +650,8 @@
// template <...> using id = type;
if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
- Diag(UsingLoc, diag::err_templated_using_declaration)
- << R << FixItHint::CreateRemoval(R);
+ Diag(UsingLoc, diag::err_templated_using_directive_declaration)
+ << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
// Unfortunately, we have to bail out instead of recovering by
// ignoring the parameters, just in case the nested name specifier
@@ -939,7 +944,7 @@
// Parse optional nested-name-specifier
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
BaseLoc = Tok.getLocation();
@@ -1001,8 +1006,8 @@
if (!Template) {
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS,
- true, LAngleLoc, TemplateArgs, RAngleLoc);
+ ParseTemplateIdAfterTemplateName(nullptr, IdLoc, SS, true, LAngleLoc,
+ TemplateArgs, RAngleLoc);
return true;
}
@@ -1032,11 +1037,10 @@
// We have an identifier; check whether it is actually a type.
IdentifierInfo *CorrectedII = nullptr;
- ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true,
- false, ParsedType(),
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo=*/true,
- &CorrectedII);
+ ParsedType Type =
+ Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo=*/true, &CorrectedII);
if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
return true;
@@ -1347,7 +1351,7 @@
CXXScopeSpec Spec;
bool HasValidSpec = true;
- if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), EnteringContext)) {
+ if (ParseOptionalCXXScopeSpecifier(Spec, nullptr, EnteringContext)) {
DS.SetTypeSpecError();
HasValidSpec = false;
}
@@ -1376,9 +1380,8 @@
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS,
- true, LAngleLoc,
- TemplateArgs, RAngleLoc)) {
+ if (ParseTemplateIdAfterTemplateName(
+ nullptr, NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
@@ -1657,8 +1660,8 @@
// "template<>", so that we treat this construct as a class
// template specialization.
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
- 0, LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
+ LAngleLoc));
TemplateParams = &FakedParamLists;
}
}
@@ -1839,7 +1842,7 @@
}
// Attach the base specifiers
- Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), BaseInfo.size());
+ Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo);
}
/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is
@@ -2248,7 +2251,7 @@
ConsumeToken();
SkipUntil(tok::r_brace, StopAtSemi);
- return DeclGroupPtrTy();
+ return nullptr;
}
// Turn on colon protection early, while parsing declspec, although there is
@@ -2277,28 +2280,28 @@
if (isAccessDecl) {
// Collect the scope specifier token we annotated earlier.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/false);
if (SS.isInvalid()) {
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS, false, true, true, ParsedType(),
- TemplateKWLoc, Name)) {
+ if (ParseUnqualifiedId(SS, false, true, true, nullptr, TemplateKWLoc,
+ Name)) {
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
// TODO: recover from mistakenly-qualified operator declarations.
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
"access declaration")) {
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
@@ -2356,7 +2359,7 @@
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
SkipUntil(tok::semi, StopBeforeMatch);
- return DeclGroupPtrTy();
+ return nullptr;
}
SourceLocation DeclEnd;
// Otherwise, it must be a using-declaration or an alias-declaration.
@@ -2386,7 +2389,7 @@
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
&CommonLateParsedAttrs))
- return DeclGroupPtrTy();
+ return nullptr;
MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
@@ -2441,7 +2444,7 @@
if (ParseCXXMemberDeclaratorBeforeInitializer(
DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) {
TryConsumeToken(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
// Check for a member function definition.
@@ -2490,7 +2493,7 @@
// Consume the optional ';'
TryConsumeToken(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -2695,7 +2698,7 @@
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
// If we stopped at a ';', eat it.
TryConsumeToken(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
@@ -2822,44 +2825,49 @@
if (getLangOpts().MicrosoftExt &&
Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
ParseMicrosoftIfExistsClassDeclaration(TagType, AS);
- return DeclGroupPtrTy();
+ return nullptr;
}
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
ConsumeExtraSemi(InsideStruct, TagType);
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_vis)) {
HandlePragmaVisibility();
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_pack)) {
HandlePragmaPack();
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_align)) {
HandlePragmaAlign();
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
HandlePragmaMSPointersToMembers();
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_ms_pragma)) {
HandlePragmaMSPragma();
- return DeclGroupPtrTy();
+ return nullptr;
+ }
+
+ if (Tok.is(tok::annot_pragma_ms_vtordisp)) {
+ HandlePragmaMSVtorDisp();
+ return nullptr;
}
// If we see a namespace here, a close brace was missing somewhere.
if (Tok.is(tok::kw_namespace)) {
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
- return DeclGroupPtrTy();
+ return nullptr;
}
AccessSpecifier NewAS = getAccessSpecifierIfPresent();
@@ -2895,7 +2903,7 @@
AccessAttrs.clear();
}
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::annot_pragma_openmp))
@@ -3066,8 +3074,8 @@
if (TagDecl) {
// While we still have something to read, read the member-declarations.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
ParseCXXClassMemberDeclarationWithPragmas(
CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), TagDecl);
@@ -3181,28 +3189,30 @@
Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
MemInitializers);
return cutOffParsing();
- } else {
- MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
- if (!MemInit.isInvalid())
- MemInitializers.push_back(MemInit.get());
- else
- AnyErrors = true;
}
-
+
+ MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
+ if (!MemInit.isInvalid())
+ MemInitializers.push_back(MemInit.get());
+ else
+ AnyErrors = true;
+
if (Tok.is(tok::comma))
ConsumeToken();
else if (Tok.is(tok::l_brace))
break;
- // If the next token looks like a base or member initializer, assume that
- // we're just missing a comma.
- else if (Tok.isOneOf(tok::identifier, tok::coloncolon)) {
+ // If the previous initializer was valid and the next token looks like a
+ // base or member initializer, assume that we're just missing a comma.
+ else if (!MemInit.isInvalid() &&
+ Tok.isOneOf(tok::identifier, tok::coloncolon)) {
SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation);
Diag(Loc, diag::err_ctor_init_missing_comma)
<< FixItHint::CreateInsertion(Loc, ", ");
} else {
// Skip over garbage, until we get to '{'. Don't eat the '{'.
- Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
- << tok::comma;
+ if (!MemInit.isInvalid())
+ Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
+ << tok::comma;
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
break;
}
@@ -3227,7 +3237,7 @@
MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
ParsedType TemplateTypeTy;
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -3355,7 +3365,8 @@
ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
/*StopAtSemi=*/true,
/*ConsumeFinalToken=*/true);
- SpecificationRange.setEnd(Tok.getLocation());
+ SpecificationRange.setEnd(ExceptionSpecTokens->back().getLocation());
+
return EST_Unparsed;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 490bd5a..ad23804 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -895,7 +895,7 @@
((Tok.is(tok::identifier) &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
Tok.is(tok::code_completion))) {
- Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(),
+ Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr,
nullptr);
break;
}
@@ -1204,7 +1204,7 @@
// type, translate it into a type and continue parsing as a
// cast expression.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
@@ -1334,8 +1334,23 @@
return ExprError();
}
+ // Check to see whether Res is a function designator only. If it is and we
+ // are compiling for OpenCL, we need to return an error as this implies
+ // that the address of the function is being taken, which is illegal in CL.
+
// These can be followed by postfix-expr pieces.
- return ParsePostfixExpressionSuffix(Res);
+ Res = ParsePostfixExpressionSuffix(Res);
+ if (getLangOpts().OpenCL)
+ if (Expr *PostfixExpr = Res.get()) {
+ QualType Ty = PostfixExpr->getType();
+ if (!Ty.isNull() && Ty->isFunctionType()) {
+ Diag(PostfixExpr->getExprLoc(),
+ diag::err_opencl_taking_function_address_parser);
+ return ExprError();
+ }
+ }
+
+ return Res;
}
/// \brief Once the leading part of a postfix-expression is parsed, this
@@ -1380,7 +1395,7 @@
if (getLangOpts().ObjC1 && !InMessageExpression &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
- ParsedType(), LHS.get());
+ nullptr, LHS.get());
break;
}
@@ -1591,7 +1606,7 @@
/*EnteringContext=*/false,
&MayBePseudoDestructor);
if (SS.isNotEmpty())
- ObjectType = ParsedType();
+ ObjectType = nullptr;
}
if (Tok.is(tok::code_completion)) {
@@ -2145,7 +2160,7 @@
ExprResult Result(true);
bool isAmbiguousTypeId;
- CastTy = ParsedType();
+ CastTy = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
@@ -2491,7 +2506,7 @@
return ExprError();
}
DefaultLoc = ConsumeToken();
- Ty = ParsedType();
+ Ty = nullptr;
} else {
ColonProtectionRAIIObject X(*this);
TypeResult TR = ParseTypeName();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index d5f1881..53009ca 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -283,8 +283,8 @@
//
// To implement this, we clear out the object type as soon as we've
// seen a leading '::' or part of a nested-name-specifier.
- ObjectType = ParsedType();
-
+ ObjectType = nullptr;
+
if (Tok.is(tok::code_completion)) {
// Code completion for a nested-name-specifier, where the code
// code completion token follows the '::'.
@@ -597,7 +597,7 @@
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
- /*ObjectType=*/ParsedType(), TemplateKWLoc, Name))
+ /*ObjectType=*/nullptr, TemplateKWLoc, Name))
return ExprError();
// This is only the direct operand of an & operator if it is not
@@ -659,7 +659,7 @@
// '::' unqualified-id
//
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
Token Replacement;
ExprResult Result =
@@ -841,6 +841,7 @@
// Parse capture.
LambdaCaptureKind Kind = LCK_ByCopy;
+ LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
SourceLocation Loc;
IdentifierInfo *Id = nullptr;
SourceLocation EllipsisLoc;
@@ -878,6 +879,8 @@
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
+ InitKind = LambdaCaptureInitKind::DirectInit;
+
ExprVector Exprs;
CommaLocsTy Commas;
if (SkippedInits) {
@@ -898,14 +901,13 @@
// to save the necessary state, and restore it later.
EnterExpressionEvaluationContext EC(Actions,
Sema::PotentiallyEvaluated);
- bool HadEquals = TryConsumeToken(tok::equal);
+
+ if (TryConsumeToken(tok::equal))
+ InitKind = LambdaCaptureInitKind::CopyInit;
+ else
+ InitKind = LambdaCaptureInitKind::ListInit;
if (!SkippedInits) {
- // Warn on constructs that will change meaning when we implement N3922
- if (!HadEquals && Tok.is(tok::l_brace)) {
- Diag(Tok, diag::warn_init_capture_direct_list_init)
- << FixItHint::CreateInsertion(Tok.getLocation(), "=");
- }
Init = ParseInitializer();
} else if (Tok.is(tok::l_brace)) {
BalancedDelimiterTracker Braces(*this, tok::l_brace);
@@ -993,19 +995,19 @@
// If x was not const, the second use would require 'L' to capture, and
// that would be an error.
- ParsedType InitCaptureParsedType;
+ ParsedType InitCaptureType;
if (Init.isUsable()) {
// Get the pointer and store it in an lvalue, so we can use it as an
// out argument.
Expr *InitExpr = Init.get();
// This performs any lvalue-to-rvalue conversions if necessary, which
// can affect what gets captured in the containing decl-context.
- QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization(
- Loc, Kind == LCK_ByRef, Id, InitExpr);
+ InitCaptureType = Actions.actOnLambdaInitCaptureInitialization(
+ Loc, Kind == LCK_ByRef, Id, InitKind, InitExpr);
Init = InitExpr;
- InitCaptureParsedType.set(InitCaptureType);
}
- Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType);
+ Intro.addCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init,
+ InitCaptureType);
}
T.consumeClose();
@@ -1566,7 +1568,8 @@
assert(Tok.is(tok::kw_co_yield) && "Not co_yield!");
SourceLocation Loc = ConsumeToken();
- ExprResult Expr = ParseAssignmentExpression();
+ ExprResult Expr = Tok.is(tok::l_brace) ? ParseBraceInitializer()
+ : ParseAssignmentExpression();
if (!Expr.isInvalid())
Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get());
return Expr;
@@ -1819,7 +1822,7 @@
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken();
- DS.Finish(Diags, PP, Policy);
+ DS.Finish(Actions, Policy);
return;
}
@@ -1875,12 +1878,12 @@
case tok::annot_decltype:
case tok::kw_decltype:
DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
- return DS.Finish(Diags, PP, Policy);
+ return DS.Finish(Actions, Policy);
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
- DS.Finish(Diags, PP, Policy);
+ DS.Finish(Actions, Policy);
return;
}
if (Tok.is(tok::annot_typename))
@@ -1888,7 +1891,7 @@
else
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
- DS.Finish(Diags, PP, Policy);
+ DS.Finish(Actions, Policy);
}
/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
@@ -1904,7 +1907,7 @@
///
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier);
- DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy());
+ DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
return false;
}
@@ -2410,9 +2413,8 @@
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
- ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(),
- &SS, false, false,
- ParsedType(),
+ ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false,
+ false, nullptr,
/*IsCtorOrDtorName=*/true,
/*NonTrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, IdLoc, IdLoc);
@@ -2448,13 +2450,11 @@
<< TemplateId->Name
<< FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
- ParsedType Ty = Actions.getTypeName(*TemplateId->Name,
- TemplateId->TemplateNameLoc,
- getCurScope(),
- &SS, false, false,
- ParsedType(),
- /*IsCtorOrDtorName=*/true,
- /*NontrivialTypeSourceInfo=*/true);
+ ParsedType Ty =
+ Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc,
+ getCurScope(), &SS, false, false, nullptr,
+ /*IsCtorOrDtorName=*/true,
+ /*NontrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
ConsumeToken();
@@ -2538,7 +2538,7 @@
if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext))
return true;
if (SS.isNotEmpty())
- ObjectType = ParsedType();
+ ObjectType = nullptr;
if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) ||
!SS.isSet()) {
Diag(TildeLoc, diag::err_destructor_tilde_scope);
@@ -2560,7 +2560,7 @@
SourceLocation ClassNameLoc = ConsumeToken();
if (TemplateSpecified || Tok.is(tok::less)) {
- Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc);
+ Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
ClassName, ClassNameLoc,
EnteringContext, ObjectType,
@@ -3026,7 +3026,7 @@
assert(isTypeIdInParens() && "Not a type-id!");
ExprResult Result(true);
- CastTy = ParsedType();
+ CastTy = nullptr;
// We need to disambiguate a very ugly part of the C++ syntax:
//
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 4896ff0..2cdb9d3 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -216,10 +216,8 @@
NextToken().isNot(tok::period) &&
getCurScope()->isInObjcMethodScope()) {
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
- return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
- ConsumeToken(),
- ParsedType(),
- nullptr);
+ return ParseAssignmentExprWithObjCMessageExprStart(
+ StartLoc, ConsumeToken(), nullptr, nullptr);
}
// Parse the receiver, which is either a type or an expression.
@@ -257,10 +255,8 @@
NextToken().is(tok::period), ReceiverType)) {
case Sema::ObjCSuperMessage:
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
- return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
- ConsumeToken(),
- ParsedType(),
- nullptr);
+ return ParseAssignmentExprWithObjCMessageExprStart(
+ StartLoc, ConsumeToken(), nullptr, nullptr);
case Sema::ObjCClassMessage:
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
@@ -320,10 +316,8 @@
if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
- return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
- SourceLocation(),
- ParsedType(),
- Idx.get());
+ return ParseAssignmentExprWithObjCMessageExprStart(
+ StartLoc, SourceLocation(), nullptr, Idx.get());
}
// If this is a normal array designator, remember it.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index cfbde09..4ae2afe 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -50,7 +50,7 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
Decl *SingleDecl = nullptr;
@@ -336,16 +336,11 @@
// Type arguments for the superclass or protocol conformances.
if (Tok.is(tok::less)) {
- parseObjCTypeArgsOrProtocolQualifiers(ParsedType(),
- typeArgsLAngleLoc,
- typeArgs,
- typeArgsRAngleLoc,
- LAngleLoc,
- protocols,
- protocolLocs,
- EndProtoLoc,
- /*consumeLastToken=*/true,
- /*warnOnIncompleteProtocols=*/true);
+ parseObjCTypeArgsOrProtocolQualifiers(
+ nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
+ protocols, protocolLocs, EndProtoLoc,
+ /*consumeLastToken=*/true,
+ /*warnOnIncompleteProtocols=*/true);
}
}
@@ -461,14 +456,8 @@
unsigned index = 0;
for (const auto &pair : protocolIdents) {
DeclResult typeParam = Actions.actOnObjCTypeParam(
- getCurScope(),
- ObjCTypeParamVariance::Invariant,
- SourceLocation(),
- index++,
- pair.first,
- pair.second,
- SourceLocation(),
- ParsedType());
+ getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
+ index++, pair.first, pair.second, SourceLocation(), nullptr);
if (typeParam.isUsable())
typeParams.push_back(typeParam.get());
}
@@ -505,8 +494,7 @@
if (Tok.is(tok::code_completion)) {
// FIXME: If these aren't protocol references, we'll need different
// completions.
- Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(),
- protocolIdents.size());
+ Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
cutOffParsing();
// FIXME: Better recovery here?.
@@ -545,16 +533,9 @@
}
// Create the type parameter.
- DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
- variance,
- varianceLoc,
- typeParams.size(),
- paramName,
- paramLoc,
- colonLoc,
- boundType.isUsable()
- ? boundType.get()
- : ParsedType());
+ DeclResult typeParam = Actions.actOnObjCTypeParam(
+ getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
+ paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
if (typeParam.isUsable())
typeParams.push_back(typeParam.get());
} while (TryConsumeToken(tok::comma));
@@ -605,7 +586,7 @@
// whether there are any protocol references.
lAngleLoc = SourceLocation();
rAngleLoc = SourceLocation();
- return list;
+ return invalid ? nullptr : list;
}
/// Parse an objc-type-parameter-list.
@@ -635,7 +616,6 @@
void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Decl *CDecl) {
SmallVector<Decl *, 32> allMethods;
- SmallVector<Decl *, 16> allProperties;
SmallVector<DeclGroupPtrTy, 8> allTUVariables;
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
@@ -791,12 +771,9 @@
SetterSel = SelectorTable::constructSetterSelector(
PP.getIdentifierTable(), PP.getSelectorTable(),
FD.D.getIdentifier());
- bool isOverridingProperty = false;
Decl *Property = Actions.ActOnProperty(
getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
- &isOverridingProperty, MethodImplKind);
- if (!isOverridingProperty)
- allProperties.push_back(Property);
+ MethodImplKind);
FD.complete(Property);
};
@@ -872,6 +849,7 @@
/// nullable
/// null_unspecified
/// null_resettable
+/// class
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
@@ -918,7 +896,7 @@
// getter/setter require extra treatment.
unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
- diag::err_objc_expected_equal_for_getter;
+ diag::err_objc_expected_equal_for_getter;
if (ExpectAndConsume(tok::equal, DiagID)) {
SkipUntil(tok::r_paren, StopAtSemi);
@@ -933,7 +911,6 @@
return cutOffParsing();
}
-
SourceLocation SelLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
@@ -988,6 +965,8 @@
// Also set the null_resettable bit.
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
+ } else if (II->isStr("class")) {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class);
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren, StopAtSemi);
@@ -1129,6 +1108,7 @@
case tok::kw__Bool:
case tok::kw__Complex:
case tok::kw___alignof:
+ case tok::kw___auto_type:
IdentifierInfo *II = Tok.getIdentifierInfo();
SelectorLoc = ConsumeToken();
return II;
@@ -1368,8 +1348,8 @@
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
- /*ReturnType=*/ ParsedType());
+ Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
+ /*ReturnType=*/nullptr);
cutOffParsing();
return nullptr;
}
@@ -1439,7 +1419,7 @@
if (ExpectAndConsume(tok::colon))
break;
- ArgInfo.Type = ParsedType();
+ ArgInfo.Type = nullptr;
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec,
Declarator::ObjCParameterContext,
@@ -1572,8 +1552,7 @@
while (1) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
- ProtocolIdents.size());
+ Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
cutOffParsing();
return true;
}
@@ -1676,8 +1655,7 @@
if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
} else {
- Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(),
- identifierLocPairs.size());
+ Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
}
cutOffParsing();
return;
@@ -2014,14 +1992,14 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
MaybeSkipAttributes(tok::objc_protocol);
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name.
- return DeclGroupPtrTy();
+ return nullptr;
}
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
@@ -2045,7 +2023,7 @@
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
Tok.getLocation()));
@@ -2056,7 +2034,7 @@
}
// Consume the ';'.
if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
- return DeclGroupPtrTy();
+ return nullptr;
return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs,
attrs.getList());
@@ -2071,7 +2049,7 @@
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
LAngleLoc, EndProtoLoc,
/*consumeLastToken=*/true))
- return DeclGroupPtrTy();
+ return nullptr;
Decl *ProtoType =
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
@@ -2105,7 +2083,7 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
MaybeSkipAttributes(tok::objc_implementation);
@@ -2113,7 +2091,7 @@
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected)
<< tok::identifier; // missing class or category name.
- return DeclGroupPtrTy();
+ return nullptr;
}
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
@@ -2146,7 +2124,7 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.is(tok::identifier)) {
@@ -2155,12 +2133,12 @@
} else {
Diag(Tok, diag::err_expected)
<< tok::identifier; // missing category name.
- return DeclGroupPtrTy();
+ return nullptr;
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected) << tok::r_paren;
SkipUntil(tok::r_paren); // don't stop at ';'
- return DeclGroupPtrTy();
+ return nullptr;
}
rparenLoc = ConsumeParen();
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
@@ -2187,7 +2165,7 @@
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected)
<< tok::identifier; // missing super class name.
- return DeclGroupPtrTy();
+ return nullptr;
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken(); // Consume super class name
@@ -2241,7 +2219,7 @@
else
// missing @implementation
Diag(atEnd.getBegin(), diag::err_expected_objc_container);
- return DeclGroupPtrTy();
+ return nullptr;
}
Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
@@ -2354,8 +2332,10 @@
propertyIvar = Tok.getIdentifierInfo();
propertyIvarLoc = ConsumeToken(); // consume ivar-name
}
- Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true,
- propertyId, propertyIvar, propertyIvarLoc);
+ Actions.ActOnPropertyImplDecl(
+ getCurScope(), atLoc, propertyLoc, true,
+ propertyId, propertyIvar, propertyIvarLoc,
+ ObjCPropertyQueryKind::OBJC_PR_query_unknown);
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); // consume ','
@@ -2375,6 +2355,31 @@
assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
"ParseObjCPropertyDynamic(): Expected '@dynamic'");
ConsumeToken(); // consume dynamic
+
+ bool isClassProperty = false;
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ if (!II) {
+ Diag(Tok, diag::err_objc_expected_property_attr) << II;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ } else {
+ SourceLocation AttrName = ConsumeToken(); // consume attribute name
+ if (II->isStr("class")) {
+ isClassProperty = true;
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected) << tok::r_paren;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ } else
+ ConsumeParen();
+ } else {
+ Diag(AttrName, diag::err_objc_expected_property_attr) << II;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ }
+ }
+ }
+
while (true) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
@@ -2390,8 +2395,11 @@
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); // consume property name
- Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false,
- propertyId, nullptr, SourceLocation());
+ Actions.ActOnPropertyImplDecl(
+ getCurScope(), atLoc, propertyLoc, false,
+ propertyId, nullptr, SourceLocation(),
+ isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
+ ObjCPropertyQueryKind::OBJC_PR_query_unknown);
if (Tok.isNot(tok::comma))
break;
@@ -2986,8 +2994,8 @@
// get in Objective-C.
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
- return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
- ParsedType(), nullptr);
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
+ nullptr);
// Parse the receiver, which is either a type or an expression.
bool IsExpr;
@@ -2998,9 +3006,8 @@
}
if (IsExpr)
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ParsedType(),
- static_cast<Expr*>(TypeOrExpr));
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
+ static_cast<Expr *>(TypeOrExpr));
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
ParsedType::getFromOpaquePtr(TypeOrExpr),
@@ -3016,8 +3023,8 @@
NextToken().is(tok::period),
ReceiverType)) {
case Sema::ObjCSuperMessage:
- return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
- ParsedType(), nullptr);
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
+ nullptr);
case Sema::ObjCClassMessage:
if (!ReceiverType) {
@@ -3058,8 +3065,8 @@
return Res;
}
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ParsedType(), Res.get());
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
+ Res.get());
}
/// \brief Parse the remainder of an Objective-C message following the
@@ -3293,8 +3300,7 @@
AtStrings.push_back(Lit.get());
}
- return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
- AtStrings.size());
+ return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
}
/// ParseObjCBooleanLiteral -
@@ -3445,7 +3451,7 @@
// Create the ObjCDictionaryLiteral.
return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
- Elements.data(), Elements.size());
+ Elements);
}
/// objc-encode-expression:
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 37eeaba..0531847 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -37,7 +37,8 @@
{OMPD_for, OMPD_simd, OMPD_for_simd},
{OMPD_parallel, OMPD_for, OMPD_parallel_for},
{OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},
- {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}};
+ {OMPD_parallel, OMPD_sections, OMPD_parallel_sections},
+ {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd}};
auto Tok = P.getCurToken();
auto DKind =
Tok.isAnnotation()
@@ -137,12 +138,15 @@
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_target_data:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_distribute:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end);
- return DeclGroupPtrTy();
+ return nullptr;
}
/// \brief Parsing of declarative or executable OpenMP directives.
@@ -157,11 +161,12 @@
/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
/// 'for simd' | 'parallel for simd' | 'target' | 'target data' |
-/// 'taskgroup' | 'teams' {clause}
+/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' {clause} |
+/// 'distribute'
/// annot_pragma_openmp_end
///
-StmtResult
-Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
+StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
+ AllowedContsructsKind Allowed) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<Expr *, 5> Identifiers;
@@ -181,6 +186,10 @@
switch (DKind) {
case OMPD_threadprivate:
+ if (Allowed != ACK_Any) {
+ Diag(Tok, diag::err_omp_immediate_directive)
+ << getOpenMPDirectiveName(DKind) << 0;
+ }
ConsumeToken();
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
// The last seen token is annot_pragma_openmp_end - need to check for
@@ -208,9 +217,9 @@
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_cancel:
- if (!StandAloneAllowed) {
+ if (Allowed == ACK_StatementsOpenMPNonStandalone) {
Diag(Tok, diag::err_omp_immediate_directive)
- << getOpenMPDirectiveName(DKind);
+ << getOpenMPDirectiveName(DKind) << 0;
}
HasAssociatedStatement = false;
// Fall through for further analysis.
@@ -232,7 +241,10 @@
case OMPD_target:
case OMPD_teams:
case OMPD_taskgroup:
- case OMPD_target_data: {
+ case OMPD_target_data:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_distribute: {
ConsumeToken();
// Parse directive name of the 'critical' directive if any.
if (DKind == OMPD_critical) {
@@ -287,6 +299,18 @@
// Consume final annot_pragma_openmp_end.
ConsumeToken();
+ // OpenMP [2.13.8, ordered Construct, Syntax]
+ // If the depend clause is specified, the ordered construct is a stand-alone
+ // directive.
+ if (DKind == OMPD_ordered && FirstClauses[OMPC_depend].getInt()) {
+ if (Allowed == ACK_StatementsOpenMPNonStandalone) {
+ Diag(Loc, diag::err_omp_immediate_directive)
+ << getOpenMPDirectiveName(DKind) << 1
+ << getOpenMPClauseName(OMPC_depend);
+ }
+ HasAssociatedStatement = false;
+ }
+
StmtResult AssociatedStmt;
if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
@@ -343,11 +367,11 @@
NoIdentIsFound = false;
if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
- } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ } else if (ParseUnqualifiedId(SS, false, false, false, nullptr,
TemplateKWLoc, Name)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -394,7 +418,9 @@
/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
/// mergeable-clause | flush-clause | read-clause | write-clause |
/// update-clause | capture-clause | seq_cst-clause | device-clause |
-/// simdlen-clause | threads-clause | simd-clause
+/// simdlen-clause | threads-clause | simd-clause | num_teams-clause |
+/// thread_limit-clause | priority-clause | grainsize-clause |
+/// nogroup-clause | num_tasks-clause | hint-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -415,6 +441,12 @@
case OMPC_collapse:
case OMPC_ordered:
case OMPC_device:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_hint:
// OpenMP [2.5, Restrictions]
// At most one num_threads clause can appear on the directive.
// OpenMP [2.8.1, simd construct, Restrictions]
@@ -426,6 +458,15 @@
// OpenMP [2.11.1, task Construct, Restrictions]
// At most one if clause can appear on the directive.
// At most one final clause can appear on the directive.
+ // OpenMP [teams Construct, Restrictions]
+ // At most one num_teams clause can appear on the directive.
+ // At most one thread_limit clause can appear on the directive.
+ // OpenMP [2.9.1, task Construct, Restrictions]
+ // At most one priority clause can appear on the directive.
+ // OpenMP [2.9.2, taskloop Construct, Restrictions]
+ // At most one grainsize clause can appear on the directive.
+ // OpenMP [2.9.2, taskloop Construct, Restrictions]
+ // At most one num_tasks clause can appear on the directive.
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
@@ -453,6 +494,7 @@
Clause = ParseOpenMPSimpleClause(CKind);
break;
case OMPC_schedule:
+ case OMPC_dist_schedule:
// OpenMP [2.7.1, Restrictions, p. 3]
// Only one schedule clause can appear on a loop directive.
if (!FirstClause) {
@@ -474,6 +516,7 @@
case OMPC_seq_cst:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_nogroup:
// OpenMP [2.7.1, Restrictions, p. 9]
// Only one ordered clause can appear on a loop directive.
// OpenMP [2.7.1, Restrictions, C/C++, p. 4]
@@ -497,7 +540,8 @@
case OMPC_copyprivate:
case OMPC_flush:
case OMPC_depend:
- Clause = ParseOpenMPVarListClause(CKind);
+ case OMPC_map:
+ Clause = ParseOpenMPVarListClause(DKind, CKind);
break;
case OMPC_unknown:
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
@@ -514,8 +558,8 @@
}
/// \brief Parsing of OpenMP clauses with single expressions like 'final',
-/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', 'thread_limit'
-/// or 'simdlen'.
+/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
+/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'.
///
/// final-clause:
/// 'final' '(' expression ')'
@@ -532,6 +576,18 @@
/// collapse-clause:
/// 'collapse' '(' expression ')'
///
+/// priority-clause:
+/// 'priority' '(' expression ')'
+///
+/// grainsize-clause:
+/// 'grainsize' '(' expression ')'
+///
+/// num_tasks-clause:
+/// 'num_tasks' '(' expression ')'
+///
+/// hint-clause:
+/// 'hint' '(' expression ')'
+///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
SourceLocation Loc = ConsumeToken();
@@ -609,6 +665,9 @@
/// simd-clause:
/// 'simd'
///
+/// nogroup-clause:
+/// 'nogroup'
+///
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();
@@ -621,7 +680,8 @@
/// argument like 'schedule' or 'dist_schedule'.
///
/// schedule-clause:
-/// 'schedule' '(' kind [',' expression ] ')'
+/// 'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ]
+/// ')'
///
/// if-clause:
/// 'if' '(' [ directive-name-modifier ':' ] expression ')'
@@ -636,24 +696,69 @@
return nullptr;
ExprResult Val;
- unsigned Arg;
- SourceLocation KLoc;
+ SmallVector<unsigned, 4> Arg;
+ SmallVector<SourceLocation, 4> KLoc;
if (Kind == OMPC_schedule) {
- Arg = getOpenMPSimpleClauseType(
+ enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };
+ Arg.resize(NumberOfElements);
+ KLoc.resize(NumberOfElements);
+ Arg[Modifier1] = OMPC_SCHEDULE_MODIFIER_unknown;
+ Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown;
+ Arg[ScheduleKind] = OMPC_SCHEDULE_unknown;
+ auto KindModifier = getOpenMPSimpleClauseType(
Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
- KLoc = Tok.getLocation();
+ if (KindModifier > OMPC_SCHEDULE_unknown) {
+ // Parse 'modifier'
+ Arg[Modifier1] = KindModifier;
+ KLoc[Modifier1] = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ if (Tok.is(tok::comma)) {
+ // Parse ',' 'modifier'
+ ConsumeAnyToken();
+ KindModifier = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
+ Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown
+ ? KindModifier
+ : (unsigned)OMPC_SCHEDULE_unknown;
+ KLoc[Modifier2] = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ }
+ // Parse ':'
+ if (Tok.is(tok::colon))
+ ConsumeAnyToken();
+ else
+ Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier";
+ KindModifier = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
+ }
+ Arg[ScheduleKind] = KindModifier;
+ KLoc[ScheduleKind] = Tok.getLocation();
if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
- if ((Arg == OMPC_SCHEDULE_static || Arg == OMPC_SCHEDULE_dynamic ||
- Arg == OMPC_SCHEDULE_guided) &&
+ if ((Arg[ScheduleKind] == OMPC_SCHEDULE_static ||
+ Arg[ScheduleKind] == OMPC_SCHEDULE_dynamic ||
+ Arg[ScheduleKind] == OMPC_SCHEDULE_guided) &&
Tok.is(tok::comma))
DelimLoc = ConsumeAnyToken();
+ } else if (Kind == OMPC_dist_schedule) {
+ Arg.push_back(getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)));
+ KLoc.push_back(Tok.getLocation());
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma))
+ DelimLoc = ConsumeAnyToken();
} else {
assert(Kind == OMPC_if);
- KLoc = Tok.getLocation();
- Arg = ParseOpenMPDirectiveKind(*this);
- if (Arg != OMPD_unknown) {
+ KLoc.push_back(Tok.getLocation());
+ Arg.push_back(ParseOpenMPDirectiveKind(*this));
+ if (Arg.back() != OMPD_unknown) {
ConsumeToken();
if (Tok.is(tok::colon))
DelimLoc = ConsumeToken();
@@ -663,8 +768,9 @@
}
}
- bool NeedAnExpression =
- (Kind == OMPC_schedule && DelimLoc.isValid()) || Kind == OMPC_if;
+ bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||
+ (Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||
+ Kind == OMPC_if;
if (NeedAnExpression) {
SourceLocation ELoc = Tok.getLocation();
ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
@@ -725,7 +831,7 @@
}
return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
/*AllowDestructorName*/ false,
- /*AllowConstructorName*/ false, ParsedType(),
+ /*AllowConstructorName*/ false, nullptr,
TemplateKWLoc, ReductionId);
}
@@ -751,13 +857,17 @@
/// flush-clause:
/// 'flush' '(' list ')'
/// depend-clause:
-/// 'depend' '(' in | out | inout : list ')'
+/// 'depend' '(' in | out | inout : list | source ')'
+/// map-clause:
+/// 'map' '(' [ [ always , ]
+/// to | from | tofrom | alloc | release | delete ':' ] list ')';
///
/// For 'linear' clause linear-list may have the following forms:
/// list
/// modifier(list)
/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
-OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
+OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
+ OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
SourceLocation ColonLoc = SourceLocation();
@@ -769,7 +879,11 @@
// OpenMP 4.1 [2.15.3.7, linear Clause]
// If no modifier is specified it is assumed to be val.
OpenMPLinearClauseKind LinearModifier = OMPC_LINEAR_val;
- SourceLocation DepLinLoc;
+ OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
+ OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
+ bool MapTypeModifierSpecified = false;
+ bool UnexpectedId = false;
+ SourceLocation DepLinMapLoc;
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
@@ -784,7 +898,7 @@
if (Kind == OMPC_reduction) {
ColonProtectionRAIIObject ColonRAII(*this);
if (getLangOpts().CPlusPlus) {
- ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, nullptr, false);
}
InvalidReductionId =
ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
@@ -802,34 +916,109 @@
ColonProtectionRAIIObject ColonRAII(*this);
DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
- DepLinLoc = Tok.getLocation();
+ DepLinMapLoc = Tok.getLocation();
if (DepKind == OMPC_DEPEND_unknown) {
SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
} else {
ConsumeToken();
+ // Special processing for depend(source) clause.
+ if (DKind == OMPD_ordered && DepKind == OMPC_DEPEND_source) {
+ // Parse ')'.
+ T.consumeClose();
+ return Actions.ActOnOpenMPVarListClause(
+ Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen,
+ /*ColonLoc=*/SourceLocation(), Tok.getLocation(),
+ ReductionIdScopeSpec, DeclarationNameInfo(), DepKind,
+ LinearModifier, MapTypeModifier, MapType, DepLinMapLoc);
+ }
}
if (Tok.is(tok::colon)) {
ColonLoc = ConsumeToken();
} else {
- Diag(Tok, diag::warn_pragma_expected_colon) << "dependency type";
+ Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
+ : diag::warn_pragma_expected_colon)
+ << "dependency type";
}
} else if (Kind == OMPC_linear) {
// Try to parse modifier if any.
if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
LinearModifier = static_cast<OpenMPLinearClauseKind>(
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
- DepLinLoc = ConsumeToken();
+ DepLinMapLoc = ConsumeToken();
LinearT.consumeOpen();
NeedRParenForLinear = true;
}
+ } else if (Kind == OMPC_map) {
+ // Handle map type for map clause.
+ ColonProtectionRAIIObject ColonRAII(*this);
+
+ // the first identifier may be a list item, a map-type or
+ // a map-type-modifier
+ MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
+ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
+ DepLinMapLoc = Tok.getLocation();
+ bool ColonExpected = false;
+
+ if (Tok.is(tok::identifier)) {
+ if (PP.LookAhead(0).is(tok::colon)) {
+ MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
+ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
+ if (MapType == OMPC_MAP_unknown) {
+ Diag(Tok, diag::err_omp_unknown_map_type);
+ } else if (MapType == OMPC_MAP_always) {
+ Diag(Tok, diag::err_omp_map_type_missing);
+ }
+ ConsumeToken();
+ } else if (PP.LookAhead(0).is(tok::comma)) {
+ if (PP.LookAhead(1).is(tok::identifier) &&
+ PP.LookAhead(2).is(tok::colon)) {
+ MapTypeModifier =
+ static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
+ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
+ if (MapTypeModifier != OMPC_MAP_always) {
+ Diag(Tok, diag::err_omp_unknown_map_type_modifier);
+ MapTypeModifier = OMPC_MAP_unknown;
+ } else {
+ MapTypeModifierSpecified = true;
+ }
+
+ ConsumeToken();
+ ConsumeToken();
+
+ MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
+ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
+ if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) {
+ Diag(Tok, diag::err_omp_unknown_map_type);
+ }
+ ConsumeToken();
+ } else {
+ MapType = OMPC_MAP_tofrom;
+ }
+ } else {
+ MapType = OMPC_MAP_tofrom;
+ }
+ } else {
+ UnexpectedId = true;
+ }
+
+ if (Tok.is(tok::colon)) {
+ ColonLoc = ConsumeToken();
+ } else if (ColonExpected) {
+ Diag(Tok, diag::warn_pragma_expected_colon) << "map type";
+ }
}
SmallVector<Expr *, 5> Vars;
- bool IsComma = ((Kind != OMPC_reduction) && (Kind != OMPC_depend)) ||
- ((Kind == OMPC_reduction) && !InvalidReductionId) ||
- ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown);
+ bool IsComma =
+ ((Kind != OMPC_reduction) && (Kind != OMPC_depend) &&
+ (Kind != OMPC_map)) ||
+ ((Kind == OMPC_reduction) && !InvalidReductionId) ||
+ ((Kind == OMPC_map) && (UnexpectedId || MapType != OMPC_MAP_unknown) &&
+ (!MapTypeModifierSpecified ||
+ (MapTypeModifierSpecified && MapTypeModifier == OMPC_MAP_always))) ||
+ ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown);
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
@@ -879,14 +1068,16 @@
T.consumeClose();
if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) ||
(Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) ||
- InvalidReductionId)
+ (Kind == OMPC_map && MapType == OMPC_MAP_unknown) ||
+ InvalidReductionId) {
return nullptr;
+ }
return Actions.ActOnOpenMPVarListClause(
Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
ReductionIdScopeSpec,
ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
: DeclarationNameInfo(),
- DepKind, LinearModifier, DepLinLoc);
+ DepKind, LinearModifier, MapTypeModifier, MapType, DepLinMapLoc);
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 4430eb8..bc70942 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -377,6 +377,14 @@
Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
}
+void Parser::HandlePragmaDump() {
+ assert(Tok.is(tok::annot_pragma_dump));
+ IdentifierInfo *II =
+ reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue());
+ Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
+ ConsumeToken();
+}
+
void Parser::HandlePragmaWeak() {
assert(Tok.is(tok::annot_pragma_weak));
SourceLocation PragmaLoc = ConsumeToken();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 35cb0fe..6c27b27 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -32,14 +32,18 @@
/// \brief Parse a standalone statement (for instance, as the body of an 'if',
/// 'while', or 'for').
-StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc) {
+StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
+ bool AllowOpenMPStandalone) {
StmtResult Res;
// We may get back a null statement if we found a #pragma. Keep going until
// we get an actual statement.
do {
StmtVector Stmts;
- Res = ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
+ Res = ParseStatementOrDeclaration(
+ Stmts, AllowOpenMPStandalone ? ACK_StatementsOpenMPAnyExecutable
+ : ACK_StatementsOpenMPNonStandalone,
+ TrailingElseLoc);
} while (!Res.isInvalid() && !Res.get());
return Res;
@@ -95,7 +99,8 @@
/// [OBC] '@' 'throw' ';'
///
StmtResult
-Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -103,8 +108,8 @@
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
- StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
- OnlyStatement, TrailingElseLoc, Attrs);
+ StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
+ Stmts, Allowed, TrailingElseLoc, Attrs);
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");
@@ -146,7 +151,7 @@
StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
- bool OnlyStatement, SourceLocation *TrailingElseLoc,
+ AllowedContsructsKind Allowed, SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
const char *SemiError = nullptr;
StmtResult Res;
@@ -202,7 +207,8 @@
}
default: {
- if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
+ if ((getLangOpts().CPlusPlus || Allowed == ACK_Any) &&
+ isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext,
DeclEnd, Attrs);
@@ -346,7 +352,7 @@
case tok::annot_pragma_openmp:
ProhibitAttributes(Attrs);
- return ParseOpenMPDeclarativeOrExecutableDirective(!OnlyStatement);
+ return ParseOpenMPDeclarativeOrExecutableDirective(Allowed);
case tok::annot_pragma_ms_pointers_to_members:
ProhibitAttributes(Attrs);
@@ -358,9 +364,18 @@
HandlePragmaMSPragma();
return StmtEmpty();
+ case tok::annot_pragma_ms_vtordisp:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSVtorDisp();
+ return StmtEmpty();
+
case tok::annot_pragma_loop_hint:
ProhibitAttributes(Attrs);
- return ParsePragmaLoopHint(Stmts, OnlyStatement, TrailingElseLoc, Attrs);
+ return ParsePragmaLoopHint(Stmts, Allowed, TrailingElseLoc, Attrs);
+
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -578,7 +593,8 @@
// can't handle GNU attributes), so only call it in the one case where
// GNU attributes are allowed.
SubStmt = ParseStatementOrDeclarationAfterAttributes(
- Stmts, /*OnlyStmts*/ true, nullptr, TempAttrs);
+ Stmts, /*Allowed=*/ACK_StatementsOpenMPNonStandalone, nullptr,
+ TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
SubStmt = Actions.ProcessStmtAttributes(
SubStmt.get(), TempAttrs.getList(), TempAttrs.Range);
@@ -717,7 +733,8 @@
// continue parsing the sub-stmt.
if (Case.isInvalid()) {
if (TopLevelCase.isInvalid()) // No parsed case stmts.
- return ParseStatement();
+ return ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
// Otherwise, just don't add it as a nested case.
} else {
// If this is the first case statement we parsed, it becomes TopLevelCase.
@@ -737,7 +754,8 @@
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
} else {
// Nicely diagnose the common error "switch (X) { case 4: }", which is
// not valid. If ColonLoc doesn't point to a valid text location, there was
@@ -789,7 +807,8 @@
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
} else {
// Diagnose the common error "switch (X) {... default: }", which is
// not valid.
@@ -885,6 +904,12 @@
case tok::annot_pragma_ms_pragma:
HandlePragmaMSPragma();
break;
+ case tok::annot_pragma_ms_vtordisp:
+ HandlePragmaMSVtorDisp();
+ break;
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ break;
default:
checkForPragmas = false;
break;
@@ -948,8 +973,8 @@
Stmts.push_back(R.get());
}
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
@@ -957,7 +982,7 @@
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
- R = ParseStatementOrDeclaration(Stmts, false);
+ R = ParseStatementOrDeclaration(Stmts, ACK_Any);
} else {
// __extension__ can start declarations and it can also be a unary
// operator for expressions. Consume multiple __extension__ markers here
@@ -1607,7 +1632,7 @@
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy());
+ Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
cutOffParsing();
return StmtError();
}
@@ -1853,7 +1878,8 @@
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
}
-StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
+StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
// Create temporary attribute list.
@@ -1876,7 +1902,7 @@
MaybeParseCXX11Attributes(Attrs);
StmtResult S = ParseStatementOrDeclarationAfterAttributes(
- Stmts, OnlyStatement, TrailingElseLoc, Attrs);
+ Stmts, Allowed, TrailingElseLoc, Attrs);
Attrs.takeAllFrom(TempAttrs);
return S;
@@ -1895,6 +1921,11 @@
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
+ // Save and reset current vtordisp stack if we have entered a C++ method body.
+ bool IsCXXMethod =
+ getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
+ Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod);
+
// Do not enter a scope for the brace, as the arguments are in the same scope
// (the function body) as the body itself. Instead, just read the statement
// list and put it into a CompoundStmt for safe keeping.
@@ -1934,6 +1965,11 @@
return Actions.ActOnSkippedFunctionBody(Decl);
}
+ // Save and reset current vtordisp stack if we have entered a C++ method body.
+ bool IsCXXMethod =
+ getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
+ Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod);
+
SourceLocation LBraceLoc = Tok.getLocation();
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
// If we failed to parse the try-catch, we just give the function an empty
@@ -2164,7 +2200,7 @@
// Condition is true, parse the statements.
while (Tok.isNot(tok::r_brace)) {
- StmtResult R = ParseStatementOrDeclaration(Stmts, false);
+ StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any);
if (R.isUsable())
Stmts.push_back(R.get());
}
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index d328139..11b0c0a 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -23,10 +23,10 @@
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
@@ -209,23 +209,27 @@
// Parse an optional scope-specifier if we're in C++.
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus) {
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
}
// Require an identifier here.
SourceLocation TemplateKWLoc;
UnqualifiedId Id;
- bool Invalid =
- ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
- /*ObjectType=*/ParsedType(), TemplateKWLoc, Id);
-
- // Perform the lookup.
- ExprResult Result = Actions.LookupInlineAsmIdentifier(
- SS, TemplateKWLoc, Id, Info, IsUnevaluatedContext);
-
+ bool Invalid = true;
+ ExprResult Result;
+ if (Tok.is(tok::kw_this)) {
+ Result = ParseCXXThis();
+ Invalid = false;
+ } else {
+ Invalid = ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*ObjectType=*/nullptr, TemplateKWLoc, Id);
+ // Perform the lookup.
+ Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
+ IsUnevaluatedContext);
+ }
// While the next two tokens are 'period' 'identifier', repeatedly parse it as
// a field access. We have to avoid consuming assembler directives that look
// like '.' 'else'.
@@ -236,9 +240,8 @@
ConsumeToken(); // Consume the period.
IdentifierInfo *Id = Tok.getIdentifierInfo();
ConsumeToken(); // Consume the identifier.
- unsigned OffsetUnused;
- Result = Actions.LookupInlineAsmVarDeclField(
- Result.get(), Id->getName(), OffsetUnused, Info, Tok.getLocation());
+ Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
+ Info, Tok.getLocation());
}
// Figure out how many tokens we are into LineToks.
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 3a964dd..ca50315 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -126,8 +126,7 @@
Actions.ActOnTemplateParameterList(CurTemplateDepthTracker.getDepth(),
ExportLoc,
TemplateLoc, LAngleLoc,
- TemplateParams.data(),
- TemplateParams.size(), RAngleLoc));
+ TemplateParams, RAngleLoc));
if (!TemplateParams.empty()) {
isSpecialization = false;
@@ -280,8 +279,8 @@
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
- 0, LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
+ LAngleLoc));
return ParseFunctionDefinition(
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
@@ -631,8 +630,7 @@
TemplateParameterList *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
- TemplateParams.data(),
- TemplateParams.size(),
+ TemplateParams,
RAngleLoc);
// Grab a default argument (if available).
@@ -695,7 +693,8 @@
// end of the template-parameter-list rather than a greater-than
// operator.
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(Actions,
+ Sema::ConstantEvaluated);
DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (DefaultArg.isInvalid())
@@ -828,6 +827,7 @@
}
// Strip the initial '>' from the token.
+ Token PrevTok = Tok;
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
areTokensAdjacent(Tok, Next)) {
// Join two adjacent '=' tokens into one, for cases like:
@@ -844,6 +844,21 @@
PP.getSourceManager(),
getLangOpts()));
+ // The advance from '>>' to '>' in a ObjectiveC template argument list needs
+ // to be properly reflected in the token cache to allow correct interaction
+ // between annotation and backtracking.
+ if (ObjCGenericList && PrevTok.getKind() == tok::greatergreater &&
+ RemainingToken == tok::greater && PP.IsPreviousCachedToken(PrevTok)) {
+ PrevTok.setKind(RemainingToken);
+ PrevTok.setLength(1);
+ // Break tok::greatergreater into two tok::greater but only add the second
+ // one in case the client asks to consume the last token.
+ if (ConsumeLastToken)
+ PP.ReplacePreviousCachedToken({PrevTok, Tok});
+ else
+ PP.ReplacePreviousCachedToken({PrevTok});
+ }
+
if (!ConsumeLastToken) {
// Since we're not supposed to consume the '>' token, we need to push
// this token and revert the current token back to the '>'.
@@ -1062,7 +1077,7 @@
TemplateId->RAngleLoc);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get());
+ setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
Tok.setLocation(TemplateId->SS.getBeginLoc());
// End location stays the same
@@ -1095,9 +1110,9 @@
// followed by a token that terminates a template argument, such as ',',
// '>', or (in some cases) '>>'.
CXXScopeSpec SS; // nested-name-specifier, if present
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ ParseOptionalCXXScopeSpecifier(SS, nullptr,
/*EnteringContext=*/false);
-
+
ParsedTemplateArgument Result;
SourceLocation EllipsisLoc;
if (SS.isSet() && Tok.is(tok::kw_template)) {
@@ -1118,11 +1133,10 @@
// template argument.
TemplateTy Template;
if (isEndOfTemplateArgument(Tok) &&
- Actions.ActOnDependentTemplateName(getCurScope(),
- SS, TemplateKWLoc, Name,
- /*ObjectType=*/ ParsedType(),
- /*EnteringContext=*/false,
- Template))
+ Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, TemplateKWLoc, Name,
+ /*ObjectType=*/nullptr,
+ /*EnteringContext=*/false, Template))
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
} else if (Tok.is(tok::identifier)) {
@@ -1136,13 +1150,11 @@
if (isEndOfTemplateArgument(Tok)) {
bool MemberOfUnknownSpecialization;
- TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
- /*hasTemplateKeyword=*/false,
- Name,
- /*ObjectType=*/ ParsedType(),
- /*EnteringContext=*/false,
- Template,
- MemberOfUnknownSpecialization);
+ TemplateNameKind TNK = Actions.isTemplateName(
+ getCurScope(), SS,
+ /*hasTemplateKeyword=*/false, Name,
+ /*ObjectType=*/nullptr,
+ /*EnteringContext=*/false, Template, MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
// We have an id-expression that refers to a class template or
// (C++0x) alias template.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 9d2a2b9..6fbcfd9 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1089,6 +1089,7 @@
/// [GNU] typeof-specifier
/// [GNU] '_Complex'
/// [C++11] 'auto'
+/// [GNU] '__auto_type'
/// [C++11] 'decltype' ( expression )
/// [C++1y] 'decltype' ( 'auto' )
///
@@ -1262,6 +1263,7 @@
case tok::kw_restrict:
case tok::kw__Complex:
case tok::kw___attribute:
+ case tok::kw___auto_type:
return TPResult::True;
// Microsoft
@@ -1515,6 +1517,7 @@
case tok::kw_double:
case tok::kw_void:
case tok::kw___unknown_anytype:
+ case tok::kw___auto_type:
return true;
case tok::kw_auto:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 26dc399..5eb8383 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -545,7 +545,7 @@
if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof))
ConsumeToken();
- Result = DeclGroupPtrTy();
+ Result = nullptr;
switch (Tok.getKind()) {
case tok::annot_pragma_unused:
HandlePragmaUnused();
@@ -625,49 +625,52 @@
if (PP.isCodeCompletionReached()) {
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
Decl *SingleDecl = nullptr;
switch (Tok.getKind()) {
case tok::annot_pragma_vis:
HandlePragmaVisibility();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_pack:
HandlePragmaPack();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_msstruct:
HandlePragmaMSStruct();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_align:
HandlePragmaAlign();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_weak:
HandlePragmaWeak();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_weakalias:
HandlePragmaWeakAlias();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_redefine_extname:
HandlePragmaRedefineExtname();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_openmp:
return ParseOpenMPDeclarativeDirective();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_ms_vtordisp:
HandlePragmaMSVtorDisp();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::annot_pragma_ms_pragma:
HandlePragmaMSPragma();
- return DeclGroupPtrTy();
+ return nullptr;
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ return nullptr;
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
@@ -678,10 +681,10 @@
case tok::r_brace:
Diag(Tok, diag::err_extraneous_closing_brace);
ConsumeBrace();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::eof:
Diag(Tok, diag::err_expected_external_declaration);
- return DeclGroupPtrTy();
+ return nullptr;
case tok::kw___extension__: {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
@@ -709,7 +712,7 @@
"top-level asm block");
if (Result.isInvalid())
- return DeclGroupPtrTy();
+ return nullptr;
SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc);
break;
}
@@ -720,7 +723,7 @@
if (!getLangOpts().ObjC1) {
Diag(Tok, diag::err_expected_external_declaration);
ConsumeToken();
- return DeclGroupPtrTy();
+ return nullptr;
}
SingleDecl = ParseObjCMethodDefinition();
break;
@@ -729,7 +732,7 @@
CurParsedObjCImpl? Sema::PCC_ObjCImplementation
: Sema::PCC_Namespace);
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -793,8 +796,8 @@
case tok::kw___if_exists:
case tok::kw___if_not_exists:
ParseMicrosoftIfExistsExternalDeclaration();
- return DeclGroupPtrTy();
-
+ return nullptr;
+
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
@@ -873,7 +876,7 @@
// may get this far before the problem becomes obvious.
if (DS.hasTagDefinition() &&
DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level))
- return DeclGroupPtrTy();
+ return nullptr;
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -896,7 +899,7 @@
!Tok.isObjCAtKeyword(tok::objc_protocol)) {
Diag(Tok, diag::err_objc_unexpected_attr);
SkipUntil(tok::semi); // FIXME: better skip?
- return DeclGroupPtrTy();
+ return nullptr;
}
DS.abort();
@@ -1094,14 +1097,16 @@
SourceLocation KWLoc;
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_deleted_function
- : diag::ext_deleted_function);
+ ? diag::warn_cxx98_compat_defaulted_deleted_function
+ : diag::ext_defaulted_deleted_function)
+ << 1 /* deleted */;
Actions.SetDeclDeleted(Res, KWLoc);
Delete = true;
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_defaulted_function
- : diag::ext_defaulted_function);
+ ? diag::warn_cxx98_compat_defaulted_deleted_function
+ : diag::ext_defaulted_deleted_function)
+ << 0 /* defaulted */;
Actions.SetDeclDefaulted(Res, KWLoc);
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
@@ -1395,7 +1400,7 @@
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus &&
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext))
return ANK_Error;
if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
@@ -1583,9 +1588,9 @@
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(),
- /*EnteringContext=*/false,
- nullptr, /*IsTypename*/ true))
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*EnteringContext=*/false, nullptr,
+ /*IsTypename*/ true))
return true;
if (!SS.isSet()) {
if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||
@@ -1641,7 +1646,7 @@
SourceLocation EndLoc = Tok.getLastLoc();
Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Ty.isInvalid() ? ParsedType() : Ty.get());
+ setTypeAnnotation(Tok, Ty.isInvalid() ? nullptr : Ty.get());
Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(TypenameLoc);
PP.AnnotateCachedTokens(Tok);
@@ -1653,7 +1658,7 @@
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext))
return true;
return TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, NeedType,
@@ -1670,15 +1675,12 @@
if (Tok.is(tok::identifier)) {
IdentifierInfo *CorrectedII = nullptr;
// Determine whether the identifier is a type name.
- if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), getCurScope(),
- &SS, false,
- NextToken().is(tok::period),
- ParsedType(),
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/ true,
- NeedType ? &CorrectedII
- : nullptr)) {
+ if (ParsedType Ty = Actions.getTypeName(
+ *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
+ false, NextToken().is(tok::period), nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo*/ true,
+ NeedType ? &CorrectedII : nullptr)) {
// A FixIt was applied as a result of typo correction
if (CorrectedII)
Tok.setIdentifierInfo(CorrectedII);
@@ -1729,12 +1731,11 @@
UnqualifiedId TemplateName;
TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
bool MemberOfUnknownSpecialization;
- if (TemplateNameKind TNK
- = Actions.isTemplateName(getCurScope(), SS,
- /*hasTemplateKeyword=*/false, TemplateName,
- /*ObjectType=*/ ParsedType(),
- EnteringContext,
- Template, MemberOfUnknownSpecialization)) {
+ if (TemplateNameKind TNK =
+ Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false, TemplateName,
+ /*ObjectType=*/nullptr, EnteringContext,
+ Template, MemberOfUnknownSpecialization)) {
// Consume the identifier.
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
@@ -1788,7 +1789,7 @@
"Cannot be a type or scope token!");
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext))
return true;
if (SS.isEmpty())
return false;
@@ -1892,7 +1893,7 @@
// Parse nested-name-specifier.
if (getLangOpts().CPlusPlus)
- ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(),
+ ParseOptionalCXXScopeSpecifier(Result.SS, nullptr,
/*EnteringContext=*/false);
// Check nested-name specifier.
@@ -1903,8 +1904,8 @@
// Parse the unqualified-id.
SourceLocation TemplateKWLoc; // FIXME: parsed, but unused.
- if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(),
- TemplateKWLoc, Result.Name)) {
+ if (ParseUnqualifiedId(Result.SS, false, true, true, nullptr, TemplateKWLoc,
+ Result.Name)) {
T.skipToEnd();
return true;
}
@@ -1985,12 +1986,12 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteModuleImport(ImportLoc, Path);
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
Diag(Tok, diag::err_module_expected_ident);
SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return nullptr;
}
// Record this part of the module path.
@@ -2008,14 +2009,14 @@
if (PP.hadModuleLoaderFatalFailure()) {
// With a fatal failure in the module loader, we abort parsing.
cutOffParsing();
- return DeclGroupPtrTy();
+ return nullptr;
}
DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
- return DeclGroupPtrTy();
-
+ return nullptr;
+
return Actions.ConvertDeclToDeclGroup(Import.get());
}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 94ec796..5f74343 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -34,7 +34,6 @@
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
@@ -657,8 +656,7 @@
CharSourceRange::getCharRange(If->getLocStart(),
Then->getLocStart()));
if (Else) {
- SourceLocation ElseKwLoc = Lexer::getLocForEndOfToken(
- Then->getLocEnd(), 0, S.getSourceManager(), S.getLangOpts());
+ SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getLocEnd());
Fixit2 = FixItHint::CreateRemoval(
SourceRange(ElseKwLoc, Else->getLocEnd()));
}
@@ -1341,20 +1339,16 @@
// the same as insertion order. This is needed to obtain a deterministic
// order of diagnostics when calling flushDiagnostics().
typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
- UsesMap *uses;
+ UsesMap uses;
public:
- UninitValsDiagReporter(Sema &S) : S(S), uses(nullptr) {}
+ UninitValsDiagReporter(Sema &S) : S(S) {}
~UninitValsDiagReporter() override { flushDiagnostics(); }
MappedType &getUses(const VarDecl *vd) {
- if (!uses)
- uses = new UsesMap();
-
- MappedType &V = (*uses)[vd];
+ MappedType &V = uses[vd];
if (!V.getPointer())
V.setPointer(new UsesVec());
-
return V;
}
@@ -1368,10 +1362,7 @@
}
void flushDiagnostics() {
- if (!uses)
- return;
-
- for (const auto &P : *uses) {
+ for (const auto &P : uses) {
const VarDecl *vd = P.first;
const MappedType &V = P.second;
@@ -1412,7 +1403,8 @@
// Release the uses vector.
delete vec;
}
- delete uses;
+
+ uses.clear();
}
private:
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 05ec5d4..6f6c4ca 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -1,4 +1,4 @@
-//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
+//===--- DeclSpec.cpp - Declaration Specifier Semantic Analysis -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,29 +15,19 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/ErrorHandling.h"
#include <cstring>
using namespace clang;
-static DiagnosticBuilder Diag(DiagnosticsEngine &D, SourceLocation Loc,
- unsigned DiagID) {
- return D.Report(Loc, DiagID);
-}
-
-
void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
assert(TemplateId && "NULL template-id annotation?");
Kind = IK_TemplateId;
@@ -280,6 +270,7 @@
case DeclaratorChunk::Array:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return false;
}
llvm_unreachable("Invalid type chunk");
@@ -288,6 +279,7 @@
switch (DS.getTypeSpecType()) {
case TST_atomic:
case TST_auto:
+ case TST_auto_type:
case TST_bool:
case TST_char:
case TST_char16:
@@ -476,6 +468,7 @@
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
+ case DeclSpec::TST_auto_type: return "__auto_type";
case DeclSpec::TST_decltype: return "(decltype)";
case DeclSpec::TST_decltype_auto: return "decltype(auto)";
case DeclSpec::TST_underlyingType: return "__underlying_type";
@@ -514,12 +507,12 @@
case SCS_extern:
case SCS_private_extern:
case SCS_static:
- if (S.getLangOpts().OpenCLVersion < 120) {
- DiagID = diag::err_opencl_unknown_type_specifier;
- PrevSpec = getSpecifierName(SC);
- return true;
- }
- break;
+ if (S.getLangOpts().OpenCLVersion < 120) {
+ DiagID = diag::err_opencl_unknown_type_specifier;
+ PrevSpec = getSpecifierName(SC);
+ return true;
+ }
+ break;
case SCS_auto:
case SCS_register:
DiagID = diag::err_opencl_unknown_type_specifier;
@@ -721,6 +714,22 @@
return false;
}
+bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
+
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy);
+ DiagID = diag::err_invalid_decl_spec_combination;
+ return true;
+ }
+
+ if (isPipe) {
+ TypeSpecPipe = TSP_pipe;
+ }
+ return false;
+}
+
bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
@@ -931,7 +940,7 @@
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
-void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPolicy &Policy) {
+void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
@@ -954,8 +963,8 @@
for (unsigned I = 0; I != NumLocs; ++I) {
if (ExtraLocs[I].isValid()) {
if (FirstLoc.isInvalid() ||
- PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I],
- FirstLoc))
+ S.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I],
+ FirstLoc))
FirstLoc = ExtraLocs[I];
Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]);
}
@@ -965,7 +974,7 @@
TypeSpecSign = TSS_unspecified;
TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false;
TypeQualifiers = 0;
- Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined)
+ S.Diag(TSTLoc, diag::err_decltype_auto_cannot_be_combined)
<< Hints[0] << Hints[1] << Hints[2] << Hints[3]
<< Hints[4] << Hints[5] << Hints[6] << Hints[7];
}
@@ -975,14 +984,14 @@
if (TypeAltiVecBool) {
// Sign specifiers are not allowed with vector bool. (PIM 2.1)
if (TypeSpecSign != TSS_unspecified) {
- Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec)
+ S.Diag(TSSLoc, diag::err_invalid_vector_bool_decl_spec)
<< getSpecifierName((TSS)TypeSpecSign);
}
// Only char/int are valid with vector bool. (PIM 2.1)
if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) &&
(TypeSpecType != TST_int)) || TypeAltiVecPixel) {
- Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec)
+ S.Diag(TSTLoc, diag::err_invalid_vector_bool_decl_spec)
<< (TypeAltiVecPixel ? "__pixel" :
getSpecifierName((TST)TypeSpecType, Policy));
}
@@ -990,15 +999,15 @@
// Only 'short' and 'long long' are valid with vector bool. (PIM 2.1)
if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) &&
(TypeSpecWidth != TSW_longlong))
- Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec)
+ S.Diag(TSWLoc, diag::err_invalid_vector_bool_decl_spec)
<< getSpecifierName((TSW)TypeSpecWidth);
// vector bool long long requires VSX support or ZVector.
if ((TypeSpecWidth == TSW_longlong) &&
- (!PP.getTargetInfo().hasFeature("vsx")) &&
- (!PP.getTargetInfo().hasFeature("power8-vector")) &&
- !PP.getLangOpts().ZVector)
- Diag(D, TSTLoc, diag::err_invalid_vector_long_long_decl_spec);
+ (!S.Context.getTargetInfo().hasFeature("vsx")) &&
+ (!S.Context.getTargetInfo().hasFeature("power8-vector")) &&
+ !S.getLangOpts().ZVector)
+ S.Diag(TSTLoc, diag::err_invalid_vector_long_long_decl_spec);
// Elements of vector bool are interpreted as unsigned. (PIM 2.1)
if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) ||
@@ -1008,20 +1017,20 @@
// vector long double and vector long long double are never allowed.
// vector double is OK for Power7 and later, and ZVector.
if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong)
- Diag(D, TSWLoc, diag::err_invalid_vector_long_double_decl_spec);
- else if (!PP.getTargetInfo().hasFeature("vsx") &&
- !PP.getLangOpts().ZVector)
- Diag(D, TSTLoc, diag::err_invalid_vector_double_decl_spec);
+ S.Diag(TSWLoc, diag::err_invalid_vector_long_double_decl_spec);
+ else if (!S.Context.getTargetInfo().hasFeature("vsx") &&
+ !S.getLangOpts().ZVector)
+ S.Diag(TSTLoc, diag::err_invalid_vector_double_decl_spec);
} else if (TypeSpecType == TST_float) {
// vector float is unsupported for ZVector.
- if (PP.getLangOpts().ZVector)
- Diag(D, TSTLoc, diag::err_invalid_vector_float_decl_spec);
+ if (S.getLangOpts().ZVector)
+ S.Diag(TSTLoc, diag::err_invalid_vector_float_decl_spec);
} else if (TypeSpecWidth == TSW_long) {
// vector long is unsupported for ZVector and deprecated for AltiVec.
- if (PP.getLangOpts().ZVector)
- Diag(D, TSWLoc, diag::err_invalid_vector_long_decl_spec);
+ if (S.getLangOpts().ZVector)
+ S.Diag(TSWLoc, diag::err_invalid_vector_long_decl_spec);
else
- Diag(D, TSWLoc, diag::warn_vector_long_decl_spec_combination)
+ S.Diag(TSWLoc, diag::warn_vector_long_decl_spec_combination)
<< getSpecifierName((TST)TypeSpecType, Policy);
}
@@ -1040,7 +1049,7 @@
TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 &&
TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
- Diag(D, TSSLoc, diag::err_invalid_sign_spec)
+ S.Diag(TSSLoc, diag::err_invalid_sign_spec)
<< getSpecifierName((TST)TypeSpecType, Policy);
// signed double -> double.
TypeSpecSign = TSS_unspecified;
@@ -1055,9 +1064,7 @@
if (TypeSpecType == TST_unspecified)
TypeSpecType = TST_int; // short -> short int, long long -> long long int.
else if (TypeSpecType != TST_int) {
- Diag(D, TSWLoc,
- TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
- : diag::err_invalid_longlong_spec)
+ S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth
<< getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecType = TST_int;
TypeSpecOwned = false;
@@ -1067,7 +1074,7 @@
if (TypeSpecType == TST_unspecified)
TypeSpecType = TST_int; // long -> long int.
else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
- Diag(D, TSWLoc, diag::err_invalid_long_spec)
+ S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth
<< getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecType = TST_int;
TypeSpecOwned = false;
@@ -1079,17 +1086,17 @@
// disallow their use. Need information about the backend.
if (TypeSpecComplex != TSC_unspecified) {
if (TypeSpecType == TST_unspecified) {
- Diag(D, TSCLoc, diag::ext_plain_complex)
+ S.Diag(TSCLoc, diag::ext_plain_complex)
<< FixItHint::CreateInsertion(
- PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
+ S.getLocForEndOfToken(getTypeSpecComplexLoc()),
" double");
TypeSpecType = TST_double; // _Complex -> _Complex double.
} else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
// Note that this intentionally doesn't include _Complex _Bool.
- if (!PP.getLangOpts().CPlusPlus)
- Diag(D, TSTLoc, diag::ext_integer_complex);
+ if (!S.getLangOpts().CPlusPlus)
+ S.Diag(TSTLoc, diag::ext_integer_complex);
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
- Diag(D, TSCLoc, diag::err_invalid_complex_spec)
+ S.Diag(TSCLoc, diag::err_invalid_complex_spec)
<< getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecComplex = TSC_unspecified;
}
@@ -1106,14 +1113,14 @@
case SCS_static:
break;
default:
- if (PP.getSourceManager().isBeforeInTranslationUnit(
+ if (S.getSourceManager().isBeforeInTranslationUnit(
getThreadStorageClassSpecLoc(), getStorageClassSpecLoc()))
- Diag(D, getStorageClassSpecLoc(),
+ S.Diag(getStorageClassSpecLoc(),
diag::err_invalid_decl_spec_combination)
<< DeclSpec::getSpecifierName(getThreadStorageClassSpec())
<< SourceRange(getThreadStorageClassSpecLoc());
else
- Diag(D, getThreadStorageClassSpecLoc(),
+ S.Diag(getThreadStorageClassSpecLoc(),
diag::err_invalid_decl_spec_combination)
<< DeclSpec::getSpecifierName(getStorageClassSpec())
<< SourceRange(getStorageClassSpecLoc());
@@ -1127,7 +1134,7 @@
// the type specifier is not optional, but we got 'auto' as a storage
// class specifier, then assume this is an attempt to use C++0x's 'auto'
// type specifier.
- if (PP.getLangOpts().CPlusPlus &&
+ if (S.getLangOpts().CPlusPlus &&
TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
TypeSpecType = TST_auto;
StorageClassSpec = SCS_unspecified;
@@ -1136,17 +1143,17 @@
}
// Diagnose if we've recovered from an ill-formed 'auto' storage class
// specifier in a pre-C++11 dialect of C++.
- if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
- Diag(D, TSTLoc, diag::ext_auto_type_specifier);
- if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 &&
+ if (!S.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
+ S.Diag(TSTLoc, diag::ext_auto_type_specifier);
+ if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 &&
StorageClassSpec == SCS_auto)
- Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
+ S.Diag(StorageClassSpecLoc, diag::warn_auto_storage_class)
<< FixItHint::CreateRemoval(StorageClassSpecLoc);
if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32)
- Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type)
+ S.Diag(TSTLoc, diag::warn_cxx98_compat_unicode_type)
<< (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
if (Constexpr_specified)
- Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr);
+ S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
@@ -1170,7 +1177,7 @@
ThreadHint = FixItHint::CreateRemoval(SCLoc);
}
- Diag(D, SCLoc, diag::err_friend_decl_spec)
+ S.Diag(SCLoc, diag::err_friend_decl_spec)
<< SpecName << StorageHint << ThreadHint;
ClearStorageClassSpecs();
@@ -1196,7 +1203,7 @@
}
FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
- Diag(D, SCLoc, diag::err_friend_decl_spec)
+ S.Diag(SCLoc, diag::err_friend_decl_spec)
<< Keyword << Hint;
FS_virtual_specified = FS_explicit_specified = false;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 5462292..34261f2 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -120,8 +120,7 @@
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
- &Context);
+ Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context);
ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, false, nullptr, false);
@@ -168,7 +167,7 @@
// Initialize predefined Objective-C types:
- if (PP.getLangOpts().ObjC1) {
+ if (getLangOpts().ObjC1) {
// If 'SEL' does not yet refer to any declarations, make it refer to the
// predefined 'SEL'.
DeclarationName SEL = &Context.Idents.get("SEL");
@@ -192,9 +191,14 @@
PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
+ // Create the internal type for the *StringMakeConstantString builtins.
+ DeclarationName ConstantString = &Context.Idents.get("__NSConstantString");
+ if (IdResolver.begin(ConstantString) == IdResolver.end())
+ PushOnScopeChains(Context.getCFConstantStringDecl(), TUScope);
+
// Initialize Microsoft "predefined C++ types".
- if (PP.getLangOpts().MSVCCompat) {
- if (PP.getLangOpts().CPlusPlus &&
+ if (getLangOpts().MSVCCompat) {
+ if (getLangOpts().CPlusPlus &&
IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end())
PushOnScopeChains(Context.buildImplicitRecord("type_info", TTK_Class),
TUScope);
@@ -203,7 +207,7 @@
}
// Initialize predefined OpenCL types.
- if (PP.getLangOpts().OpenCL) {
+ if (getLangOpts().OpenCL) {
addImplicitTypedef("image1d_t", Context.OCLImage1dTy);
addImplicitTypedef("image1d_array_t", Context.OCLImage1dArrayTy);
addImplicitTypedef("image1d_buffer_t", Context.OCLImage1dBufferTy);
@@ -249,7 +253,7 @@
}
}
- if (PP.getTargetInfo().hasBuiltinMSVaList()) {
+ if (Context.getTargetInfo().hasBuiltinMSVaList()) {
DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list");
if (IdResolver.begin(MSVaList) == IdResolver.end())
PushOnScopeChains(Context.getBuiltinMSVaListDecl(), TUScope);
@@ -350,6 +354,20 @@
AnalysisWarnings.PrintStats();
}
+void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
+ QualType SrcType,
+ SourceLocation Loc) {
+ Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context);
+ if (!ExprNullability || *ExprNullability != NullabilityKind::Nullable)
+ return;
+
+ Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context);
+ if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull)
+ return;
+
+ Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.
@@ -373,18 +391,7 @@
assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
#endif
- // Check whether we're implicitly casting from a nullable type to a nonnull
- // type.
- if (auto exprNullability = E->getType()->getNullability(Context)) {
- if (*exprNullability == NullabilityKind::Nullable) {
- if (auto typeNullability = Ty->getNullability(Context)) {
- if (*typeNullability == NullabilityKind::NonNull) {
- Diag(E->getLocStart(), diag::warn_nullability_lost)
- << E->getType() << Ty;
- }
- }
- }
- }
+ diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getLocStart());
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
@@ -1469,7 +1476,7 @@
// arguments and that it returns something of a reasonable type,
// so we can emit a fixit and carry on pretending that E was
// actually a CallExpr.
- SourceLocation ParenInsertionLoc = PP.getLocForEndOfToken(Range.getEnd());
+ SourceLocation ParenInsertionLoc = getLocForEndOfToken(Range.getEnd());
Diag(Loc, PD)
<< /*zero-arg*/ 1 << Range
<< (IsCallableWithAppend(E.get())
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 5a29bad..f314571 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -275,7 +275,7 @@
case PCK_Unknown:
llvm_unreachable("unexpected pragma comment kind");
case PCK_Linker:
- Consumer.HandleLinkerOptionPragma(Arg);
+ Consumer.HandleLinkerOption(Arg);
return;
case PCK_Lib:
Consumer.HandleDependentLibrary(Arg);
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9e146ed..f7aace6 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -291,8 +291,10 @@
if (!SD)
return false;
+ SD = SD->getUnderlyingDecl();
+
// Namespace and namespace aliases are fine.
- if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+ if (isa<NamespaceDecl>(SD))
return true;
if (!isa<TypeDecl>(SD))
@@ -396,10 +398,7 @@
}
Found.suppressDiagnostics();
- if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
- return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
-
- return false;
+ return Found.getAsSingle<NamespaceDecl>();
}
namespace {
@@ -533,6 +532,9 @@
LookupName(Found, S);
}
+ if (Found.isAmbiguous())
+ return true;
+
// If we performed lookup into a dependent context and did not find anything,
// that's fine: just build a dependent nested-name-specifier.
if (Found.empty() && isDependent &&
@@ -551,8 +553,6 @@
return false;
}
- // FIXME: Deal with ambiguities cleanly.
-
if (Found.empty() && !ErrorRecoveryLookup) {
// If identifier is not found as class-name-or-namespace-name, but is found
// as other entity, don't look for typos.
@@ -562,6 +562,8 @@
else if (S && !isDependent)
LookupName(R, S);
if (!R.empty()) {
+ // Don't diagnose problems with this speculative lookup.
+ R.suppressDiagnostics();
// The identifier is found in ordinary lookup. If correction to colon is
// allowed, suggest replacement to ':'.
if (IsCorrectedToColon) {
@@ -604,7 +606,7 @@
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Name);
- if (NamedDecl *ND = Corrected.getCorrectionDecl())
+ if (NamedDecl *ND = Corrected.getFoundDecl())
Found.addDecl(ND);
Found.setLookupName(Corrected.getCorrection());
} else {
@@ -612,7 +614,8 @@
}
}
- NamedDecl *SD = Found.getAsSingle<NamedDecl>();
+ NamedDecl *SD =
+ Found.isSingleResult() ? Found.getRepresentativeDecl() : nullptr;
bool IsExtension = false;
bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension);
if (!AcceptSpec && IsExtension) {
@@ -684,7 +687,8 @@
return false;
}
- QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ QualType T =
+ Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl()));
TypeLocBuilder TLB;
if (isa<InjectedClassNameType>(T)) {
InjectedClassNameTypeLoc InjectedTL
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 4aecd08..ad1d7da 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -683,7 +683,8 @@
// C++ 5.2.7p5
// Upcasts are resolved statically.
- if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
+ if (DestRecord &&
+ Self.IsDerivedFrom(OpRange.getBegin(), SrcPointee, DestPointee)) {
if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
OpRange.getBegin(), OpRange,
&BasePath)) {
@@ -1171,7 +1172,8 @@
Kind = CK_DerivedToBase;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
- if (!Self.IsDerivedFrom(SrcExpr->getType(), R->getPointeeType(), Paths))
+ if (!Self.IsDerivedFrom(SrcExpr->getLocStart(), SrcExpr->getType(),
+ R->getPointeeType(), Paths))
return TC_NotApplicable;
Self.BuildBasePathArray(Paths, BasePath);
@@ -1260,8 +1262,8 @@
QualType OrigDestType, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath) {
// We can only work with complete types. But don't complain if it doesn't work
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0) ||
- Self.RequireCompleteType(OpRange.getBegin(), DestType, 0))
+ if (!Self.isCompleteType(OpRange.getBegin(), SrcType) ||
+ !Self.isCompleteType(OpRange.getBegin(), DestType))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
@@ -1271,7 +1273,7 @@
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
- if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
+ if (!Self.IsDerivedFrom(OpRange.getBegin(), DestType, SrcType, Paths)) {
return TC_NotApplicable;
}
@@ -1307,7 +1309,7 @@
if (!Paths.isRecordingPaths()) {
Paths.clear();
Paths.setRecordingPaths(true);
- Self.IsDerivedFrom(DestType, SrcType, Paths);
+ Self.IsDerivedFrom(OpRange.getBegin(), DestType, SrcType, Paths);
}
std::string PathDisplayStr;
std::set<unsigned> DisplayedPaths;
@@ -1397,8 +1399,11 @@
msg = diag::err_bad_static_cast_member_pointer_nonmp;
return TC_NotApplicable;
}
+
+ // Lock down the inheritance model right now in MS ABI, whether or not the
+ // pointee types are the same.
if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft())
- Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0);
+ (void)Self.isCompleteType(OpRange.getBegin(), SrcType);
// T == T, modulo cv
if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
@@ -1410,16 +1415,15 @@
QualType DestClass(DestMemPtr->getClass(), 0);
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcClass, 0) ||
- !Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
+ if (!Self.IsDerivedFrom(OpRange.getBegin(), SrcClass, DestClass, Paths))
return TC_NotApplicable;
- }
// B is a base of D. But is it an allowed base? If not, it's a hard error.
if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) {
Paths.clear();
Paths.setRecordingPaths(true);
- bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
+ bool StillOkay =
+ Self.IsDerivedFrom(OpRange.getBegin(), SrcClass, DestClass, Paths);
assert(StillOkay);
(void)StillOkay;
std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
@@ -1843,8 +1847,8 @@
if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// We need to determine the inheritance model that the class will use if
// haven't yet.
- Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0);
- Self.RequireCompleteType(OpRange.getBegin(), DestType, 0);
+ (void)Self.isCompleteType(OpRange.getBegin(), SrcType);
+ (void)Self.isCompleteType(OpRange.getBegin(), DestType);
}
// Don't allow casting between member pointers of different sizes.
@@ -2101,6 +2105,7 @@
&& (SrcExpr.get()->getType()->isIntegerType()
|| SrcExpr.get()->getType()->isFloatingType())) {
Kind = CK_VectorSplat;
+ SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get());
return;
}
@@ -2335,6 +2340,7 @@
if (DestVecTy->getVectorKind() == VectorType::AltiVecVector &&
(SrcType->isIntegerType() || SrcType->isFloatingType())) {
Kind = CK_VectorSplat;
+ SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get());
} else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) {
SrcExpr = ExprError();
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5c94227..6c2834b 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1180,8 +1180,7 @@
/// Checks if a the given expression evaluates to null.
///
/// \brief Returns true if the value evaluates to null.
-static bool CheckNonNullExpr(Sema &S,
- const Expr *Expr) {
+static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
// If the expression has non-null type, it doesn't evaluate to null.
if (auto nullability
= Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) {
@@ -1802,8 +1801,17 @@
Ty = ByValType;
else if (Form == Arithmetic)
Ty = Context.getPointerDiffType();
- else
- Ty = Context.getPointerType(ValType.getUnqualifiedType());
+ else {
+ Expr *ValArg = TheCall->getArg(i);
+ unsigned AS = 0;
+ // Keep address space of non-atomic pointer type.
+ if (const PointerType *PtrTy =
+ ValArg->getType()->getAs<PointerType>()) {
+ AS = PtrTy->getPointeeType().getAddressSpace();
+ }
+ Ty = Context.getPointerType(
+ Context.getAddrSpaceQualType(ValType.getUnqualifiedType(), AS));
+ }
break;
case 2:
// The third argument to compare_exchange / GNU exchange is a
@@ -5085,6 +5093,19 @@
return;
}
+ // Taking the absolute value of a pointer is very suspicious, they probably
+ // wanted to index into an array, dereference a pointer, call a function, etc.
+ if (ArgType->isPointerType() || ArgType->canDecayToPointerType()) {
+ unsigned DiagType = 0;
+ if (ArgType->isFunctionType())
+ DiagType = 1;
+ else if (ArgType->isArrayType())
+ DiagType = 2;
+
+ Diag(Call->getExprLoc(), diag::warn_pointer_abs) << DiagType << ArgType;
+ return;
+ }
+
// std::abs has overloads which prevent most of the absolute value problems
// from occurring.
if (IsStdAbs)
@@ -5633,17 +5654,15 @@
}
if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var.
- S.Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_stack_ref
- : diag::warn_ret_stack_addr)
+ S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType()
<< DR->getDecl()->getDeclName() << diagRange;
} else if (isa<BlockExpr>(stackE)) { // local block.
S.Diag(diagLoc, diag::err_ret_local_block) << diagRange;
} else if (isa<AddrLabelExpr>(stackE)) { // address of label.
S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange;
} else { // local temporary.
- S.Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_local_temp_ref
- : diag::warn_ret_local_temp_addr)
- << diagRange;
+ S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref)
+ << lhsType->isReferenceType() << diagRange;
}
// Display the "trail" of reference variables that we followed until we
@@ -6224,7 +6243,8 @@
IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
- bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast);
+ bool isIntegerCast = CE->getCastKind() == CK_IntegralCast ||
+ CE->getCastKind() == CK_BooleanToSignedIntegral;
// Assume that non-integer casts can span the full range of the type.
if (!isIntegerCast)
@@ -6964,7 +6984,7 @@
SmallString<16> PrettyTargetValue;
if (T->isSpecificBuiltinType(BuiltinType::Bool))
- PrettyTargetValue = IntegerValue == 0 ? "false" : "true";
+ PrettyTargetValue = Value.isZero() ? "false" : "true";
else
IntegerValue.toString(PrettyTargetValue);
@@ -7028,6 +7048,10 @@
E->getExprLoc()))
return;
+ // Don't warn on functions which have return type nullptr_t.
+ if (isa<CallExpr>(E))
+ return;
+
// Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
const Expr::NullPointerConstantKind NullKind =
E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull);
@@ -7043,8 +7067,12 @@
// __null is usually wrapped in a macro. Go up a macro if that is the case.
if (NullKind == Expr::NPCK_GNUNull) {
- if (Loc.isMacroID())
- Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ if (Loc.isMacroID()) {
+ StringRef MacroName =
+ Lexer::getImmediateMacroName(Loc, S.SourceMgr, S.getLangOpts());
+ if (MacroName == "NULL")
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ }
}
// Only warn if the null and context location are in the same macro expansion.
@@ -7286,20 +7314,24 @@
}
}
- // If the target is bool, warn if expr is a function or method call.
- if (Target->isSpecificBuiltinType(BuiltinType::Bool) &&
- isa<CallExpr>(E)) {
+ // Detect the case where a call result is converted from floating-point to
+ // to bool, and the final argument to the call is converted from bool, to
+ // discover this typo:
+ //
+ // bool b = fabs(x < 1.0); // should be "bool b = fabs(x) < 1.0;"
+ //
+ // FIXME: This is an incredibly special case; is there some more general
+ // way to detect this class of misplaced-parentheses bug?
+ if (Target->isBooleanType() && isa<CallExpr>(E)) {
// Check last argument of function call to see if it is an
// implicit cast from a type matching the type the result
// is being cast to.
CallExpr *CEx = cast<CallExpr>(E);
- unsigned NumArgs = CEx->getNumArgs();
- if (NumArgs > 0) {
+ if (unsigned NumArgs = CEx->getNumArgs()) {
Expr *LastA = CEx->getArg(NumArgs - 1);
Expr *InnerE = LastA->IgnoreParenImpCasts();
- const Type *InnerType =
- S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
- if (isa<ImplicitCastExpr>(LastA) && (InnerType == Target)) {
+ if (isa<ImplicitCastExpr>(LastA) &&
+ InnerE->getType()->isBooleanType()) {
// Warn on this floating-point to bool conversion
DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_floating_point_to_bool);
@@ -7482,18 +7514,16 @@
CheckImplicitConversion(S, E, T, CC);
// Now continue drilling into this expression.
-
- if (PseudoObjectExpr * POE = dyn_cast<PseudoObjectExpr>(E)) {
- if (POE->getResultExpr())
- E = POE->getResultExpr();
+
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+ // The bound subexpressions in a PseudoObjectExpr are not reachable
+ // as transitive children.
+ // FIXME: Use a more uniform representation for this.
+ for (auto *SE : POE->semantics())
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
+ AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
}
-
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
- if (OVE->getSourceExpr())
- AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
- return;
- }
-
+
// Skip past explicit casts.
if (isa<ExplicitCastExpr>(E)) {
E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
@@ -7553,12 +7583,6 @@
} // end anonymous namespace
-enum {
- AddressOf,
- FunctionPointer,
- ArrayPointer
-};
-
// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
// Returns true when emitting a warning about taking the address of a reference.
static bool CheckForReference(Sema &SemaRef, const Expr *E,
@@ -7657,6 +7681,26 @@
}
}
+ auto ComplainAboutNonnullParamOrCall = [&](bool IsParam) {
+ std::string Str;
+ llvm::raw_string_ostream S(Str);
+ E->printPretty(S, nullptr, getPrintingPolicy());
+ unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare
+ : diag::warn_cast_nonnull_to_bool;
+ Diag(E->getExprLoc(), DiagID) << IsParam << S.str()
+ << E->getSourceRange() << Range << IsEqual;
+ };
+
+ // If we have a CallExpr that is tagged with returns_nonnull, we can complain.
+ if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) {
+ if (auto *Callee = Call->getDirectCallee()) {
+ if (Callee->hasAttr<ReturnsNonNullAttr>()) {
+ ComplainAboutNonnullParamOrCall(false);
+ return;
+ }
+ }
+ }
+
// Expect to find a single Decl. Skip anything more complicated.
ValueDecl *D = nullptr;
if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
@@ -7668,40 +7712,38 @@
// Weak Decls can be null.
if (!D || D->isWeak())
return;
-
+
// Check for parameter decl with nonnull attribute
- if (const ParmVarDecl* PV = dyn_cast<ParmVarDecl>(D)) {
- if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV))
- if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
- unsigned NumArgs = FD->getNumParams();
- llvm::SmallBitVector AttrNonNull(NumArgs);
+ if (const auto* PV = dyn_cast<ParmVarDecl>(D)) {
+ if (getCurFunction() &&
+ !getCurFunction()->ModifiedNonNullParams.count(PV)) {
+ if (PV->hasAttr<NonNullAttr>()) {
+ ComplainAboutNonnullParamOrCall(true);
+ return;
+ }
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+ auto ParamIter = std::find(FD->param_begin(), FD->param_end(), PV);
+ assert(ParamIter != FD->param_end());
+ unsigned ParamNo = std::distance(FD->param_begin(), ParamIter);
+
for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
if (!NonNull->args_size()) {
- AttrNonNull.set(0, NumArgs);
- break;
+ ComplainAboutNonnullParamOrCall(true);
+ return;
}
- for (unsigned Val : NonNull->args()) {
- if (Val >= NumArgs)
- continue;
- AttrNonNull.set(Val);
- }
- }
- if (!AttrNonNull.empty())
- for (unsigned i = 0; i < NumArgs; ++i)
- if (FD->getParamDecl(i) == PV &&
- (AttrNonNull[i] || PV->hasAttr<NonNullAttr>())) {
- std::string Str;
- llvm::raw_string_ostream S(Str);
- E->printPretty(S, nullptr, getPrintingPolicy());
- unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare
- : diag::warn_cast_nonnull_to_bool;
- Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange()
- << Range << IsEqual;
+
+ for (unsigned ArgNo : NonNull->args()) {
+ if (ArgNo == ParamNo) {
+ ComplainAboutNonnullParamOrCall(true);
return;
}
+ }
+ }
}
}
-
+ }
+
QualType T = D->getType();
const bool IsArray = T->isArrayType();
const bool IsFunction = T->isFunctionType();
@@ -7722,7 +7764,11 @@
unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
: diag::warn_impcast_pointer_to_bool;
- unsigned DiagType;
+ enum {
+ AddressOf,
+ FunctionPointer,
+ ArrayPointer
+ } DiagType;
if (IsAddressOf)
DiagType = AddressOf;
else if (IsFunction)
@@ -7808,6 +7854,10 @@
void Sema::CheckForIntOverflow (Expr *E) {
if (isa<BinaryOperator>(E->IgnoreParenCasts()))
E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ else if (auto InitList = dyn_cast<InitListExpr>(E))
+ for (Expr *E : InitList->inits())
+ if (isa<BinaryOperator>(E->IgnoreParenCasts()))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
}
namespace {
@@ -8410,6 +8460,15 @@
}
}
}
+
+ // Parameters with the pass_object_size attribute only need to be marked
+ // constant at function definitions. Because we lack information about
+ // whether we're on a declaration or definition when we're instantiating the
+ // attribute, we need to check for constness here.
+ if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>())
+ if (!Param->getType().isConstQualified())
+ Diag(Param->getLocation(), diag::err_attribute_pointers_only)
+ << Attr->getSpelling() << 1;
}
return HasInvalidParm;
@@ -8529,7 +8588,7 @@
return;
llvm::APSInt index;
- if (!IndexExpr->EvaluateAsInt(index, Context))
+ if (!IndexExpr->EvaluateAsInt(index, Context, Expr::SE_AllowSideEffects))
return;
if (IndexNegated)
index = -index;
@@ -9860,4 +9919,3 @@
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
-
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 06d9e37..12aec6c 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -494,6 +494,7 @@
bool &AsNestedNameSpecifier) const {
AsNestedNameSpecifier = false;
+ auto *Named = ND;
ND = ND->getUnderlyingDecl();
// Skip unnamed entities.
@@ -526,14 +527,14 @@
return false;
if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
- ((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
+ (isa<NamespaceDecl>(ND) &&
Filter != &ResultBuilder::IsNamespace &&
Filter != &ResultBuilder::IsNamespaceOrAlias &&
Filter != nullptr))
AsNestedNameSpecifier = true;
// Filter out any unwanted results.
- if (Filter && !(this->*Filter)(ND)) {
+ if (Filter && !(this->*Filter)(Named)) {
// Check whether it is interesting as a nested-name-specifier.
if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus &&
IsNestedNameSpecifier(ND) &&
@@ -1142,14 +1143,12 @@
/// \brief Determines whether the given declaration is a namespace or
/// namespace alias.
bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {
- return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+ return isa<NamespaceDecl>(ND->getUnderlyingDecl());
}
/// \brief Determines whether the given declaration is a type.
bool ResultBuilder::IsType(const NamedDecl *ND) const {
- if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
- ND = Using->getTargetDecl();
-
+ ND = ND->getUnderlyingDecl();
return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
}
@@ -1157,11 +1156,9 @@
/// "." or "->". Only value declarations, nested name specifiers, and
/// using declarations thereof should show up.
bool ResultBuilder::IsMember(const NamedDecl *ND) const {
- if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
- ND = Using->getTargetDecl();
-
+ ND = ND->getUnderlyingDecl();
return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
- isa<ObjCPropertyDecl>(ND);
+ isa<ObjCPropertyDecl>(ND);
}
static bool isObjCReceiverType(ASTContext &C, QualType T) {
@@ -3036,6 +3033,7 @@
case Decl::ParmVar: return CXCursor_ParmDecl;
case Decl::Typedef: return CXCursor_TypedefDecl;
case Decl::TypeAlias: return CXCursor_TypeAliasDecl;
+ case Decl::TypeAliasTemplate: return CXCursor_TypeAliasTemplateDecl;
case Decl::Var: return CXCursor_VarDecl;
case Decl::Namespace: return CXCursor_Namespace;
case Decl::NamespaceAlias: return CXCursor_NamespaceAlias;
@@ -3376,7 +3374,7 @@
case PCC_Statement:
case PCC_RecoveryInFunction:
if (S->getFnParent())
- AddPrettyFunctionResults(PP.getLangOpts(), Results);
+ AddPrettyFunctionResults(getLangOpts(), Results);
break;
case PCC_Namespace:
@@ -3520,7 +3518,7 @@
if (S->getFnParent() &&
!Data.ObjCCollection &&
!Data.IntegralConstantExpression)
- AddPrettyFunctionResults(PP.getLangOpts(), Results);
+ AddPrettyFunctionResults(getLangOpts(), Results);
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results, false, PreferredTypeIsPointer);
@@ -3572,7 +3570,7 @@
Container = getContainerDef(Container);
// Add properties in this container.
- for (const auto *P : Container->properties())
+ for (const auto *P : Container->instance_properties())
if (AddedProperties.insert(P->getIdentifier()).second)
Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
CurContext);
@@ -4051,7 +4049,7 @@
// If expression's type is CXXRecordDecl, it may overload the function
// call operator, so we check if it does and add them as candidates.
// A complete type is needed to lookup for member function call operators.
- if (!RequireCompleteType(Loc, NakedFn->getType(), 0)) {
+ if (isCompleteType(Loc, NakedFn->getType())) {
DeclarationName OpName = Context.DeclarationNames
.getCXXOperatorName(OO_Call);
LookupResult R(*this, OpName, Loc, LookupOrdinaryName);
@@ -4093,7 +4091,7 @@
return;
// A complete type is needed to lookup for constructors.
- if (RequireCompleteType(Loc, Type, 0))
+ if (!isCompleteType(Loc, Type))
return;
CXXRecordDecl *RD = Type->getAsCXXRecordDecl();
@@ -4205,7 +4203,7 @@
Results.ExitScope();
if (S->getFnParent())
- AddPrettyFunctionResults(PP.getLangOpts(), Results);
+ AddPrettyFunctionResults(getLangOpts(), Results);
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results, false);
@@ -5925,8 +5923,8 @@
}
}
-void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
- unsigned NumProtocols) {
+void Sema::CodeCompleteObjCProtocolReferences(
+ ArrayRef<IdentifierLocPair> Protocols) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCProtocolName);
@@ -5937,9 +5935,9 @@
// Tell the result set to ignore all of the protocols we have
// already seen.
// FIXME: This doesn't work when caching code-completion results.
- for (unsigned I = 0; I != NumProtocols; ++I)
- if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first,
- Protocols[I].second))
+ for (const IdentifierLocPair &Pair : Protocols)
+ if (ObjCProtocolDecl *Protocol = LookupProtocol(Pair.first,
+ Pair.second))
Results.Ignore(Protocol);
// Add all protocols.
@@ -6191,7 +6189,7 @@
// Figure out which interface we're looking into.
ObjCInterfaceDecl *Class = nullptr;
if (ObjCImplementationDecl *ClassImpl
- = dyn_cast<ObjCImplementationDecl>(Container))
+ = dyn_cast<ObjCImplementationDecl>(Container))
Class = ClassImpl->getClassInterface();
else
Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl()
@@ -6200,8 +6198,8 @@
// Determine the type of the property we're synthesizing.
QualType PropertyType = Context.getObjCIdType();
if (Class) {
- if (ObjCPropertyDecl *Property
- = Class->FindPropertyDeclaration(PropertyName)) {
+ if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration(
+ PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
PropertyType
= Property->getType().getNonReferenceType().getUnqualifiedType();
@@ -7180,7 +7178,7 @@
Containers.push_back(Cat);
for (unsigned I = 0, N = Containers.size(); I != N; ++I)
- for (auto *P : Containers[I]->properties())
+ for (auto *P : Containers[I]->instance_properties())
AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context,
KnownSelectors, Results);
}
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index a2a7900..4b4fd6b 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
using namespace clang;
using namespace sema;
@@ -52,6 +53,8 @@
Args.addArgument(TemplateArgumentLoc(
TemplateArgument(FnType->getReturnType()),
S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
+ // FIXME: If the function is a non-static member function, add the type
+ // of the implicit object parameter before the formal parameters.
for (QualType T : FnType->getParamTypes())
Args.addArgument(TemplateArgumentLoc(
TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
@@ -82,6 +85,12 @@
// The promise type is required to be a class type.
QualType PromiseType = S.Context.getTypeDeclType(Promise);
if (!PromiseType->getAsCXXRecordDecl()) {
+ // Use the fully-qualified name of the type.
+ auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, Std);
+ NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
+ CoroTrait.getTypePtr());
+ PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
+
S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
<< PromiseType;
return QualType();
@@ -93,12 +102,14 @@
/// Check that this is a context in which a coroutine suspension can appear.
static FunctionScopeInfo *
checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
- // 'co_await' and 'co_yield' are permitted in unevaluated operands.
- // FIXME: Not in 'noexcept'.
- if (S.isUnevaluatedContext())
+ // 'co_await' and 'co_yield' are not permitted in unevaluated operands.
+ if (S.isUnevaluatedContext()) {
+ S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
return nullptr;
+ }
// Any other usage must be within a function.
+ // FIXME: Reject a coroutine with a deduced return type.
auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
if (!FD) {
S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
@@ -121,9 +132,12 @@
assert(ScopeInfo && "missing function scope for function");
// If we don't have a promise variable, build one now.
- if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) {
+ if (!ScopeInfo->CoroutinePromise) {
QualType T =
- lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc);
+ FD->getType()->isDependentType()
+ ? S.Context.DependentTy
+ : lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(),
+ Loc);
if (T.isNull())
return nullptr;
@@ -158,6 +172,23 @@
Expr *Results[3];
};
+static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
+ StringRef Name,
+ MutableArrayRef<Expr *> Args) {
+ DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
+
+ // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
+ CXXScopeSpec SS;
+ ExprResult Result = S.BuildMemberReferenceExpr(
+ Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
+ SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
+ /*Scope=*/nullptr);
+ if (Result.isInvalid())
+ return ExprError();
+
+ return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
+}
+
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
@@ -167,22 +198,11 @@
const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
- DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc);
-
Expr *Operand = new (S.Context) OpaqueValueExpr(
- Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E);
-
- // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
- CXXScopeSpec SS;
- ExprResult Result = S.BuildMemberReferenceExpr(
- Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS,
- SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
- /*Scope=*/nullptr);
- if (Result.isInvalid())
- return Calls;
+ Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
// FIXME: Pass coroutine handle to await_suspend.
- Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr);
+ ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
if (Result.isInvalid())
return Calls;
Calls.Results[I] = Result.get();
@@ -193,6 +213,12 @@
}
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(E);
+ if (R.isInvalid()) return ExprError();
+ E = R.get();
+ }
+
ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
if (Awaitable.isInvalid())
return ExprError();
@@ -200,13 +226,8 @@
}
ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
-
- if (E->getType()->isDependentType()) {
- Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
- if (Coroutine)
- Coroutine->CoroutineStmts.push_back(Res);
- return Res;
- }
+ if (!Coroutine)
+ return ExprError();
if (E->getType()->isPlaceholderType()) {
ExprResult R = CheckPlaceholderExpr(E);
@@ -214,8 +235,16 @@
E = R.get();
}
- // FIXME: If E is a prvalue, create a temporary.
- // FIXME: If E is an xvalue, convert to lvalue.
+ if (E->getType()->isDependentType()) {
+ Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
+ Coroutine->CoroutineStmts.push_back(Res);
+ return Res;
+ }
+
+ // If the expression is a temporary, materialize it as an lvalue so that we
+ // can use it multiple times.
+ if (E->getValueKind() == VK_RValue)
+ E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
// Build the await_ready, await_suspend, await_resume calls.
ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
@@ -224,25 +253,74 @@
Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
RSS.Results[2]);
- if (Coroutine)
- Coroutine->CoroutineStmts.push_back(Res);
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
+static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine,
+ SourceLocation Loc, StringRef Name,
+ MutableArrayRef<Expr *> Args) {
+ assert(Coroutine->CoroutinePromise && "no promise for coroutine");
+
+ // Form a reference to the promise.
+ auto *Promise = Coroutine->CoroutinePromise;
+ ExprResult PromiseRef = S.BuildDeclRefExpr(
+ Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
+ if (PromiseRef.isInvalid())
+ return ExprError();
+
+ // Call 'yield_value', passing in E.
+ return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
+}
+
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
- // FIXME: Build yield_value call.
- ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
+ if (!Coroutine)
+ return ExprError();
+
+ // Build yield_value call.
+ ExprResult Awaitable =
+ buildPromiseCall(*this, Coroutine, Loc, "yield_value", E);
if (Awaitable.isInvalid())
return ExprError();
+
+ // Build 'operator co_await' call.
+ Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
+ if (Awaitable.isInvalid())
+ return ExprError();
+
return BuildCoyieldExpr(Loc, Awaitable.get());
}
ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
+ if (!Coroutine)
+ return ExprError();
- // FIXME: Build await_* calls.
- Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E);
- if (Coroutine)
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(E);
+ if (R.isInvalid()) return ExprError();
+ E = R.get();
+ }
+
+ if (E->getType()->isDependentType()) {
+ Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
Coroutine->CoroutineStmts.push_back(Res);
+ return Res;
+ }
+
+ // If the expression is a temporary, materialize it as an lvalue so that we
+ // can use it multiple times.
+ if (E->getValueKind() == VK_RValue)
+ E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
+
+ // Build the await_ready, await_suspend, await_resume calls.
+ ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
+ if (RSS.IsInvalid)
+ return ExprError();
+
+ Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2]);
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
@@ -251,15 +329,37 @@
}
StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
+ if (!Coroutine)
+ return StmtError();
- // FIXME: Build return_* calls.
- Stmt *Res = new (Context) CoreturnStmt(Loc, E);
- if (Coroutine)
- Coroutine->CoroutineStmts.push_back(Res);
+ if (E && E->getType()->isPlaceholderType() &&
+ !E->getType()->isSpecificPlaceholderType(BuiltinType::Overload)) {
+ ExprResult R = CheckPlaceholderExpr(E);
+ if (R.isInvalid()) return StmtError();
+ E = R.get();
+ }
+
+ // FIXME: If the operand is a reference to a variable that's about to go out
+ // of scope, we should treat the operand as an xvalue for this overload
+ // resolution.
+ ExprResult PC;
+ if (E && !E->getType()->isVoidType()) {
+ PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E);
+ } else {
+ E = MakeFullDiscardedValueExpr(E).get();
+ PC = buildPromiseCall(*this, Coroutine, Loc, "return_void", None);
+ }
+ if (PC.isInvalid())
+ return StmtError();
+
+ Expr *PCE = ActOnFinishFullExpr(PC.get()).get();
+
+ Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE);
+ Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
-void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) {
+void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
FunctionScopeInfo *Fn = getCurFunction();
assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
@@ -284,6 +384,65 @@
Diag(Fn->CoroutineStmts.front()->getLocStart(),
diag::ext_coroutine_without_co_await_co_yield);
- // FIXME: Perform analysis of initial and final suspend,
- // and set_exception call.
+ SourceLocation Loc = FD->getLocation();
+
+ // Form a declaration statement for the promise declaration, so that AST
+ // visitors can more easily find it.
+ StmtResult PromiseStmt =
+ ActOnDeclStmt(ConvertDeclToDeclGroup(Fn->CoroutinePromise), Loc, Loc);
+ if (PromiseStmt.isInvalid())
+ return FD->setInvalidDecl();
+
+ // Form and check implicit 'co_await p.initial_suspend();' statement.
+ ExprResult InitialSuspend =
+ buildPromiseCall(*this, Fn, Loc, "initial_suspend", None);
+ // FIXME: Support operator co_await here.
+ if (!InitialSuspend.isInvalid())
+ InitialSuspend = BuildCoawaitExpr(Loc, InitialSuspend.get());
+ InitialSuspend = ActOnFinishFullExpr(InitialSuspend.get());
+ if (InitialSuspend.isInvalid())
+ return FD->setInvalidDecl();
+
+ // Form and check implicit 'co_await p.final_suspend();' statement.
+ ExprResult FinalSuspend =
+ buildPromiseCall(*this, Fn, Loc, "final_suspend", None);
+ // FIXME: Support operator co_await here.
+ if (!FinalSuspend.isInvalid())
+ FinalSuspend = BuildCoawaitExpr(Loc, FinalSuspend.get());
+ FinalSuspend = ActOnFinishFullExpr(FinalSuspend.get());
+ if (FinalSuspend.isInvalid())
+ return FD->setInvalidDecl();
+
+ // FIXME: Perform analysis of set_exception call.
+
+ // FIXME: Try to form 'p.return_void();' expression statement to handle
+ // control flowing off the end of the coroutine.
+
+ // Build implicit 'p.get_return_object()' expression and form initialization
+ // of return type from it.
+ ExprResult ReturnObject =
+ buildPromiseCall(*this, Fn, Loc, "get_return_object", None);
+ if (ReturnObject.isInvalid())
+ return FD->setInvalidDecl();
+ QualType RetType = FD->getReturnType();
+ if (!RetType->isDependentType()) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeResult(Loc, RetType, false);
+ ReturnObject = PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
+ ReturnObject.get());
+ if (ReturnObject.isInvalid())
+ return FD->setInvalidDecl();
+ }
+ ReturnObject = ActOnFinishFullExpr(ReturnObject.get(), Loc);
+ if (ReturnObject.isInvalid())
+ return FD->setInvalidDecl();
+
+ // FIXME: Perform move-initialization of parameters into frame-local copies.
+ SmallVector<Expr*, 16> ParamMoves;
+
+ // Build body for the coroutine wrapper statement.
+ Body = new (Context) CoroutineBodyStmt(
+ Body, PromiseStmt.get(), InitialSuspend.get(), FinalSuspend.get(),
+ /*SetException*/nullptr, /*Fallthrough*/nullptr,
+ ReturnObject.get(), ParamMoves);
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 80413ad..f8de19b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -33,7 +33,6 @@
#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
#include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex
#include "clang/Lex/Preprocessor.h" // Included for isCodeCompletionEnabled()
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
@@ -111,6 +110,7 @@
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw___underlying_type:
+ case tok::kw___auto_type:
return true;
case tok::annot_typename:
@@ -207,7 +207,7 @@
FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD);
}
if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType)
- return ParsedType();
+ return nullptr;
// We found some types in dependent base classes. Recover as if the user
// wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the
@@ -266,8 +266,8 @@
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
if (!isClassName && !IsCtorOrDtorName)
- return ParsedType();
-
+ return nullptr;
+
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
if (WantNontrivialTypeSourceInfo)
@@ -278,13 +278,13 @@
II, NameLoc);
return ParsedType::make(T);
}
-
- return ParsedType();
+
+ return nullptr;
}
if (!LookupCtx->isDependentContext() &&
RequireCompleteDeclContext(*SS, LookupCtx))
- return ParsedType();
+ return nullptr;
}
// FIXME: LookupNestedNameSpecifierName isn't the right kind of
@@ -346,8 +346,8 @@
// identifier is not a template (typo correction for template names
// is handled elsewhere).
!(getLangOpts().CPlusPlus && NewSSPtr &&
- isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(),
- false, Template, MemberOfUnknownSpecialization))) {
+ isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false,
+ Template, MemberOfUnknownSpecialization))) {
ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
isClassName, HasTrailingDot, ObjectTypePtr,
IsCtorOrDtorName,
@@ -367,7 +367,7 @@
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
case LookupResult::Ambiguous:
// Recover from type-hiding ambiguities by hiding the type. We'll
@@ -377,7 +377,7 @@
// that only makes sense if the identifier was treated like a type.
if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) {
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
// Look to see if we have a type anywhere in the list of results.
@@ -399,7 +399,7 @@
// will produce the ambiguity, or will complain that it expected
// a type name.
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
// We found a type within the ambiguous lookup; diagnose the
@@ -449,7 +449,7 @@
if (T.isNull()) {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
return ParsedType::make(T);
}
@@ -559,8 +559,8 @@
ParsedType &SuggestedType,
bool AllowClassTemplates) {
// We don't have anything to suggest (yet).
- SuggestedType = ParsedType();
-
+ SuggestedType = nullptr;
+
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
if (TypoCorrection Corrected =
@@ -592,11 +592,11 @@
if (Corrected.getCorrectionSpecifier())
tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
SourceRange(IILoc));
- SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(),
- IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false,
- false, ParsedType(),
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo=*/true);
+ SuggestedType =
+ getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S,
+ tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo=*/true);
}
return;
}
@@ -609,7 +609,7 @@
TemplateTy TemplateResult;
bool MemberOfUnknownSpecialization;
if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false,
- Name, ParsedType(), true, TemplateResult,
+ Name, nullptr, true, TemplateResult,
MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.get();
Diag(IILoc, diag::err_template_missing_args) << TplName;
@@ -795,7 +795,7 @@
}
// In C, we first see whether there is a tag type by the same name, in
- // which case it's likely that the user just forget to write "enum",
+ // which case it's likely that the user just forgot to write "enum",
// "struct", or "union".
if (!getLangOpts().CPlusPlus && !SecondTry &&
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
@@ -813,9 +813,8 @@
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
- NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
- NamedDecl *UnderlyingFirstDecl
- = FirstDecl? FirstDecl->getUnderlyingDecl() : nullptr;
+ NamedDecl *FirstDecl = Corrected.getFoundDecl();
+ NamedDecl *UnderlyingFirstDecl = Corrected.getCorrectionDecl();
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) {
UnqualifiedDiag = diag::err_no_template_suggest;
@@ -1828,13 +1827,13 @@
// If both declarations give a tag declaration a typedef name for linkage
// purposes, then they declare the same entity.
- if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
+ if (S.getLangOpts().CPlusPlus &&
+ OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
Decl->getAnonDeclWithTypedefName())
continue;
}
- if (!Old->isExternallyVisible())
- Filter.erase();
+ Filter.erase();
}
Filter.done();
@@ -1879,7 +1878,8 @@
/// how to resolve this situation, merging decls or emitting
/// diagnostics as appropriate. If there was an error, set New to be invalid.
///
-void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
+void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
+ LookupResult &OldDecls) {
// If the new decl is known invalid already, don't bother doing any
// merging checks.
if (New->isInvalidDecl()) return;
@@ -1960,6 +1960,19 @@
// Make the old tag definition visible.
makeMergedDefinitionVisible(Hidden, NewTag->getLocation());
+
+ // If this was an unscoped enumeration, yank all of its enumerators
+ // out of the scope.
+ if (isa<EnumDecl>(NewTag)) {
+ Scope *EnumScope = getNonFieldDeclScope(S);
+ for (auto *D : NewTag->decls()) {
+ auto *ED = cast<EnumConstantDecl>(D);
+ assert(EnumScope->isDeclScope(ED));
+ EnumScope->RemoveDecl(ED);
+ IdResolver.RemoveDecl(ED);
+ ED->getLexicalDeclContext()->removeDecl(ED);
+ }
+ }
}
}
@@ -2220,6 +2233,15 @@
NewAttr = S.mergeSwiftNameAttr(D, SNA->getRange(), SNA->getName(),
AMK == Sema::AMK_Override,
AttrSpellingListIndex);
+ else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
+ NewAttr = S.mergeInternalLinkageAttr(
+ D, InternalLinkageA->getRange(),
+ &S.Context.Idents.get(InternalLinkageA->getSpelling()),
+ AttrSpellingListIndex);
+ else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
+ NewAttr = S.mergeCommonAttr(D, CommonA->getRange(),
+ &S.Context.Idents.get(CommonA->getSpelling()),
+ AttrSpellingListIndex);
else if (isa<AlignedAttr>(Attr))
// AlignedAttrs are handled separately, because we need to handle all
// such attributes on a declaration at the same time.
@@ -2362,9 +2384,24 @@
if (!Old->hasAttrs() && !New->hasAttrs())
return;
- // attributes declared post-definition are currently ignored
+ // Attributes declared post-definition are currently ignored.
checkNewAttributesAfterDef(*this, New, Old);
+ if (AsmLabelAttr *NewA = New->getAttr<AsmLabelAttr>()) {
+ if (AsmLabelAttr *OldA = Old->getAttr<AsmLabelAttr>()) {
+ if (OldA->getLabel() != NewA->getLabel()) {
+ // This redeclaration changes __asm__ label.
+ Diag(New->getLocation(), diag::err_different_asm_label);
+ Diag(OldA->getLocation(), diag::note_previous_declaration);
+ }
+ } else if (Old->isUsed()) {
+ // This redeclaration adds an __asm__ label to a declaration that has
+ // already been ODR-used.
+ Diag(New->getLocation(), diag::err_late_asm_label_name)
+ << isa<FunctionDecl>(Old) << New->getAttr<AsmLabelAttr>()->getRange();
+ }
+ }
+
if (!Old->hasAttrs())
return;
@@ -2604,6 +2641,21 @@
return false;
}
+static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A,
+ const FunctionDecl *B) {
+ assert(A->getNumParams() == B->getNumParams());
+
+ auto AttrEq = [](const ParmVarDecl *A, const ParmVarDecl *B) {
+ const auto *AttrA = A->getAttr<PassObjectSizeAttr>();
+ const auto *AttrB = B->getAttr<PassObjectSizeAttr>();
+ if (AttrA == AttrB)
+ return true;
+ return AttrA && AttrB && AttrA->getType() == AttrB->getType();
+ };
+
+ return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq);
+}
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -2670,6 +2722,13 @@
}
}
+ if (New->hasAttr<InternalLinkageAttr>() &&
+ !Old->hasAttr<InternalLinkageAttr>()) {
+ Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->dropAttr<InternalLinkageAttr>();
+ }
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
@@ -2775,7 +2834,17 @@
Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) {
UndefinedButUsed.erase(Old->getCanonicalDecl());
}
-
+
+ // If pass_object_size params don't match up perfectly, this isn't a valid
+ // redeclaration.
+ if (Old->getNumParams() > 0 && Old->getNumParams() == New->getNumParams() &&
+ !hasIdenticalPassObjectSizeAttrs(Old, New)) {
+ Diag(New->getLocation(), diag::err_different_pass_object_size_params)
+ << New->getDeclName();
+ Diag(OldLocation, PrevDiag) << Old << Old->getType();
+ return true;
+ }
+
if (getLangOpts().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
@@ -3319,6 +3388,9 @@
if (New->isInvalidDecl())
return;
+ if (!shouldLinkPossiblyHiddenDecl(Previous, New))
+ return;
+
VarTemplateDecl *NewTemplate = New->getDescribedVarTemplate();
// Verify the old decl was also a variable or variable template.
@@ -3350,9 +3422,6 @@
return New->setInvalidDecl();
}
- if (!shouldLinkPossiblyHiddenDecl(Old, New))
- return;
-
// Ensure the template parameters are compatible.
if (NewTemplate &&
!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
@@ -3383,6 +3452,14 @@
New->dropAttr<WeakImportAttr>();
}
+ if (New->hasAttr<InternalLinkageAttr>() &&
+ !Old->hasAttr<InternalLinkageAttr>()) {
+ Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->dropAttr<InternalLinkageAttr>();
+ }
+
// Merge the types.
VarDecl *MostRecent = Old->getMostRecentDecl();
if (MostRecent != Old) {
@@ -3708,10 +3785,15 @@
bool IsExplicitSpecialization =
!TemplateParams.empty() && TemplateParams.back()->size() == 0;
if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() &&
- !IsExplicitInstantiation && !IsExplicitSpecialization) {
+ !IsExplicitInstantiation && !IsExplicitSpecialization &&
+ !isa<ClassTemplatePartialSpecializationDecl>(Tag)) {
// Per C++ [dcl.type.elab]p1, a class declaration cannot have a
// nested-name-specifier unless it is an explicit instantiation
// or an explicit specialization.
+ //
+ // FIXME: We allow class template partial specializations here too, per the
+ // obvious intent of DR1819.
+ //
// Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either.
Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier)
<< GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << SS.getRange();
@@ -3881,14 +3963,11 @@
DeclContext *Owner,
DeclarationName Name,
SourceLocation NameLoc,
- unsigned diagnostic) {
+ bool IsUnion) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName,
Sema::ForRedeclaration);
if (!SemaRef.LookupName(R, S)) return false;
- if (R.getAsSingle<TagDecl>())
- return false;
-
// Pick a representative declaration.
NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
assert(PrevDecl && "Expected a non-null Decl");
@@ -3896,7 +3975,8 @@
if (!SemaRef.isDeclInScope(PrevDecl, Owner, S))
return false;
- SemaRef.Diag(NameLoc, diagnostic) << Name;
+ SemaRef.Diag(NameLoc, diag::err_anonymous_record_member_redecl)
+ << IsUnion << Name;
SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
return true;
@@ -3924,10 +4004,6 @@
AccessSpecifier AS,
SmallVectorImpl<NamedDecl *> &Chaining,
bool MSAnonStruct) {
- unsigned diagKind
- = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
- : diag::err_anonymous_struct_member_redecl;
-
bool Invalid = false;
// Look every FieldDecl and IndirectFieldDecl with a name.
@@ -3936,7 +4012,8 @@
cast<NamedDecl>(D)->getDeclName()) {
ValueDecl *VD = cast<ValueDecl>(D);
if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
- VD->getLocation(), diagKind)) {
+ VD->getLocation(),
+ AnonRecord->isUnion())) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
@@ -4130,7 +4207,7 @@
assert(FD->getAccess() != AS_none);
if (FD->getAccess() != AS_public) {
Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
- << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
+ << Record->isUnion() << (FD->getAccess() == AS_protected);
Invalid = true;
}
@@ -4154,11 +4231,11 @@
// Visual C++ allows type definition in anonymous struct or union.
if (getLangOpts().MicrosoftExt)
Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type)
- << (int)Record->isUnion();
+ << Record->isUnion();
else {
// This is a nested type declaration.
Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type)
- << (int)Record->isUnion();
+ << Record->isUnion();
Invalid = true;
}
} else {
@@ -4167,7 +4244,7 @@
// not part of standard C++.
Diag(MemRecord->getLocation(),
diag::ext_anonymous_record_with_anonymous_type)
- << (int)Record->isUnion();
+ << Record->isUnion();
}
} else if (isa<AccessSpecDecl>(Mem)) {
// Any access specifier is fine.
@@ -4188,10 +4265,9 @@
if (getLangOpts().MicrosoftExt &&
DK == diag::err_anonymous_record_with_type)
Diag(Mem->getLocation(), diag::ext_anonymous_record_with_type)
- << (int)Record->isUnion();
+ << Record->isUnion();
else {
- Diag(Mem->getLocation(), DK)
- << (int)Record->isUnion();
+ Diag(Mem->getLocation(), DK) << Record->isUnion();
Invalid = true;
}
}
@@ -4208,7 +4284,7 @@
if (!Record->isUnion() && !Owner->isRecord()) {
Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
- << (int)getLangOpts().CPlusPlus;
+ << getLangOpts().CPlusPlus;
Invalid = true;
}
@@ -4602,11 +4678,13 @@
DeclarationNameInfo NameInfo) {
DeclarationName Name = NameInfo.getName();
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getIdentifier() && Record->getDeclName() == Name) {
- Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name;
- return true;
- }
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC);
+ while (Record && Record->isAnonymousStructOrUnion())
+ Record = dyn_cast<CXXRecordDecl>(Record->getParent());
+ if (Record && Record->getIdentifier() && Record->getDeclName() == Name) {
+ Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name;
+ return true;
+ }
return false;
}
@@ -4800,13 +4878,6 @@
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForRedeclaration);
- // If we're hiding internal-linkage symbols in modules from redeclaration
- // lookup, let name lookup know.
- if ((getLangOpts().Modules || getLangOpts().ModulesLocalVisibility) &&
- getLangOpts().ModulesHideInternalLinkage &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
- Previous.setAllowHiddenInternal(false);
-
// See if this is a redefinition of a variable in the same scope.
if (!D.getCXXScopeSpec().isSet()) {
bool IsLinkageLookup = false;
@@ -5200,7 +5271,7 @@
filterNonConflictingPreviousTypedefDecls(*this, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
- MergeTypedefNameDecl(NewTD, Previous);
+ MergeTypedefNameDecl(S, NewTD, Previous);
}
// If this is the C FILE type, notify the AST context.
@@ -5687,7 +5758,8 @@
// Suppress the warning in system macros, it's used in macros in some
// popular C system headers, such as in glibc's htonl() macro.
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::warn_deprecated_register)
+ getLangOpts().CPlusPlus1z ? diag::ext_register_storage_class
+ : diag::warn_deprecated_register)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
@@ -5747,7 +5819,10 @@
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
R, TInfo, SC);
-
+
+ if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
+ ParsingInitForAutoVars.insert(NewVD);
+
if (D.isInvalidType())
NewVD->setInvalidDecl();
} else {
@@ -6054,9 +6129,20 @@
}
} else if (SC == SC_Register) {
// Global Named register
- if (!Context.getTargetInfo().isValidGCCRegisterName(Label) &&
- DeclAttrsMatchCUDAMode(getLangOpts(), NewVD))
- Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
+ if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) {
+ const auto &TI = Context.getTargetInfo();
+ bool HasSizeMismatch;
+
+ if (!TI.isValidGCCRegisterName(Label))
+ Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
+ else if (!TI.validateGlobalRegisterVariable(Label,
+ Context.getTypeSize(R),
+ HasSizeMismatch))
+ Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label;
+ else if (HasSizeMismatch)
+ Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label;
+ }
+
if (!R->isIntegralType(Context) && !R->isPointerType()) {
Diag(D.getLocStart(), diag::err_asm_bad_register_type);
NewVD->setInvalidDecl(true);
@@ -7585,6 +7671,13 @@
} else {
Context.adjustExceptionSpec(NewFD, EST_BasicNoexcept);
}
+
+ // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the
+ // following restrictions:
+ // - The declaration's parameter list shall be equivalent to an empty
+ // parameter list.
+ if (FPT->getNumParams() > 0 || FPT->isVariadic())
+ Diag(NewFD->getLocation(), diag::err_function_concept_with_params);
}
// C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is
@@ -8169,6 +8262,23 @@
for (auto Param : NewFD->params())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
}
+ for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
+ PE = NewFD->param_end(); PI != PE; ++PI) {
+ ParmVarDecl *Param = *PI;
+ QualType PT = Param->getType();
+
+ // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value
+ // types.
+ if (getLangOpts().OpenCLVersion >= 200) {
+ if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
+ QualType ElemTy = PipeTy->getElementType();
+ if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
+ Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type );
+ D.setInvalidType();
+ }
+ }
+ }
+ }
MarkUnusedFileScopedDecl(NewFD);
@@ -8994,6 +9104,96 @@
}
}
+QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
+ DeclarationName Name, QualType Type,
+ TypeSourceInfo *TSI,
+ SourceRange Range, bool DirectInit,
+ Expr *Init) {
+ bool IsInitCapture = !VDecl;
+ assert((!VDecl || !VDecl->isInitCapture()) &&
+ "init captures are expected to be deduced prior to initialization");
+
+ ArrayRef<Expr *> DeduceInits = Init;
+ if (DirectInit) {
+ if (auto *PL = dyn_cast<ParenListExpr>(Init))
+ DeduceInits = PL->exprs();
+ else if (auto *IL = dyn_cast<InitListExpr>(Init))
+ DeduceInits = IL->inits();
+ }
+
+ // Deduction only works if we have exactly one source expression.
+ if (DeduceInits.empty()) {
+ // It isn't possible to write this directly, but it is possible to
+ // end up in this situation with "auto x(some_pack...);"
+ Diag(Init->getLocStart(), IsInitCapture
+ ? diag::err_init_capture_no_expression
+ : diag::err_auto_var_init_no_expression)
+ << Name << Type << Range;
+ return QualType();
+ }
+
+ if (DeduceInits.size() > 1) {
+ Diag(DeduceInits[1]->getLocStart(),
+ IsInitCapture ? diag::err_init_capture_multiple_expressions
+ : diag::err_auto_var_init_multiple_expressions)
+ << Name << Type << Range;
+ return QualType();
+ }
+
+ Expr *DeduceInit = DeduceInits[0];
+ if (DirectInit && isa<InitListExpr>(DeduceInit)) {
+ Diag(Init->getLocStart(), IsInitCapture
+ ? diag::err_init_capture_paren_braces
+ : diag::err_auto_var_init_paren_braces)
+ << isa<InitListExpr>(Init) << Name << Type << Range;
+ return QualType();
+ }
+
+ // Expressions default to 'id' when we're in a debugger.
+ bool DefaultedAnyToId = false;
+ if (getLangOpts().DebuggerCastResultToId &&
+ Init->getType() == Context.UnknownAnyTy && !IsInitCapture) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ return QualType();
+ }
+ Init = Result.get();
+ DefaultedAnyToId = true;
+ }
+
+ QualType DeducedType;
+ if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+ if (!IsInitCapture)
+ DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
+ else if (isa<InitListExpr>(Init))
+ Diag(Range.getBegin(),
+ diag::err_init_capture_deduction_failure_from_init_list)
+ << Name
+ << (DeduceInit->getType().isNull() ? TSI->getType()
+ : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ else
+ Diag(Range.getBegin(), diag::err_init_capture_deduction_failure)
+ << Name << TSI->getType()
+ << (DeduceInit->getType().isNull() ? TSI->getType()
+ : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ }
+
+ // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using
+ // 'id' instead of a specific object type prevents most of our usual
+ // checks.
+ // We only want to warn outside of template instantiations, though:
+ // inside a template, the 'id' could have come from a parameter.
+ if (ActiveTemplateInstantiations.empty() && !DefaultedAnyToId &&
+ !IsInitCapture && !DeducedType.isNull() && DeducedType->isObjCIdType()) {
+ SourceLocation Loc = TSI->getTypeLoc().getBeginLoc();
+ Diag(Loc, diag::warn_auto_var_is_id) << Name << Range;
+ }
+
+ return DeducedType;
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -9021,79 +9221,27 @@
RealDecl->setInvalidDecl();
return;
}
- ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
// Attempt typo correction early so that the type of the init expression can
- // be deduced based on the chosen correction:if the original init contains a
+ // be deduced based on the chosen correction if the original init contains a
// TypoExpr.
ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl);
if (!Res.isUsable()) {
RealDecl->setInvalidDecl();
return;
}
+ Init = Res.get();
- if (Res.get() != Init) {
- Init = Res.get();
- if (CXXDirectInit)
- CXXDirectInit = dyn_cast<ParenListExpr>(Init);
- }
-
- Expr *DeduceInit = Init;
- // Initializer could be a C++ direct-initializer. Deduction only works if it
- // contains exactly one expression.
- if (CXXDirectInit) {
- if (CXXDirectInit->getNumExprs() == 0) {
- // It isn't possible to write this directly, but it is possible to
- // end up in this situation with "auto x(some_pack...);"
- Diag(CXXDirectInit->getLocStart(),
- VDecl->isInitCapture() ? diag::err_init_capture_no_expression
- : diag::err_auto_var_init_no_expression)
- << VDecl->getDeclName() << VDecl->getType()
- << VDecl->getSourceRange();
- RealDecl->setInvalidDecl();
- return;
- } else if (CXXDirectInit->getNumExprs() > 1) {
- Diag(CXXDirectInit->getExpr(1)->getLocStart(),
- VDecl->isInitCapture()
- ? diag::err_init_capture_multiple_expressions
- : diag::err_auto_var_init_multiple_expressions)
- << VDecl->getDeclName() << VDecl->getType()
- << VDecl->getSourceRange();
- RealDecl->setInvalidDecl();
- return;
- } else {
- DeduceInit = CXXDirectInit->getExpr(0);
- if (isa<InitListExpr>(DeduceInit))
- Diag(CXXDirectInit->getLocStart(),
- diag::err_auto_var_init_paren_braces)
- << VDecl->getDeclName() << VDecl->getType()
- << VDecl->getSourceRange();
- }
- }
-
- // Expressions default to 'id' when we're in a debugger.
- bool DefaultedToAuto = false;
- if (getLangOpts().DebuggerCastResultToId &&
- Init->getType() == Context.UnknownAnyTy) {
- ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
- Init = Result.get();
- DefaultedToAuto = true;
- }
-
- QualType DeducedType;
- if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) ==
- DAR_Failed)
- DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
+ QualType DeducedType = deduceVarTypeFromInitializer(
+ VDecl, VDecl->getDeclName(), VDecl->getType(),
+ VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init);
if (DeducedType.isNull()) {
RealDecl->setInvalidDecl();
return;
}
+
VDecl->setType(DeducedType);
assert(VDecl->isLinkageValid());
@@ -9101,38 +9249,18 @@
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
- // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using
- // 'id' instead of a specific object type prevents most of our usual checks.
- // We only want to warn outside of template instantiations, though:
- // inside a template, the 'id' could have come from a parameter.
- if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto &&
- DeducedType->isObjCIdType()) {
- SourceLocation Loc =
- VDecl->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
- Diag(Loc, diag::warn_auto_var_is_id)
- << VDecl->getDeclName() << DeduceInit->getSourceRange();
- }
-
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
// We never need to merge the type, because we cannot form an incomplete
// array of auto, nor deduce such a type.
- MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/false);
+ MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
}
// Check the deduced type is valid for a variable declaration.
CheckVariableDeclarationType(VDecl);
if (VDecl->isInvalidDecl())
return;
-
- // If all looks well, warn if this is a case that will change meaning when
- // we implement N3922.
- if (DirectInit && !CXXDirectInit && isa<InitListExpr>(Init)) {
- Diag(Init->getLocStart(),
- diag::warn_auto_var_direct_list_init)
- << FixItHint::CreateInsertion(Init->getLocStart(), "=");
- }
}
// dllimport cannot be used on variable definitions.
@@ -9244,17 +9372,18 @@
}
// Perform the initialization.
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
if (!VDecl->isInvalidDecl()) {
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
- InitializationKind Kind
- = DirectInit ?
- CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(),
- Init->getLocStart(),
- Init->getLocEnd())
- : InitializationKind::CreateDirectList(
- VDecl->getLocation())
- : InitializationKind::CreateCopy(VDecl->getLocation(),
- Init->getLocStart());
+ InitializationKind Kind =
+ DirectInit
+ ? CXXDirectInit
+ ? InitializationKind::CreateDirect(VDecl->getLocation(),
+ Init->getLocStart(),
+ Init->getLocEnd())
+ : InitializationKind::CreateDirectList(VDecl->getLocation())
+ : InitializationKind::CreateCopy(VDecl->getLocation(),
+ Init->getLocStart());
MultiExprArg Args = Init;
if (CXXDirectInit)
@@ -9318,7 +9447,7 @@
if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong &&
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
Init->getLocStart()))
- getCurFunction()->markSafeWeakUse(Init);
+ getCurFunction()->markSafeWeakUse(Init);
}
// The initialization is usually a full-expression.
@@ -10206,7 +10335,7 @@
} else if (DeducedCanon != UCanon) {
Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
diag::err_auto_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
+ << (unsigned)AT->getKeyword()
<< Deduced << DeducedDecl->getDeclName()
<< U << D->getDeclName()
<< DeducedDecl->getInit()->getSourceRange()
@@ -10804,12 +10933,8 @@
// from the translation unit and reattach to the current context.
if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) {
// Is the decl actually in the context?
- for (const auto *DI : Context.getTranslationUnitDecl()->decls()) {
- if (DI == D) {
- Context.getTranslationUnitDecl()->removeDecl(D);
- break;
- }
- }
+ if (Context.getTranslationUnitDecl()->containsDecl(D))
+ Context.getTranslationUnitDecl()->removeDecl(D);
// Either way, reassign the lexical decl context to our FunctionDecl.
D->setLexicalDeclContext(CurContext);
}
@@ -10934,22 +11059,26 @@
if (FD) {
FD->setBody(Body);
- if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body &&
- !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) {
- // If the function has a deduced result type but contains no 'return'
- // statements, the result type as written must be exactly 'auto', and
- // the deduced result type is 'void'.
- if (!FD->getReturnType()->getAs<AutoType>()) {
- Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
- << FD->getReturnType();
- FD->setInvalidDecl();
- } else {
- // Substitute 'void' for the 'auto' in the type.
- TypeLoc ResultType = getReturnTypeLoc(FD);
- Context.adjustDeducedFunctionResultType(
- FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
+ if (getLangOpts().CPlusPlus14) {
+ if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
+ FD->getReturnType()->isUndeducedType()) {
+ // If the function has a deduced result type but contains no 'return'
+ // statements, the result type as written must be exactly 'auto', and
+ // the deduced result type is 'void'.
+ if (!FD->getReturnType()->getAs<AutoType>()) {
+ Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
+ << FD->getReturnType();
+ FD->setInvalidDecl();
+ } else {
+ // Substitute 'void' for the 'auto' in the type.
+ TypeLoc ResultType = getReturnTypeLoc(FD);
+ Context.adjustDeducedFunctionResultType(
+ FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
+ }
}
} else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
+ // In C++11, we don't use 'auto' deduction rules for lambda call
+ // operators because we don't support return type deduction.
auto *LSI = getCurLambda();
if (LSI->HasImplicitReturnType) {
deduceClosureReturnType(*LSI);
@@ -11697,6 +11826,28 @@
return false;
}
+/// Find the DeclContext in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static DeclContext *getTagInjectionContext(DeclContext *DC) {
+ while (!DC->isFileContext() && !DC->isFunctionOrMethod())
+ DC = DC->getParent();
+ return DC;
+}
+
+/// Find the Scope in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
+ while (S->isClassScope() ||
+ (LangOpts.CPlusPlus &&
+ S->isFunctionPrototypeScope()) ||
+ ((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() && S->getEntity()->isTransparentContext()))
+ S = S->getParent();
+ return S;
+}
+
/// \brief This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
@@ -12013,16 +12164,10 @@
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
// lexical context,
- while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod())
- SearchDC = SearchDC->getParent();
+ SearchDC = getTagInjectionContext(SearchDC);
// Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
- (getLangOpts().CPlusPlus &&
- S->isFunctionPrototypeScope()) ||
- ((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() && S->getEntity()->isTransparentContext()))
- S = S->getParent();
+ S = getTagInjectionScope(S, getLangOpts());
} else {
assert(TUK == TUK_Friend);
// C++ [namespace.memdef]p3:
@@ -12034,9 +12179,16 @@
// In C++, we need to do a redeclaration lookup to properly
// diagnose some problems.
+ // FIXME: redeclaration lookup is also used (with and without C++) to find a
+ // hidden declaration so that we don't get ambiguity errors when using a
+ // type declared by an elaborated-type-specifier. In C that is not correct
+ // and we should instead merge compatible types found by lookup.
if (getLangOpts().CPlusPlus) {
Previous.setRedeclarationKind(ForRedeclaration);
LookupQualifiedName(Previous, SearchDC);
+ } else {
+ Previous.setRedeclarationKind(ForRedeclaration);
+ LookupName(Previous, S);
}
}
@@ -12168,16 +12320,34 @@
if (!Invalid) {
// If this is a use, just return the declaration we found, unless
// we have attributes.
-
- // FIXME: In the future, return a variant or some other clue
- // for the consumer of this Decl to know it doesn't own it.
- // For our current ASTs this shouldn't be a problem, but will
- // need to be changed with DeclGroups.
- if (!Attr &&
- ((TUK == TUK_Reference &&
- (!PrevTagDecl->getFriendObjectKind() || getLangOpts().MicrosoftExt))
- || TUK == TUK_Friend))
- return PrevTagDecl;
+ if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ if (Attr) {
+ // FIXME: Diagnose these attributes. For now, we create a new
+ // declaration to hold them.
+ } else if (TUK == TUK_Reference &&
+ (PrevTagDecl->getFriendObjectKind() ==
+ Decl::FOK_Undeclared ||
+ PP.getModuleContainingLocation(
+ PrevDecl->getLocation()) !=
+ PP.getModuleContainingLocation(KWLoc)) &&
+ SS.isEmpty()) {
+ // This declaration is a reference to an existing entity, but
+ // has different visibility from that entity: it either makes
+ // a friend visible or it makes a type visible in a new module.
+ // In either case, create a new declaration. We only do this if
+ // the declaration would have meant the same thing if no prior
+ // declaration were found, that is, if it was found in the same
+ // scope where we would have injected a declaration.
+ if (!getTagInjectionContext(CurContext)->getRedeclContext()
+ ->Equals(PrevDecl->getDeclContext()->getRedeclContext()))
+ return PrevTagDecl;
+ // This is in the injected scope, create a new declaration in
+ // that scope.
+ S = getTagInjectionScope(S, getLangOpts());
+ } else {
+ return PrevTagDecl;
+ }
+ }
// Diagnose attempts to redefine a tag.
if (TUK == TUK_Definition) {
@@ -12475,7 +12645,7 @@
<< Name;
Invalid = true;
}
- } else {
+ } else if (!PrevDecl) {
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
}
DeclsInPrototypeScope.push_back(New);
@@ -13108,7 +13278,7 @@
Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
diag::err_illegal_union_or_anon_struct_member)
- << (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
+ << FD->getParent()->isUnion() << FD->getDeclName() << member;
DiagnoseNontrivial(RDecl, member);
return !getLangOpts().CPlusPlus11;
}
@@ -13956,21 +14126,6 @@
PrevDecl = nullptr;
}
- if (PrevDecl) {
- // When in C++, we may get a TagDecl with the same name; in this case the
- // enum constant will 'hide' the tag.
- assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
- "Received TagDecl when not in C++!");
- if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) {
- if (isa<EnumConstantDecl>(PrevDecl))
- Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
- else
- Diag(IdLoc, diag::err_redefinition) << Id;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return nullptr;
- }
- }
-
// C++ [class.mem]p15:
// If T is the name of a class, then each of the following shall have a name
// different from T:
@@ -13982,17 +14137,32 @@
EnumConstantDecl *New =
CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val);
+ if (!New)
+ return nullptr;
- if (New) {
- // Process attributes.
- if (Attr) ProcessDeclAttributeList(S, New, Attr);
- ProcessAPINotes(New);
-
- // Register this decl in the current scope stack.
- New->setAccess(TheEnumDecl->getAccess());
- PushOnScopeChains(New, S);
+ if (PrevDecl) {
+ // When in C++, we may get a TagDecl with the same name; in this case the
+ // enum constant will 'hide' the tag.
+ assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
+ "Received TagDecl when not in C++!");
+ if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) &&
+ shouldLinkPossiblyHiddenDecl(PrevDecl, New)) {
+ if (isa<EnumConstantDecl>(PrevDecl))
+ Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
+ else
+ Diag(IdLoc, diag::err_redefinition) << Id;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return nullptr;
+ }
}
+ // Process attributes.
+ if (Attr) ProcessDeclAttributeList(S, New, Attr);
+
+ // Register this decl in the current scope stack.
+ New->setAccess(TheEnumDecl->getAccess());
+ PushOnScopeChains(New, S);
+
ActOnDocumentableDecl(New);
return New;
@@ -14453,8 +14623,8 @@
}
static void checkModuleImportContext(Sema &S, Module *M,
- SourceLocation ImportLoc,
- DeclContext *DC) {
+ SourceLocation ImportLoc, DeclContext *DC,
+ bool FromInclude = false) {
SourceLocation ExternCLoc;
if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
@@ -14473,7 +14643,9 @@
DC = DC->getParent();
if (!isa<TranslationUnitDecl>(DC)) {
- S.Diag(ImportLoc, diag::err_module_import_not_at_top_level_fatal)
+ S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M))
+ ? diag::ext_module_import_not_at_top_level_noop
+ : diag::err_module_import_not_at_top_level_fatal)
<< M->getFullModuleName() << DC;
S.Diag(cast<Decl>(DC)->getLocStart(),
diag::note_module_import_not_at_top_level) << DC;
@@ -14532,7 +14704,7 @@
}
void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
- checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
// Determine whether we're in the #include buffer for a module. The #includes
// in that buffer do not qualify as module imports; they're just an
@@ -14543,9 +14715,15 @@
TUKind == TU_Module &&
getSourceManager().isWrittenInMainFile(DirectiveLoc);
+ // Similarly, if this module is specified by -fmodule-implementation-of
+ // don't actually synthesize an illegal module import.
+ bool ShouldAddImport = !IsInModuleIncludes &&
+ (getLangOpts().ImplementationOfModule.empty() ||
+ getLangOpts().ImplementationOfModule != Mod->getTopLevelModuleName());
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
- if (!IsInModuleIncludes) {
+ if (ShouldAddImport) {
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
DirectiveLoc, Mod,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 886504a..d58fdc7 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -244,11 +244,12 @@
/// \brief Diagnose mutually exclusive attributes when present on a given
/// declaration. Returns true if diagnosed.
template <typename AttrTy>
-static bool checkAttrMutualExclusion(Sema &S, Decl *D,
- const AttributeList &Attr) {
+static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
+ IdentifierInfo *Ident) {
if (AttrTy *A = D->getAttr<AttrTy>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << Attr.getName() << A;
+ S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident
+ << A;
+ S.Diag(A->getLocation(), diag::note_conflicting_attribute);
return true;
}
return false;
@@ -315,7 +316,7 @@
Diag(Loc->Loc, diag::err_attribute_argument_type)
<< Attr.getName() << AANT_ArgumentString
<< FixItHint::CreateInsertion(Loc->Loc, "\"")
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(Loc->Loc), "\"");
+ << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\"");
Str = Loc->Ident->getName();
if (ArgLocation)
*ArgLocation = Loc->Loc;
@@ -347,6 +348,25 @@
Attr.getAttributeSpellingListIndex()));
}
+template <typename AttrType>
+static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ handleSimpleAttribute<AttrType>(S, D, Attr);
+}
+
+/// \brief Applies the given attribute to the Decl so long as the Decl doesn't
+/// already have one of the given incompatible attributes.
+template <typename AttrType, typename IncompatibleAttrType,
+ typename... IncompatibleAttrTypes>
+static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, Attr.getRange(),
+ Attr.getName()))
+ return;
+ handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D,
+ Attr);
+}
+
/// \brief Check if the passed-in expression is of type int or bool.
static bool isIntOrBool(Expr *Exp) {
QualType QT = Exp->getType();
@@ -808,6 +828,43 @@
Attr.getAttributeSpellingListIndex()));
}
+static void handlePassObjectSizeAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (D->hasAttr<PassObjectSizeAttr>()) {
+ S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter)
+ << Attr.getName();
+ return;
+ }
+
+ Expr *E = Attr.getArgAsExpr(0);
+ uint32_t Type;
+ if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1))
+ return;
+
+ // pass_object_size's argument is passed in as the second argument of
+ // __builtin_object_size. So, it has the same constraints as that second
+ // argument; namely, it must be in the range [0, 3].
+ if (Type > 3) {
+ S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range)
+ << Attr.getName() << 0 << 3 << E->getSourceRange();
+ return;
+ }
+
+ // pass_object_size is only supported on constant pointer parameters; as a
+ // kindness to users, we allow the parameter to be non-const for declarations.
+ // At this point, we have no clue if `D` belongs to a function declaration or
+ // definition, so we defer the constness check until later.
+ if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) {
+ S.Diag(D->getLocStart(), diag::err_attribute_pointers_only)
+ << Attr.getName() << 1;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
ConsumableAttr::ConsumedState DefaultState;
@@ -1035,17 +1092,14 @@
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- // If the alignment is less than or equal to 8 bits, the packed attribute
- // has no effect.
+ // Report warning about changed offset in the newer compiler versions.
if (!FD->getType()->isDependentType() &&
- !FD->getType()->isIncompleteType() &&
+ !FD->getType()->isIncompleteType() && FD->isBitField() &&
S.Context.getTypeAlign(FD->getType()) <= 8)
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
- << Attr.getName() << FD->getType();
- else
- FD->addAttr(::new (S.Context)
- PackedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield);
+
+ FD->addAttr(::new (S.Context) PackedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -1161,10 +1215,12 @@
SourceRange TypeRange,
bool isReturnValue = false) {
if (!S.isValidPointerAttrType(T)) {
- S.Diag(Attr.getLoc(), isReturnValue
- ? diag::warn_attribute_return_pointers_only
- : diag::warn_attribute_pointers_only)
- << Attr.getName() << AttrParmRange << TypeRange;
+ if (isReturnValue)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only)
+ << Attr.getName() << AttrParmRange << TypeRange;
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only)
+ << Attr.getName() << AttrParmRange << TypeRange << 0;
return false;
}
return true;
@@ -1543,7 +1599,7 @@
}
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (checkAttrMutualExclusion<HotAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName()))
return;
D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context,
@@ -1551,7 +1607,7 @@
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName()))
return;
D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context,
@@ -1593,12 +1649,22 @@
static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CPlusPlus) {
S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
- << Attr.getName() << AttributeLangSupport::Cpp;
+ << Attr.getName() << AttributeLangSupport::Cpp;
return;
}
- D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(),
+ Attr.getAttributeSpellingListIndex()))
+ D->addAttr(CA);
+}
+
+static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
+ return;
+
+ D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
@@ -1637,7 +1703,7 @@
!VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
+ : diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
@@ -1723,13 +1789,24 @@
static void handleNotTailCalledAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
D->addAttr(::new (S.Context) NotTailCalledAttr(
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
+static void handleDisableTailCallsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<NakedAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
+ return;
+
+ D->addAttr(::new (S.Context) DisableTailCallsAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage()) {
@@ -2730,7 +2807,7 @@
if (prioritynum < 101 || prioritynum > 65535) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range)
- << E->getSourceRange();
+ << E->getSourceRange() << Attr.getName() << 101 << 65535;
Attr.setInvalid();
return;
}
@@ -3240,38 +3317,31 @@
return true;
}
-/// handleModeAttr - This attribute modifies the width of a decl with primitive
-/// type.
-///
-/// Despite what would be logical, the mode attribute is a decl attribute, not a
-/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
-/// HImode, not an intermediate pointer.
-static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // This attribute isn't documented, but glibc uses it. It changes
- // the width of an int or unsigned int to the specified size.
- if (!Attr.isArgIdent(0)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
- << AANT_ArgumentIdentifier;
- return;
- }
-
- IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
- StringRef Str = Name->getName();
-
- normalizeName(Str);
-
- unsigned DestWidth = 0;
- bool IntegerMode = true;
- bool ComplexMode = false;
+/// parseModeAttrArg - Parses attribute mode string and returns parsed type
+/// attribute.
+static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
+ bool &IntegerMode, bool &ComplexMode) {
switch (Str.size()) {
case 2:
switch (Str[0]) {
- case 'Q': DestWidth = 8; break;
- case 'H': DestWidth = 16; break;
- case 'S': DestWidth = 32; break;
- case 'D': DestWidth = 64; break;
- case 'X': DestWidth = 96; break;
- case 'T': DestWidth = 128; break;
+ case 'Q':
+ DestWidth = 8;
+ break;
+ case 'H':
+ DestWidth = 16;
+ break;
+ case 'S':
+ DestWidth = 32;
+ break;
+ case 'D':
+ DestWidth = 64;
+ break;
+ case 'X':
+ DestWidth = 96;
+ break;
+ case 'T':
+ DestWidth = 128;
+ break;
}
if (Str[1] == 'F') {
IntegerMode = false;
@@ -3299,17 +3369,58 @@
DestWidth = S.Context.getTargetInfo().getUnwindWordWidth();
break;
}
+}
+
+/// handleModeAttr - This attribute modifies the width of a decl with primitive
+/// type.
+///
+/// Despite what would be logical, the mode attribute is a decl attribute, not a
+/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
+/// HImode, not an intermediate pointer.
+static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // This attribute isn't documented, but glibc uses it. It changes
+ // the width of an int or unsigned int to the specified size.
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
+ << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
+ StringRef Str = Name->getName();
+
+ normalizeName(Str);
+
+ unsigned DestWidth = 0;
+ bool IntegerMode = true;
+ bool ComplexMode = false;
+ llvm::APInt VectorSize(64, 0);
+ if (Str.size() >= 4 && Str[0] == 'V') {
+ // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2).
+ size_t StrSize = Str.size();
+ size_t VectorStringLength = 0;
+ while ((VectorStringLength + 1) < StrSize &&
+ isdigit(Str[VectorStringLength + 1]))
+ ++VectorStringLength;
+ if (VectorStringLength &&
+ !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) &&
+ VectorSize.isPowerOf2()) {
+ parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth,
+ IntegerMode, ComplexMode);
+ S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated);
+ } else {
+ VectorSize = 0;
+ }
+ }
+
+ if (!VectorSize)
+ parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode);
QualType OldTy;
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
OldTy = TD->getUnderlyingType();
- else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
- OldTy = VD->getType();
- else {
- S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
- << Attr.getName() << Attr.getRange();
- return;
- }
+ else
+ OldTy = cast<ValueDecl>(D)->getType();
// Base type can also be a vector type (see PR17453).
// Distinguish between base type and base element type.
@@ -3357,7 +3468,10 @@
}
QualType NewTy = NewElemTy;
- if (const VectorType *OldVT = OldTy->getAs<VectorType>()) {
+ if (VectorSize.getBoolValue()) {
+ NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(),
+ VectorType::GenericVector);
+ } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) {
// Complex machine mode does not support base vector types.
if (ComplexMode) {
S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type);
@@ -3420,6 +3534,42 @@
AttrSpellingListIndex);
}
+CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex) {
+ if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, Range, Ident))
+ return nullptr;
+
+ return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex);
+}
+
+InternalLinkageAttr *
+Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
+ unsigned AttrSpellingListIndex) {
+ if (auto VD = dyn_cast<VarDecl>(D)) {
+ // Attribute applies to Var but not any subclass of it (like ParmVar,
+ // ImplicitParm or VarTemplateSpecialization).
+ if (VD->getKind() != Decl::Var) {
+ Diag(Range.getBegin(), diag::warn_attribute_wrong_decl_type)
+ << Ident << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
+ : ExpectedVariableOrFunction);
+ return nullptr;
+ }
+ // Attribute does not apply to non-static local variables.
+ if (VD->hasLocalStorage()) {
+ Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
+ return nullptr;
+ }
+ }
+
+ if (checkAttrMutualExclusion<CommonAttr>(*this, D, Range, Ident))
+ return nullptr;
+
+ return ::new (Context)
+ InternalLinkageAttr(Range, Context, AttrSpellingListIndex);
+}
+
MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
@@ -3473,7 +3623,8 @@
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
@@ -3496,6 +3647,12 @@
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(),
+ Attr.getName()) ||
+ checkAttrMutualExclusion<CUDAHostAttr>(S, D, Attr.getRange(),
+ Attr.getName())) {
+ return;
+ }
FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getReturnType()->isVoidType()) {
SourceRange RTRange = FD->getReturnTypeSourceRange();
@@ -3806,7 +3963,7 @@
QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx);
if (!BufferTy->isPointerType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
- << Attr.getName();
+ << Attr.getName() << 0;
}
}
@@ -4092,7 +4249,8 @@
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
D->addAttr(::new (S.Context)
@@ -4102,7 +4260,8 @@
static void handleCFUnknownTransferAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
D->addAttr(::new (S.Context)
@@ -4638,12 +4797,149 @@
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
+static void handleMipsInterruptAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Only one optional argument permitted.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 1;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ if (Attr.getNumArgs() == 0)
+ Str = "";
+ else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
+ return;
+
+ // Semantic checks for a function with the 'interrupt' attribute for MIPS:
+ // a) Must be a function.
+ // b) Must have no parameters.
+ // c) Must have the 'void' return type.
+ // d) Cannot have the 'mips16' attribute, as that instruction set
+ // lacks the 'eret' instruction.
+ // e) The attribute itself must either have no argument or one of the
+ // valid interrupt types, see [MipsInterruptDocs].
+
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'interrupt'" << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
+ S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
+ << 0;
+ return;
+ }
+
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
+ << 1;
+ return;
+ }
+
+ if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(),
+ Attr.getName()))
+ return;
+
+ MipsInterruptAttr::InterruptType Kind;
+ if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << Attr.getName() << "'" + std::string(Str) + "'";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) MipsInterruptAttr(
+ Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleAnyX86InterruptAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Semantic checks for a function with the 'interrupt' attribute.
+ // a) Must be a function.
+ // b) Must have the 'void' return type.
+ // c) Must take 1 or 2 arguments.
+ // d) The 1st argument must be a pointer.
+ // e) The 2nd argument (if any) must be an unsigned integer.
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
+ CXXMethodDecl::isStaticOverloadedOperator(
+ cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionWithProtoType;
+ return;
+ }
+ // Interrupt handler must have void return type.
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 0;
+ return;
+ }
+ // Interrupt handler must have 1 or 2 parameters.
+ unsigned NumParams = getFunctionOrMethodNumParams(D);
+ if (NumParams < 1 || NumParams > 2) {
+ S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 1;
+ return;
+ }
+ // The first argument must be a pointer.
+ if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
+ S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 2;
+ return;
+ }
+ // The second argument, if present, must be an unsigned integer.
+ unsigned TypeSize =
+ S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
+ ? 64
+ : 32;
+ if (NumParams == 2 &&
+ (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
+ S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
+ S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
+ return;
+ }
+ D->addAttr(::new (S.Context) AnyX86InterruptAttr(
+ Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex()));
+ D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Dispatch the interrupt attribute based on the current target.
- if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
+ switch (S.Context.getTargetInfo().getTriple().getArch()) {
+ case llvm::Triple::msp430:
handleMSP430InterruptAttr(S, D, Attr);
- else
+ break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips:
+ handleMipsInterruptAttr(S, D, Attr);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ handleAnyX86InterruptAttr(S, D, Attr);
+ break;
+ default:
handleARMInterruptAttr(S, D, Attr);
+ break;
+ }
}
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
@@ -4937,6 +5233,14 @@
Attr.getAttributeSpellingListIndex()));
}
+static void handleInternalLinkageAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (InternalLinkageAttr *Internal =
+ S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(),
+ Attr.getAttributeSpellingListIndex()))
+ D->addAttr(Internal);
+}
+
/// Handles semantic checking for features that are common to all attributes,
/// such as checking whether a parameter was properly specified, or the correct
/// number of arguments were passed, etc.
@@ -5027,7 +5331,8 @@
handleDLLAttr(S, D, Attr);
break;
case AttributeList::AT_Mips16:
- handleSimpleAttribute<Mips16Attr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<Mips16Attr, MipsInterruptAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
@@ -5078,7 +5383,11 @@
handleCommonAttr(S, D, Attr);
break;
case AttributeList::AT_CUDAConstant:
- handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDAConstantAttr, CUDASharedAttr>(S, D,
+ Attr);
+ break;
+ case AttributeList::AT_PassObjectSize:
+ handlePassObjectSizeAttr(S, D, Attr);
break;
case AttributeList::AT_Constructor:
handleConstructorAttr(S, D, Attr);
@@ -5120,10 +5429,12 @@
handleGlobalAttr(S, D, Attr);
break;
case AttributeList::AT_CUDADevice:
- handleSimpleAttribute<CUDADeviceAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_CUDAHost:
- handleSimpleAttribute<CUDAHostAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_GNUInline:
handleGNUInlineAttr(S, D, Attr);
@@ -5177,7 +5488,7 @@
handleHotAttr(S, D, Attr);
break;
case AttributeList::AT_Naked:
- handleSimpleAttribute<NakedAttr>(S, D, Attr);
+ handleNakedAttr(S, D, Attr);
break;
case AttributeList::AT_NoReturn:
handleNoReturnAttr(S, D, Attr);
@@ -5186,7 +5497,8 @@
handleSimpleAttribute<NoThrowAttr>(S, D, Attr);
break;
case AttributeList::AT_CUDAShared:
- handleSimpleAttribute<CUDASharedAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDASharedAttr, CUDAConstantAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_VecReturn:
handleVecReturnAttr(S, D, Attr);
@@ -5310,6 +5622,9 @@
case AttributeList::AT_NotTailCalled:
handleNotTailCalledAttr(S, D, Attr);
break;
+ case AttributeList::AT_DisableTailCalls:
+ handleDisableTailCallsAttr(S, D, Attr);
+ break;
case AttributeList::AT_Used:
handleUsedAttr(S, D, Attr);
break;
@@ -5394,6 +5709,9 @@
case AttributeList::AT_OpenCLImageAccess:
handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr);
break;
+ case AttributeList::AT_InternalLinkage:
+ handleInternalLinkageAttr(S, D, Attr);
+ break;
// Microsoft attributes:
case AttributeList::AT_MSNoVTable:
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 42f4fce..10f6c12 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1553,9 +1553,9 @@
/// \brief Performs the actual work of attaching the given base class
/// specifiers to a C++ class.
-bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
- unsigned NumBases) {
- if (NumBases == 0)
+bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
+ MutableArrayRef<CXXBaseSpecifier *> Bases) {
+ if (Bases.empty())
return false;
// Used to keep track of which base types we have already seen, so
@@ -1571,7 +1571,7 @@
// Copy non-redundant base specifiers into permanent storage.
unsigned NumGoodBases = 0;
bool Invalid = false;
- for (unsigned idx = 0; idx < NumBases; ++idx) {
+ for (unsigned idx = 0; idx < Bases.size(); ++idx) {
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
@@ -1597,7 +1597,7 @@
Bases[NumGoodBases++] = Bases[idx];
// Note this base's direct & indirect bases, if there could be ambiguity.
- if (NumBases > 1)
+ if (Bases.size() > 1)
NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType);
if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
@@ -1619,7 +1619,7 @@
}
// Attach the remaining base class specifiers to the derived class.
- Class->setBases(Bases, NumGoodBases);
+ Class->setBases(Bases.data(), NumGoodBases);
for (unsigned idx = 0; idx < NumGoodBases; ++idx) {
// Check whether this direct base is inaccessible due to ambiguity.
@@ -1654,21 +1654,21 @@
/// ActOnBaseSpecifiers - Attach the given base specifiers to the
/// class, after checking whether there are any duplicate base
/// classes.
-void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
- unsigned NumBases) {
- if (!ClassDecl || !Bases || !NumBases)
+void Sema::ActOnBaseSpecifiers(Decl *ClassDecl,
+ MutableArrayRef<CXXBaseSpecifier *> Bases) {
+ if (!ClassDecl || Bases.empty())
return;
AdjustDeclIfTemplate(ClassDecl);
- AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl), Bases, NumBases);
+ AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl), Bases);
}
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
-bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
+bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) {
if (!getLangOpts().CPlusPlus)
return false;
-
+
CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
@@ -1682,13 +1682,18 @@
if (BaseRD->isInvalidDecl() || DerivedRD->isInvalidDecl())
return false;
- // FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
- return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
+ // FIXME: In a modules build, do we need the entire path to be visible for us
+ // to be able to use the inheritance relationship?
+ if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
+ return false;
+
+ return DerivedRD->isDerivedFrom(BaseRD);
}
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
-bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
+bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base,
+ CXXBasePaths &Paths) {
if (!getLangOpts().CPlusPlus)
return false;
@@ -1700,6 +1705,9 @@
if (!BaseRD)
return false;
+ if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
+ return false;
+
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
@@ -1734,26 +1742,31 @@
/// otherwise. Loc is the location where this routine should point to
/// if there is an error, and Range is the source range to highlight
/// if there is an error.
+///
+/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the
+/// diagnostic for the respective type of error will be suppressed, but the
+/// check for ill-formed code will still be performed.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name,
- CXXCastPath *BasePath) {
+ CXXCastPath *BasePath,
+ bool IgnoreAccess) {
// First, determine whether the path from Derived to Base is
// ambiguous. This is slightly more expensive than checking whether
// the Derived to Base conversion exists, because here we need to
// explore multiple paths to determine if there is an ambiguity.
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
- bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths);
+ bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths);
assert(DerivationOkay &&
"Can only be used with a derived-to-base conversion");
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (InaccessibleBaseID) {
+ if (!IgnoreAccess) {
// Check that the base class can be accessed.
switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
InaccessibleBaseID)) {
@@ -1781,7 +1794,7 @@
// performance isn't as much of an issue.
Paths.clear();
Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
+ bool StillOkay = IsDerivedFrom(Loc, Derived, Base, Paths);
assert(StillOkay && "Can only be used with a derived-to-base conversion");
(void)StillOkay;
@@ -1802,12 +1815,10 @@
SourceLocation Loc, SourceRange Range,
CXXCastPath *BasePath,
bool IgnoreAccess) {
- return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? 0
- : diag::err_upcast_to_inaccessible_base,
- diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName(),
- BasePath);
+ return CheckDerivedToBaseConversion(
+ Derived, Base, diag::err_upcast_to_inaccessible_base,
+ diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName(),
+ BasePath, IgnoreAccess);
}
@@ -2757,7 +2768,8 @@
// virtual base class.
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
- if (SemaRef.IsDerivedFrom(SemaRef.Context.getTypeDeclType(ClassDecl),
+ if (SemaRef.IsDerivedFrom(ClassDecl->getLocation(),
+ SemaRef.Context.getTypeDeclType(ClassDecl),
BaseType, Paths)) {
for (CXXBasePaths::paths_iterator Path = Paths.begin();
Path != Paths.end(); ++Path) {
@@ -2980,10 +2992,15 @@
if (BaseType.isNull()) {
BaseType = Context.getTypeDeclType(TyD);
MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false);
- if (SS.isSet())
- // FIXME: preserve source range information
+ if (SS.isSet()) {
BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(),
BaseType);
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ }
}
}
@@ -4406,64 +4423,35 @@
}
}
-bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
- unsigned DiagID, AbstractDiagSelID SelID) {
- class NonAbstractTypeDiagnoser : public TypeDiagnoser {
- unsigned DiagID;
- AbstractDiagSelID SelID;
-
- public:
- NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID)
- : TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { }
-
- void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
- if (Suppressed) return;
- if (SelID == -1)
- S.Diag(Loc, DiagID) << T;
- else
- S.Diag(Loc, DiagID) << SelID << T;
- }
- } Diagnoser(DiagID, SelID);
-
- return RequireNonAbstractType(Loc, T, Diagnoser);
-}
-
-bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
- TypeDiagnoser &Diagnoser) {
+bool Sema::isAbstractType(SourceLocation Loc, QualType T) {
if (!getLangOpts().CPlusPlus)
return false;
- if (const ArrayType *AT = Context.getAsArrayType(T))
- return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
-
- if (const PointerType *PT = T->getAs<PointerType>()) {
- // Find the innermost pointer type.
- while (const PointerType *T = PT->getPointeeType()->getAs<PointerType>())
- PT = T;
-
- if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
- return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
- }
-
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
+ const auto *RD = Context.getBaseElementType(T)->getAsCXXRecordDecl();
+ if (!RD)
return false;
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ // FIXME: Per [temp.inst]p1, we are supposed to trigger instantiation of a
+ // class template specialization here, but doing so breaks a lot of code.
// We can't answer whether something is abstract until it has a
- // definition. If it's currently being defined, we'll walk back
+ // definition. If it's currently being defined, we'll walk back
// over all the declarations when we have a full definition.
const CXXRecordDecl *Def = RD->getDefinition();
if (!Def || Def->isBeingDefined())
return false;
- if (!RD->isAbstract())
+ return RD->isAbstract();
+}
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+ TypeDiagnoser &Diagnoser) {
+ if (!isAbstractType(Loc, T))
return false;
+ T = Context.getBaseElementType(T);
Diagnoser.diagnose(*this, Loc, T);
- DiagnoseAbstractType(RD);
-
+ DiagnoseAbstractType(T->getAsCXXRecordDecl());
return true;
}
@@ -5641,7 +5629,9 @@
/// having a particular direct or virtual base class.
bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
- return shouldDeleteForClassSubobject(BaseClass, Base, 0);
+ // If program is correct, BaseClass cannot be null, but if it is, the error
+ // must be reported elsewhere.
+ return BaseClass && shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
/// Check whether we should delete a special member function due to the class
@@ -7013,6 +7003,7 @@
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
extendLeft(Before, Chunk.getSourceRange());
break;
@@ -7035,7 +7026,7 @@
// If we can provide a correct fix-it hint, do so.
if (After.isInvalid() && ConvTSI) {
SourceLocation InsertLoc =
- PP.getLocForEndOfToken(ConvTSI->getTypeLoc().getLocEnd());
+ getLocForEndOfToken(ConvTSI->getTypeLoc().getLocEnd());
DB << FixItHint::CreateInsertion(InsertLoc, " ")
<< FixItHint::CreateInsertionFromRange(
InsertLoc, CharSourceRange::getTokenRange(Before))
@@ -7118,7 +7109,7 @@
if (ConvType == ClassType)
Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used)
<< ClassType;
- else if (IsDerivedFrom(ClassType, ConvType))
+ else if (IsDerivedFrom(Conversion->getLocation(), ClassType, ConvType))
Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used)
<< ClassType << ConvType;
} else if (ConvType->isVoidType()) {
@@ -7185,7 +7176,8 @@
SourceLocation IdentLoc,
IdentifierInfo *II,
SourceLocation LBrace,
- AttributeList *AttrList) {
+ AttributeList *AttrList,
+ UsingDirectiveDecl *&UD) {
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
@@ -7206,23 +7198,14 @@
// treated as an original-namespace-name.
//
// Since namespace names are unique in their scope, and we don't
- // look through using directives, just look for any ordinary names.
-
- const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
- Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
- Decl::IDNS_Namespace;
- NamedDecl *PrevDecl = nullptr;
- DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
- ++I) {
- if ((*I)->getIdentifierNamespace() & IDNS) {
- PrevDecl = *I;
- break;
- }
- }
-
+ // look through using directives, just look for any ordinary names
+ // as if by qualified name lookup.
+ LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration);
+ LookupQualifiedName(R, CurContext->getRedeclContext());
+ NamedDecl *PrevDecl =
+ R.isSingleResult() ? R.getRepresentativeDecl() : nullptr;
PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
-
+
if (PrevNS) {
// This is an extended namespace definition.
if (IsInline != PrevNS->isInline())
@@ -7310,14 +7293,13 @@
// namespace internal linkage.
if (!PrevNS) {
- UsingDirectiveDecl* UD
- = UsingDirectiveDecl::Create(Context, Parent,
- /* 'using' */ LBrace,
- /* 'namespace' */ SourceLocation(),
- /* qualifier */ NestedNameSpecifierLoc(),
- /* identifier */ SourceLocation(),
- Namespc,
- /* Ancestor */ Parent);
+ UD = UsingDirectiveDecl::Create(Context, Parent,
+ /* 'using' */ LBrace,
+ /* 'namespace' */ SourceLocation(),
+ /* qualifier */ NestedNameSpecifierLoc(),
+ /* identifier */ SourceLocation(),
+ Namespc,
+ /* Ancestor */ Parent);
UD->setImplicit();
Parent->addDecl(UD);
}
@@ -7555,7 +7537,7 @@
S.PDiag(diag::err_using_directive_suggest) << Ident,
S.PDiag(diag::note_namespace_defined_here));
}
- R.addDecl(Corrected.getCorrectionDecl());
+ R.addDecl(Corrected.getFoundDecl());
return true;
}
return false;
@@ -7573,7 +7555,7 @@
assert(IdentLoc.isValid() && "Invalid NamespceName location.");
// This can only happen along a recovery path.
- while (S->getFlags() & Scope::TemplateParamScope)
+ while (S->isTemplateParamScope())
S = S->getParent();
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
@@ -7603,9 +7585,9 @@
}
if (!R.empty()) {
- NamedDecl *Named = R.getFoundDecl();
- assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
- && "expected namespace decl");
+ NamedDecl *Named = R.getRepresentativeDecl();
+ NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>();
+ assert(NS && "expected namespace decl");
// The use of a nested name specifier may trigger deprecation warnings.
DiagnoseUseOfDecl(Named, IdentLoc);
@@ -7622,7 +7604,6 @@
// Find enclosing context containing both using-directive and
// nominated namespace.
- NamespaceDecl *NS = getNamespaceDecl(Named);
DeclContext *CommonAncestor = cast<DeclContext>(NS);
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
CommonAncestor = CommonAncestor->getParent();
@@ -7821,6 +7802,10 @@
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
PrevShadow = Shadow;
FoundEquivalentDecl = true;
+ } else if (isEquivalentInternalLinkageDeclaration(D, Target)) {
+ // We don't conflict with an existing using shadow decl of an equivalent
+ // declaration, but we're not a redeclaration of it.
+ FoundEquivalentDecl = true;
}
if (isVisible(D))
@@ -8400,7 +8385,7 @@
} else {
// Convert 'using X::Y;' to 'typedef X::Y Y;'.
SourceLocation InsertLoc =
- PP.getLocForEndOfToken(NameInfo.getLocEnd());
+ getLocForEndOfToken(NameInfo.getLocEnd());
Diag(InsertLoc, diag::note_using_decl_class_member_workaround)
<< 1 // typedef declaration
<< FixItHint::CreateReplacement(UsingLoc, "typedef")
@@ -8533,7 +8518,7 @@
TypeResult Type,
Decl *DeclFromDeclSpec) {
// Skip up to the relevant declaration scope.
- while (S->getFlags() & Scope::TemplateParamScope)
+ while (S->isTemplateParamScope())
S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
@@ -8695,28 +8680,41 @@
}
}
assert(!R.isAmbiguous() && !R.empty());
+ NamedDecl *ND = R.getRepresentativeDecl();
// Check if we have a previous declaration with the same name.
- NamedDecl *PrevDecl = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
- ForRedeclaration);
- if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
- PrevDecl = nullptr;
+ LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ LookupName(PrevR, S);
- NamedDecl *ND = R.getFoundDecl();
+ // Check we're not shadowing a template parameter.
+ if (PrevR.isSingleResult() && PrevR.getFoundDecl()->isTemplateParameter()) {
+ DiagnoseTemplateParameterShadow(AliasLoc, PrevR.getFoundDecl());
+ PrevR.clear();
+ }
- if (PrevDecl) {
+ // Filter out any other lookup result from an enclosing scope.
+ FilterLookupForScope(PrevR, CurContext, S, /*ConsiderLinkage*/false,
+ /*AllowInlineNamespace*/false);
+
+ // Find the previous declaration and check that we can redeclare it.
+ NamespaceAliasDecl *Prev = nullptr;
+ if (PrevR.isSingleResult()) {
+ NamedDecl *PrevDecl = PrevR.getRepresentativeDecl();
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace; check that it matches.
- if (!AD->getNamespace()->Equals(getNamespaceDecl(ND))) {
+ if (AD->getNamespace()->Equals(getNamespaceDecl(ND))) {
+ Prev = AD;
+ } else if (isVisible(PrevDecl)) {
Diag(AliasLoc, diag::err_redefinition_different_namespace_alias)
<< Alias;
- Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias)
+ Diag(AD->getLocation(), diag::note_previous_namespace_alias)
<< AD->getNamespace();
return nullptr;
}
- } else {
- unsigned DiagID = isa<NamespaceDecl>(PrevDecl)
+ } else if (isVisible(PrevDecl)) {
+ unsigned DiagID = isa<NamespaceDecl>(PrevDecl->getUnderlyingDecl())
? diag::err_redefinition
: diag::err_redefinition_different_kind;
Diag(AliasLoc, DiagID) << Alias;
@@ -8732,8 +8730,8 @@
NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
Alias, SS.getWithLocInContext(Context),
IdentLoc, ND);
- if (PrevDecl)
- AliasDecl->setPreviousDecl(cast<NamespaceAliasDecl>(PrevDecl));
+ if (Prev)
+ AliasDecl->setPreviousDecl(Prev);
PushOnScopeChains(AliasDecl, S);
return AliasDecl;
@@ -9483,6 +9481,10 @@
if (Class->getDescribedClassTemplate())
return;
+ CallingConv ExpectedCallingConv = S.Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true);
+
+ CXXConstructorDecl *LastExportedDefaultCtor = nullptr;
for (Decl *Member : Class->decls()) {
auto *CD = dyn_cast<CXXConstructorDecl>(Member);
if (!CD) {
@@ -9494,7 +9496,25 @@
continue;
}
- for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
+ CallingConv ActualCallingConv =
+ CD->getType()->getAs<FunctionProtoType>()->getCallConv();
+
+ // Skip default constructors with typical calling conventions and no default
+ // arguments.
+ unsigned NumParams = CD->getNumParams();
+ if (ExpectedCallingConv == ActualCallingConv && NumParams == 0)
+ continue;
+
+ if (LastExportedDefaultCtor) {
+ S.Diag(LastExportedDefaultCtor->getLocation(),
+ diag::err_attribute_dll_ambiguous_default_ctor) << Class;
+ S.Diag(CD->getLocation(), diag::note_entity_declared_at)
+ << CD->getDeclName();
+ return;
+ }
+ LastExportedDefaultCtor = CD;
+
+ for (unsigned I = 0; I != NumParams; ++I) {
// Skip any default arguments that we've already instantiated.
if (S.Context.getDefaultArgExprForConstructor(CD, I))
continue;
@@ -12226,7 +12246,7 @@
diag::ext_unelaborated_friend_type)
<< (unsigned) RD->getTagKind()
<< T
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ << FixItHint::CreateInsertion(getLocForEndOfToken(FriendLoc),
InsertionText);
} else {
Diag(FriendLoc,
@@ -13017,7 +13037,7 @@
if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
// Check if the new class derives from the old class.
- if (!IsDerivedFrom(NewClassTy, OldClassTy)) {
+ if (!IsDerivedFrom(New->getLocation(), NewClassTy, OldClassTy)) {
Diag(New->getLocation(), diag::err_covariant_return_not_derived)
<< New->getDeclName() << NewTy << OldTy
<< New->getReturnTypeSourceRange();
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index c52558d..3f957af 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -15,12 +15,11 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
-#include "clang/AST/DataRecursiveASTVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Lookup.h"
@@ -607,7 +606,7 @@
} else if (typeBound->isObjCObjectType()) {
// The user forgot the * on an Objective-C pointer type, e.g.,
// "T : NSView".
- SourceLocation starLoc = PP.getLocForEndOfToken(
+ SourceLocation starLoc = getLocForEndOfToken(
typeBoundInfo->getTypeLoc().getEndLoc());
Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
diag::err_objc_type_param_bound_missing_pointer)
@@ -760,7 +759,7 @@
if (newTypeParams->size() > prevTypeParams->size()) {
diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation();
} else {
- diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd());
+ diagLoc = S.getLocForEndOfToken(newTypeParams->back()->getLocEnd());
}
S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch)
@@ -875,7 +874,7 @@
newContext == TypeParamListContext::Definition) {
// Diagnose this problem for forward declarations and definitions.
SourceLocation insertionLoc
- = S.PP.getLocForEndOfToken(newTypeParam->getLocation());
+ = S.getLocForEndOfToken(newTypeParam->getLocation());
std::string newCode
= " : " + prevTypeParam->getUnderlyingType().getAsString(
S.Context.getPrintingPolicy());
@@ -1410,8 +1409,8 @@
if (allProtocolsDeclared) {
Diag(firstClassNameLoc, diag::warn_objc_redundant_qualified_class_type)
<< baseClass->getDeclName() << SourceRange(lAngleLoc, rAngleLoc)
- << FixItHint::CreateInsertion(
- PP.getLocForEndOfToken(firstClassNameLoc), " *");
+ << FixItHint::CreateInsertion(getLocForEndOfToken(firstClassNameLoc),
+ " *");
}
}
@@ -1491,7 +1490,7 @@
// If we have a typedef of an Objective-C class type that is missing a '*',
// add the '*'.
if (type->getAs<ObjCInterfaceType>()) {
- SourceLocation starLoc = PP.getLocForEndOfToken(loc);
+ SourceLocation starLoc = getLocForEndOfToken(loc);
ParsedAttributes parsedAttrs(attrFactory);
D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc,
SourceLocation(),
@@ -1872,6 +1871,8 @@
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
+ // FIXME: This will produce an error if the definition of the interface has
+ // been imported from a module but is not visible.
RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
diag::warn_undef_interface);
} else {
@@ -2269,7 +2270,7 @@
DiagID =
IsOverridingMode ? diag::warn_non_covariant_overriding_ret_types
- : diag::warn_non_covariant_ret_types;
+ : diag::warn_non_covariant_ret_types;
}
}
@@ -2353,7 +2354,7 @@
DiagID =
IsOverridingMode ? diag::warn_non_contravariant_overriding_param_types
- : diag::warn_non_contravariant_param_types;
+ : diag::warn_non_contravariant_param_types;
}
}
@@ -2362,7 +2363,7 @@
<< MethodImpl->getDeclName() << IfaceTy << ImplTy;
S.Diag(IfaceVar->getLocation(),
(IsOverridingMode ? diag::note_previous_declaration
- : diag::note_previous_definition))
+ : diag::note_previous_definition))
<< getTypeRange(IfaceVar->getTypeSourceInfo());
return false;
}
@@ -2737,7 +2738,8 @@
for (auto *I : CDecl->class_methods()) {
if (!ClsMapSeen.insert(I->getSelector()).second)
continue;
- if (!ClsMap.count(I->getSelector())) {
+ if (!I->isPropertyAccessor() &&
+ !ClsMap.count(I->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
diag::warn_undef_method_impl);
@@ -2746,12 +2748,14 @@
IMPDecl->getClassMethod(I->getSelector());
assert(CDecl->getClassMethod(I->getSelector()) &&
"Expected to find the method through lookup as well");
- if (!WarnCategoryMethodImpl)
- WarnConflictingTypedMethods(ImpMethodDecl, I,
- isa<ObjCProtocolDecl>(CDecl));
- else
- WarnExactTypedMethods(ImpMethodDecl, I,
- isa<ObjCProtocolDecl>(CDecl));
+ // ImpMethodDecl may be null as in a @dynamic property.
+ if (ImpMethodDecl) {
+ if (!WarnCategoryMethodImpl)
+ WarnConflictingTypedMethods(ImpMethodDecl, I,
+ isa<ObjCProtocolDecl>(CDecl));
+ else if (!I->isPropertyAccessor())
+ WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl));
+ }
}
}
@@ -3653,10 +3657,11 @@
// property will be synthesized when property with same name is
// seen in the @implementation.
for (const auto *Ext : IDecl->visible_extensions()) {
- for (const auto *Property : Ext->properties()) {
+ for (const auto *Property : Ext->instance_properties()) {
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
- = IC->FindPropertyImplDecl(Property->getIdentifier()))
+ = IC->FindPropertyImplDecl(Property->getIdentifier(),
+ Property->getQueryKind()))
if (PIDecl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic)
continue;
@@ -4580,7 +4585,7 @@
/// Used by Sema::DiagnoseUnusedBackingIvarInAccessor to check if a property
/// accessor references the backing ivar.
class UnusedBackingIvarChecker :
- public DataRecursiveASTVisitor<UnusedBackingIvarChecker> {
+ public RecursiveASTVisitor<UnusedBackingIvarChecker> {
public:
Sema &S;
const ObjCMethodDecl *Method;
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index f993a28..f12bf24 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -713,7 +713,7 @@
continue;
Paths.clear();
- if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
+ if (!IsDerivedFrom(SubLoc, CanonicalSubT, CanonicalSuperT, Paths))
continue;
if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
@@ -1179,6 +1179,7 @@
return CT_Cannot;
case Expr::MSPropertyRefExprClass:
+ case Expr::MSPropertySubscriptExprClass:
llvm_unreachable("Invalid class for expression");
#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a1e2c01..d8dd0ba 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -327,18 +327,16 @@
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
- SuppressedDiagnosticsMap::iterator
- Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
+ auto Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
if (Pos != SuppressedDiagnostics.end()) {
- SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second;
- for (unsigned I = 0, N = Suppressed.size(); I != N; ++I)
- Diag(Suppressed[I].first, Suppressed[I].second);
+ for (const PartialDiagnosticAt &Suppressed : Pos->second)
+ Diag(Suppressed.first, Suppressed.second);
// Clear out the list of suppressed diagnostics, so that we don't emit
// them again for this specialization. However, we don't obsolete this
// entry from the table, because we want to avoid ever emitting these
// diagnostics again.
- Suppressed.clear();
+ Pos->second.clear();
}
// C++ [basic.start.main]p3:
@@ -349,8 +347,10 @@
// See if this is an auto-typed variable whose initializer we are parsing.
if (ParsingInitForAutoVars.count(D)) {
+ const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType();
+
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
- << D->getDeclName();
+ << D->getDeclName() << (unsigned)AT->getKeyword();
return true;
}
@@ -465,7 +465,7 @@
// 'nil' for ObjC methods, where it's much more likely that the
// variadic arguments form a list of object pointers.
SourceLocation MissingNilLoc
- = PP.getLocForEndOfToken(sentinelExpr->getLocEnd());
+ = getLocForEndOfToken(sentinelExpr->getLocEnd());
std::string NullValue;
if (calleeType == CT_Method && PP.isMacroDefined("nil"))
NullValue = "nil";
@@ -494,7 +494,7 @@
//===----------------------------------------------------------------------===//
/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
-ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
+ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
// Handle any placeholder expressions which made it here.
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
@@ -509,9 +509,16 @@
// If we are here, we are not calling a function but taking
// its address (which is not allowed in OpenCL v1.0 s6.8.a.3).
if (getLangOpts().OpenCL) {
- Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
+ if (Diagnose)
+ Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
return ExprError();
}
+
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
+ if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc()))
+ return ExprError();
+
E = ImpCastExprToType(E, Context.getPointerType(Ty),
CK_FunctionToPointerDecay).get();
} else if (Ty->isArrayType()) {
@@ -580,7 +587,7 @@
&S.Context.Idents.get("object_setClass"),
SourceLocation(), S.LookupOrdinaryName);
if (ObjectSetClass) {
- SourceLocation RHSLocEnd = S.PP.getLocForEndOfToken(RHS->getLocEnd());
+ SourceLocation RHSLocEnd = S.getLocForEndOfToken(RHS->getLocEnd());
S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) <<
FixItHint::CreateInsertion(OIRE->getLocStart(), "object_setClass(") <<
FixItHint::CreateReplacement(SourceRange(OIRE->getOpLoc(),
@@ -677,9 +684,10 @@
if (T.hasQualifiers())
T = T.getUnqualifiedType();
+ // Under the MS ABI, lock down the inheritance model now.
if (T->isMemberPointerType() &&
Context.getTargetInfo().getCXXABI().isMicrosoft())
- RequireCompleteType(E->getExprLoc(), T, 0);
+ (void)isCompleteType(E->getExprLoc(), T);
UpdateMarkingForLValueToRValue(E);
@@ -704,8 +712,8 @@
return Res;
}
-ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
- ExprResult Res = DefaultFunctionArrayConversion(E);
+ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose) {
+ ExprResult Res = DefaultFunctionArrayConversion(E, Diagnose);
if (Res.isInvalid())
return ExprError();
Res = DefaultLvalueConversion(Res.get());
@@ -1452,12 +1460,11 @@
Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
<< ControllingExpr->getSourceRange() << ControllingExpr->getType()
<< (unsigned) CompatIndices.size();
- for (SmallVectorImpl<unsigned>::iterator I = CompatIndices.begin(),
- E = CompatIndices.end(); I != E; ++I) {
- Diag(Types[*I]->getTypeLoc().getBeginLoc(),
+ for (unsigned I : CompatIndices) {
+ Diag(Types[I]->getTypeLoc().getBeginLoc(),
diag::note_compat_assoc)
- << Types[*I]->getTypeLoc().getSourceRange()
- << Types[*I]->getType();
+ << Types[I]->getTypeLoc().getSourceRange()
+ << Types[I]->getType();
}
return ExprError();
}
@@ -1540,8 +1547,8 @@
return ExprError();
SmallVector<SourceLocation, 4> StringTokLocs;
- for (unsigned i = 0; i != StringToks.size(); ++i)
- StringTokLocs.push_back(StringToks[i].getLocation());
+ for (const Token &Tok : StringToks)
+ StringTokLocs.push_back(Tok.getLocation());
QualType CharTy = Context.CharTy;
StringLiteral::StringKind Kind = StringLiteral::Ascii;
@@ -1769,10 +1776,9 @@
std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts());
bool DroppedSpecifier =
TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr;
- unsigned NoteID =
- (TC.getCorrectionDecl() && isa<ImplicitParamDecl>(TC.getCorrectionDecl()))
- ? diag::note_implicit_param_decl
- : diag::note_previous_decl;
+ unsigned NoteID = TC.getCorrectionDeclAs<ImplicitParamDecl>()
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
if (!Ctx)
SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo,
SemaRef.PDiag(NoteID));
@@ -1840,8 +1846,8 @@
}
// Do we really want to note all of these?
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- Diag((*I)->getLocation(), diag::note_dependent_var_use);
+ for (NamedDecl *D : R)
+ Diag(D->getLocation(), diag::note_dependent_var_use);
// Return true if we are inside a default argument instantiation
// and the found name refers to an instance member function, otherwise
@@ -1896,28 +1902,26 @@
bool AcceptableWithRecovery = false;
bool AcceptableWithoutRecovery = false;
- NamedDecl *ND = Corrected.getCorrectionDecl();
+ NamedDecl *ND = Corrected.getFoundDecl();
if (ND) {
if (Corrected.isOverloaded()) {
OverloadCandidateSet OCS(R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
- for (TypoCorrection::decl_iterator CD = Corrected.begin(),
- CDEnd = Corrected.end();
- CD != CDEnd; ++CD) {
+ for (NamedDecl *CD : Corrected) {
if (FunctionTemplateDecl *FTD =
- dyn_cast<FunctionTemplateDecl>(*CD))
+ dyn_cast<FunctionTemplateDecl>(CD))
AddTemplateOverloadCandidate(
FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs,
Args, OCS);
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(CD))
if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0)
AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none),
Args, OCS);
}
switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
case OR_Success:
- ND = Best->Function;
+ ND = Best->FoundDecl;
Corrected.setCorrectionDecl(ND);
break;
default:
@@ -1939,15 +1943,16 @@
R.setNamingClass(Record);
}
- AcceptableWithRecovery =
- isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND);
+ auto *UnderlyingND = ND->getUnderlyingDecl();
+ AcceptableWithRecovery = isa<ValueDecl>(UnderlyingND) ||
+ isa<FunctionTemplateDecl>(UnderlyingND);
// FIXME: If we ended up with a typo for a type name or
// Objective-C class name, we're in trouble because the parser
// is in the wrong place to recover. Suggest the typo
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
AcceptableWithoutRecovery =
- isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
+ isa<TypeDecl>(UnderlyingND) || isa<ObjCInterfaceDecl>(UnderlyingND);
} else {
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
@@ -1955,8 +1960,7 @@
}
if (AcceptableWithRecovery || AcceptableWithoutRecovery) {
- unsigned NoteID = (Corrected.getCorrectionDecl() &&
- isa<ImplicitParamDecl>(Corrected.getCorrectionDecl()))
+ unsigned NoteID = Corrected.getCorrectionDeclAs<ImplicitParamDecl>()
? diag::note_implicit_param_decl
: diag::note_previous_decl;
if (SS.isEmpty())
@@ -2586,7 +2590,7 @@
// In C++98, the qualifier type doesn't actually have to be a base
// type of the object type, in which case we just ignore it.
// Otherwise build the appropriate casts.
- if (IsDerivedFrom(FromRecordType, QRecordType)) {
+ if (IsDerivedFrom(FromLoc, FromRecordType, QRecordType)) {
CXXCastPath BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
FromLoc, FromRange, &BasePath))
@@ -2622,7 +2626,7 @@
// We only need to do this if the naming-class to declaring-class
// conversion is non-trivial.
if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) {
- assert(IsDerivedFrom(FromRecordType, URecordType));
+ assert(IsDerivedFrom(FromLoc, FromRecordType, URecordType));
CXXCastPath BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
FromLoc, FromRange, &BasePath))
@@ -2669,9 +2673,7 @@
// Turn off ADL when we find certain kinds of declarations during
// normal lookup:
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = *I;
-
+ for (NamedDecl *D : R) {
// C++0x [basic.lookup.argdep]p3:
// -- a declaration of a class member
// Since using decls preserve this property, we check this on the
@@ -3082,6 +3084,8 @@
Kind = CharacterLiteral::UTF16;
else if (Literal.isUTF32())
Kind = CharacterLiteral::UTF32;
+ else if (Literal.isUTF8())
+ Kind = CharacterLiteral::UTF8;
Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
Tok.getLocation());
@@ -3685,7 +3689,7 @@
return false;
if (E->getObjectKind() == OK_BitField) {
- S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield)
+ S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield)
<< 1 << E->getSourceRange();
return true;
}
@@ -3744,6 +3748,128 @@
return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep);
}
+static void captureVariablyModifiedType(ASTContext &Context, QualType T,
+ CapturingScopeInfo *CSI) {
+ assert(T->isVariablyModifiedType());
+ assert(CSI != nullptr);
+
+ // We're going to walk down into the type and look for VLA expressions.
+ do {
+ const Type *Ty = T.getTypePtr();
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ T = QualType();
+ break;
+ // These types are never variably-modified.
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Record:
+ case Type::Enum:
+ case Type::Elaborated:
+ case Type::TemplateSpecialization:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ case Type::Pipe:
+ llvm_unreachable("type class is never variably-modified!");
+ case Type::Adjusted:
+ T = cast<AdjustedType>(Ty)->getOriginalType();
+ break;
+ case Type::Decayed:
+ T = cast<DecayedType>(Ty)->getPointeeType();
+ break;
+ case Type::Pointer:
+ T = cast<PointerType>(Ty)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ T = cast<BlockPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ T = cast<ReferenceType>(Ty)->getPointeeType();
+ break;
+ case Type::MemberPointer:
+ T = cast<MemberPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // Losing element qualification here is fine.
+ T = cast<ArrayType>(Ty)->getElementType();
+ break;
+ case Type::VariableArray: {
+ // Losing element qualification here is fine.
+ const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
+
+ // Unknown size indication requires no size computation.
+ // Otherwise, evaluate and record it.
+ if (auto Size = VAT->getSizeExpr()) {
+ if (!CSI->isVLATypeCaptured(VAT)) {
+ RecordDecl *CapRecord = nullptr;
+ if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ CapRecord = LSI->Lambda;
+ } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
+ CapRecord = CRSI->TheRecordDecl;
+ }
+ if (CapRecord) {
+ auto ExprLoc = Size->getExprLoc();
+ auto SizeType = Context.getSizeType();
+ // Build the non-static data member.
+ auto Field =
+ FieldDecl::Create(Context, CapRecord, ExprLoc, ExprLoc,
+ /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
+ /*BW*/ nullptr, /*Mutable*/ false,
+ /*InitStyle*/ ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Field->setCapturedVLAType(VAT);
+ CapRecord->addDecl(Field);
+
+ CSI->addVLATypeCapture(ExprLoc, SizeType);
+ }
+ }
+ }
+ T = VAT->getElementType();
+ break;
+ }
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ T = cast<FunctionType>(Ty)->getReturnType();
+ break;
+ case Type::Paren:
+ case Type::TypeOf:
+ case Type::UnaryTransform:
+ case Type::Attributed:
+ case Type::SubstTemplateTypeParm:
+ case Type::PackExpansion:
+ // Keep walking after single level desugaring.
+ T = T.getSingleStepDesugaredType(Context);
+ break;
+ case Type::Typedef:
+ T = cast<TypedefType>(Ty)->desugar();
+ break;
+ case Type::Decltype:
+ T = cast<DecltypeType>(Ty)->desugar();
+ break;
+ case Type::Auto:
+ T = cast<AutoType>(Ty)->getDeducedType();
+ break;
+ case Type::TypeOfExpr:
+ T = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
+ break;
+ case Type::Atomic:
+ T = cast<AtomicType>(Ty)->getValueType();
+ break;
+ }
+ } while (!T.isNull() && T->isVariablyModifiedType());
+}
+
/// \brief Build a sizeof or alignof expression given a type operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
@@ -3759,6 +3885,30 @@
CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind))
return ExprError();
+ if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) {
+ if (auto *TT = T->getAs<TypedefType>()) {
+ for (auto I = FunctionScopes.rbegin(),
+ E = std::prev(FunctionScopes.rend());
+ I != E; ++I) {
+ auto *CSI = dyn_cast<CapturingScopeInfo>(*I);
+ if (CSI == nullptr)
+ break;
+ DeclContext *DC = nullptr;
+ if (auto *LSI = dyn_cast<LambdaScopeInfo>(CSI))
+ DC = LSI->CallOperator;
+ else if (auto *CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI))
+ DC = CRSI->TheCapturedDecl;
+ else if (auto *BSI = dyn_cast<BlockScopeInfo>(CSI))
+ DC = BSI->TheDecl;
+ if (DC) {
+ if (DC->containsDecl(TT->getDecl()))
+ break;
+ captureVariablyModifiedType(Context, T, CSI);
+ }
+ }
+ }
+ }
+
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
return new (Context) UnaryExprOrTypeTraitExpr(
ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
@@ -3787,7 +3937,7 @@
Diag(E->getExprLoc(), diag::err_openmp_default_simd_align_expr);
isInvalid = true;
} else if (E->refersToBitField()) { // C99 6.5.3.4p1.
- Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0;
isInvalid = true;
} else {
isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
@@ -3899,6 +4049,13 @@
return true;
}
+static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) {
+ auto *BaseNoParens = Base->IgnoreParens();
+ if (auto *MSProp = dyn_cast<MSPropertyRefExpr>(BaseNoParens))
+ return MSProp->getPropertyDecl()->getType()->isArrayType();
+ return isa<MSPropertySubscriptExpr>(BaseNoParens);
+}
+
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
Expr *idx, SourceLocation rbLoc) {
@@ -3919,10 +4076,15 @@
// operand might be an overloadable type, in which case the overload
// resolution for the operator overload should get the first crack
// at the overload.
+ bool IsMSPropertySubscript = false;
if (base->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(base);
- if (result.isInvalid()) return ExprError();
- base = result.get();
+ IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
+ if (!IsMSPropertySubscript) {
+ ExprResult result = CheckPlaceholderExpr(base);
+ if (result.isInvalid())
+ return ExprError();
+ base = result.get();
+ }
}
if (idx->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(idx);
@@ -3937,6 +4099,21 @@
VK_LValue, OK_Ordinary, rbLoc);
}
+ // MSDN, property (C++)
+ // https://msdn.microsoft.com/en-us/library/yhfk0thd(v=vs.120).aspx
+ // This attribute can also be used in the declaration of an empty array in a
+ // class or structure definition. For example:
+ // __declspec(property(get=GetX, put=PutX)) int x[];
+ // The above statement indicates that x[] can be used with one or more array
+ // indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b),
+ // and p->x[a][b] = i will be turned into p->PutX(a, b, i);
+ if (IsMSPropertySubscript) {
+ // Build MS property subscript expression if base is MS property reference
+ // or MS property subscript.
+ return new (Context) MSPropertySubscriptExpr(
+ base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc);
+ }
+
// Use C++ overloaded-operator rules if either operand has record
// type. The spec says to do this if either type is *overloadable*,
// but enum types can't declare subscript operators or conversion
@@ -4284,10 +4461,16 @@
if (Result.isInvalid())
return ExprError();
- Expr *Arg = Result.getAs<Expr>();
- CheckCompletedExpr(Arg, Param->getOuterLocStart());
- // Build the default argument expression.
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg);
+ Result = ActOnFinishFullExpr(Result.getAs<Expr>(),
+ Param->getOuterLocStart());
+ if (Result.isInvalid())
+ return ExprError();
+
+ // Remember the instantiated default argument.
+ Param->setDefaultArg(Result.getAs<Expr>());
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->DefaultArgumentInstantiated(Param);
+ }
}
// If the default expression creates temporaries, we need to
@@ -4372,29 +4555,27 @@
llvm::make_unique<FunctionCallCCC>(S, FuncName.getAsIdentifierInfo(),
Args.size(), ME),
Sema::CTK_ErrorRecovery)) {
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ if (NamedDecl *ND = Corrected.getFoundDecl()) {
if (Corrected.isOverloaded()) {
OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
- for (TypoCorrection::decl_iterator CD = Corrected.begin(),
- CDEnd = Corrected.end();
- CD != CDEnd; ++CD) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
+ for (NamedDecl *CD : Corrected) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(CD))
S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args,
OCS);
}
switch (OCS.BestViableFunction(S, NameLoc, Best)) {
case OR_Success:
- ND = Best->Function;
+ ND = Best->FoundDecl;
Corrected.setCorrectionDecl(ND);
break;
default:
break;
}
}
- if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
+ ND = ND->getUnderlyingDecl();
+ if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))
return Corrected;
- }
}
}
return TypoCorrection();
@@ -4530,7 +4711,7 @@
bool IsListInitialization) {
unsigned NumParams = Proto->getNumParams();
bool Invalid = false;
- unsigned ArgIx = 0;
+ size_t ArgIx = 0;
// Continue to check argument types (even if we have too few/many args).
for (unsigned i = FirstParam; i < NumParams; i++) {
QualType ProtoArgType = Proto->getParamType(i);
@@ -4600,26 +4781,25 @@
// return __unknown_anytype aren't *really* variadic.
if (Proto->getReturnType() == Context.UnknownAnyTy && FDecl &&
FDecl->isExternC()) {
- for (unsigned i = ArgIx, e = Args.size(); i != e; ++i) {
+ for (Expr *A : Args.slice(ArgIx)) {
QualType paramType; // ignored
- ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
+ ExprResult arg = checkUnknownAnyArg(CallLoc, A, paramType);
Invalid |= arg.isInvalid();
AllArgs.push_back(arg.get());
}
// Otherwise do argument promotion, (C99 6.5.2.2p7).
} else {
- for (unsigned i = ArgIx, e = Args.size(); i != e; ++i) {
- ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType,
- FDecl);
+ for (Expr *A : Args.slice(ArgIx)) {
+ ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl);
Invalid |= Arg.isInvalid();
AllArgs.push_back(Arg.get());
}
}
// Check for array bounds violations.
- for (unsigned i = ArgIx, e = Args.size(); i != e; ++i)
- CheckArrayAccess(Args[i]);
+ for (Expr *A : Args.slice(ArgIx))
+ CheckArrayAccess(A);
}
return Invalid;
}
@@ -4746,7 +4926,7 @@
}
/// If a builtin function has a pointer argument with no explicit address
-/// space, than it should be able to accept a pointer to any address
+/// space, then it should be able to accept a pointer to any address
/// space as input. In order to do this, we need to replace the
/// standard builtin declaration with one that uses the same address space
/// as the call.
@@ -4901,14 +5081,12 @@
// We aren't supposed to apply this logic for if there's an '&' involved.
if (!find.HasFormOfMemberPointer) {
OverloadExpr *ovl = find.Expression;
- if (isa<UnresolvedLookupExpr>(ovl)) {
- UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs,
- RParenLoc, ExecConfig);
- } else {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs,
- RParenLoc);
- }
+ RParenLoc, ExecConfig,
+ /*AllowTypoCorrection=*/true,
+ find.IsAddressOfOperand);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc);
}
}
@@ -4921,17 +5099,21 @@
Expr *NakedFn = Fn->IgnoreParens();
+ bool CallingNDeclIndirectly = false;
NamedDecl *NDecl = nullptr;
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
- if (UnOp->getOpcode() == UO_AddrOf)
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) {
+ if (UnOp->getOpcode() == UO_AddrOf) {
+ CallingNDeclIndirectly = true;
NakedFn = UnOp->getSubExpr()->IgnoreParens();
+ }
+ }
if (isa<DeclRefExpr>(NakedFn)) {
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(NDecl);
if (FDecl && FDecl->getBuiltinID()) {
- // Rewrite the function decl for this builtin by replacing paramaters
+ // Rewrite the function decl for this builtin by replacing parameters
// with no explicit address space with the address space of the arguments
// in ArgExprs.
if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) {
@@ -4946,6 +5128,11 @@
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
+ if (CallingNDeclIndirectly &&
+ !checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ Fn->getLocStart()))
+ return ExprError();
+
if (FD->hasAttr<EnableIfAttr>()) {
if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
Diag(Fn->getLocStart(),
@@ -5012,6 +5199,12 @@
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
+ // Functions with 'interrupt' attribute cannot be called directly.
+ if (FDecl && FDecl->hasAttr<AnyX86InterruptAttr>()) {
+ Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
+ return ExprError();
+ }
+
// Promote the function operand.
// We special-case function promotion here because we only allow promoting
// builtin functions to function pointers in the callee of a call.
@@ -5561,6 +5754,39 @@
return false;
}
+ExprResult Sema::prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr) {
+ QualType DestElemTy = VectorTy->castAs<VectorType>()->getElementType();
+
+ if (DestElemTy == SplattedExpr->getType())
+ return SplattedExpr;
+
+ assert(DestElemTy->isFloatingType() ||
+ DestElemTy->isIntegralOrEnumerationType());
+
+ CastKind CK;
+ if (VectorTy->isExtVectorType() && SplattedExpr->getType()->isBooleanType()) {
+ // OpenCL requires that we convert `true` boolean expressions to -1, but
+ // only when splatting vectors.
+ if (DestElemTy->isFloatingType()) {
+ // To avoid having to have a CK_BooleanToSignedFloating cast kind, we cast
+ // in two steps: boolean to signed integral, then to floating.
+ ExprResult CastExprRes = ImpCastExprToType(SplattedExpr, Context.IntTy,
+ CK_BooleanToSignedIntegral);
+ SplattedExpr = CastExprRes.get();
+ CK = CK_IntegralToFloating;
+ } else {
+ CK = CK_BooleanToSignedIntegral;
+ }
+ } else {
+ ExprResult CastExprRes = SplattedExpr;
+ CK = PrepareScalarCast(CastExprRes, DestElemTy);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ SplattedExpr = CastExprRes.get();
+ }
+ return ImpCastExprToType(SplattedExpr, DestElemTy, CK);
+}
+
ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
Expr *CastExpr, CastKind &Kind) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
@@ -5591,15 +5817,8 @@
diag::err_invalid_conversion_between_vector_and_scalar)
<< DestTy << SrcTy << R;
- QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
- ExprResult CastExprRes = CastExpr;
- CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = ImpCastExprToType(CastExprRes.get(), DestElemTy, CK).get();
-
Kind = CK_VectorSplat;
- return CastExpr;
+ return prepareVectorSplat(DestTy, CastExpr);
}
ExprResult
@@ -6474,7 +6693,7 @@
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &Note,
SourceRange ParenRange) {
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
+ SourceLocation EndLoc = Self.getLocForEndOfToken(ParenRange.getEnd());
if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() &&
EndLoc.isValid()) {
Self.Diag(Loc, Note)
@@ -6487,7 +6706,9 @@
}
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
- return Opc >= BO_Mul && Opc <= BO_Shr;
+ return BinaryOperator::isAdditiveOp(Opc) ||
+ BinaryOperator::isMultiplicativeOp(Opc) ||
+ BinaryOperator::isShiftOp(Opc);
}
/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
@@ -6533,10 +6754,6 @@
return false;
}
-static bool IsLogicOp(BinaryOperatorKind Opc) {
- return (Opc >= BO_LT && Opc <= BO_NE) || (Opc >= BO_LAnd && Opc <= BO_LOr);
-}
-
/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type
/// or is a logical expression such as (x==y) which has int type, but is
/// commonly interpreted as boolean.
@@ -6546,7 +6763,7 @@
if (E->getType()->isBooleanType())
return true;
if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E))
- return IsLogicOp(OP->getOpcode());
+ return OP->isComparisonOp() || OP->isLogicalOp();
if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E))
return OP->getOpcode() == UO_LNot;
if (E->getType()->isPointerType())
@@ -6940,13 +7157,9 @@
if (RHSType->isExtVectorType())
return Incompatible;
if (RHSType->isArithmeticType()) {
- // CK_VectorSplat does T -> vector T, so first cast to the
- // element type.
- QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
- if (elType != RHSType && ConvertRHS) {
- Kind = PrepareScalarCast(RHS, elType);
- RHS = ImpCastExprToType(RHS.get(), elType, Kind);
- }
+ // CK_VectorSplat does T -> vector T, so first cast to the element type.
+ if (ConvertRHS)
+ RHS = prepareVectorSplat(LHSType, RHS.get());
Kind = CK_VectorSplat;
return Compatible;
}
@@ -7293,11 +7506,14 @@
LHSType->isBlockPointerType()) &&
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- CastKind Kind;
- CXXCastPath Path;
- CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
- if (ConvertRHS)
- RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
+ if (Diagnose || ConvertRHS) {
+ CastKind Kind;
+ CXXCastPath Path;
+ CheckPointerConversion(RHS.get(), LHSType, Kind, Path,
+ /*IgnoreBaseAccess=*/false, Diagnose);
+ if (ConvertRHS)
+ RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
+ }
return Compatible;
}
@@ -7309,14 +7525,14 @@
// Suppress this for references: C++ 8.5.3p5.
if (!LHSType->isReferenceType()) {
// FIXME: We potentially allocate here even if ConvertRHS is false.
- RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
if (RHS.isInvalid())
return Incompatible;
}
Expr *PRE = RHS.get()->IgnoreParenCasts();
- if (ObjCProtocolExpr *OPE = dyn_cast<ObjCProtocolExpr>(PRE)) {
- ObjCProtocolDecl *PDecl = OPE->getProtocol();
+ if (Diagnose && isa<ObjCProtocolExpr>(PRE)) {
+ ObjCProtocolDecl *PDecl = cast<ObjCProtocolExpr>(PRE)->getProtocol();
if (PDecl && !PDecl->hasDefinition()) {
Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName();
Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
@@ -7338,11 +7554,11 @@
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
- DiagnoseCFAudited);
+ Diagnose, DiagnoseCFAudited);
if (getLangOpts().ObjC1 &&
- (CheckObjCBridgeRelatedConversions(E->getLocStart(),
- LHSType, E->getType(), E) ||
- ConversionToObjCStringLiteralCheck(LHSType, E))) {
+ (CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType,
+ E->getType(), E, Diagnose) ||
+ ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) {
RHS = E;
return Compatible;
}
@@ -7573,13 +7789,12 @@
ExprResult &RHS,
SourceLocation Loc, bool IsDiv) {
// Check for division/remainder by zero.
- unsigned Diag = (IsDiv) ? diag::warn_division_by_zero :
- diag::warn_remainder_by_zero;
llvm::APSInt RHSValue;
if (!RHS.get()->isValueDependent() &&
RHS.get()->EvaluateAsInt(RHSValue, S.Context) && RHSValue == 0)
S.DiagRuntimeBehavior(Loc, RHS.get(),
- S.PDiag(Diag) << RHS.get()->getSourceRange());
+ S.PDiag(diag::warn_remainder_division_by_zero)
+ << IsDiv << RHS.get()->getSourceRange());
}
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
@@ -7816,7 +8031,7 @@
// Only print a fixit for "str" + int, not for int + "str".
if (IndexExpr == RHSExpr) {
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
+ SourceLocation EndLoc = Self.getLocForEndOfToken(RHSExpr->getLocEnd());
Self.Diag(OpLoc, diag::note_string_plus_scalar_silence)
<< FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
<< FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
@@ -7866,7 +8081,7 @@
// Only print a fixit for str + char, not for char + str.
if (isa<CharacterLiteral>(RHSExpr->IgnoreImpCasts())) {
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
+ SourceLocation EndLoc = Self.getLocForEndOfToken(RHSExpr->getLocEnd());
Self.Diag(OpLoc, diag::note_string_plus_scalar_silence)
<< FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
<< FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
@@ -7886,9 +8101,10 @@
<< RHSExpr->getSourceRange();
}
-QualType Sema::CheckAdditionOperands( // C99 6.5.6
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
- QualType* CompLHSTy) {
+// C99 6.5.6
+QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc, BinaryOperatorKind Opc,
+ QualType* CompLHSTy) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
@@ -8064,7 +8280,7 @@
}
static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc, unsigned Opc,
+ SourceLocation Loc, BinaryOperatorKind Opc,
QualType LHSType) {
// OpenCL 6.3j: shift values are effectively % word size of LHS (more defined),
// so skip remaining warnings as we don't want to modify values within Sema.
@@ -8164,7 +8380,7 @@
if (RHS.isInvalid()) return QualType();
QualType LHSType = LHS.get()->getType();
- const VectorType *LHSVecTy = LHSType->getAs<VectorType>();
+ const VectorType *LHSVecTy = LHSType->castAs<VectorType>();
QualType LHSEleType = LHSVecTy->getElementType();
// Note that RHS might not be a vector.
@@ -8207,7 +8423,7 @@
// C99 6.5.7
QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc, unsigned Opc,
+ SourceLocation Loc, BinaryOperatorKind Opc,
bool IsCompAssign) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
@@ -8512,9 +8728,9 @@
if (BinaryOperator::isEqualityOp(Opc) &&
hasIsEqualMethod(S, LHS.get(), RHS.get())) {
SourceLocation Start = LHS.get()->getLocStart();
- SourceLocation End = S.PP.getLocForEndOfToken(RHS.get()->getLocEnd());
+ SourceLocation End = S.getLocForEndOfToken(RHS.get()->getLocEnd());
CharSourceRange OpRange =
- CharSourceRange::getCharRange(Loc, S.PP.getLocForEndOfToken(Loc));
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
S.Diag(Loc, diag::note_objc_literal_comparison_isequal)
<< FixItHint::CreateInsertion(Start, Opc == BO_EQ ? "[" : "![")
@@ -8526,7 +8742,7 @@
static void diagnoseLogicalNotOnLHSofComparison(Sema &S, ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc,
- unsigned OpaqueOpc) {
+ BinaryOperatorKind Opc) {
// Check that left hand side is !something.
UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS.get()->IgnoreImpCasts());
if (!UO || UO->getOpcode() != UO_LNot) return;
@@ -8545,7 +8761,7 @@
// First note suggest !(x < y)
SourceLocation FirstOpen = SubExpr->getLocStart();
SourceLocation FirstClose = RHS.get()->getLocEnd();
- FirstClose = S.getPreprocessor().getLocForEndOfToken(FirstClose);
+ FirstClose = S.getLocForEndOfToken(FirstClose);
if (FirstClose.isInvalid())
FirstOpen = SourceLocation();
S.Diag(UO->getOperatorLoc(), diag::note_logical_not_fix)
@@ -8555,7 +8771,7 @@
// Second note suggests (!x) < y
SourceLocation SecondOpen = LHS.get()->getLocStart();
SourceLocation SecondClose = LHS.get()->getLocEnd();
- SecondClose = S.getPreprocessor().getLocForEndOfToken(SecondClose);
+ SecondClose = S.getLocForEndOfToken(SecondClose);
if (SecondClose.isInvalid())
SecondOpen = SourceLocation();
S.Diag(UO->getOperatorLoc(), diag::note_logical_not_silence_with_parens)
@@ -8581,12 +8797,10 @@
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc, unsigned OpaqueOpc,
+ SourceLocation Loc, BinaryOperatorKind Opc,
bool IsRelational) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
- BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc;
-
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
@@ -8599,7 +8813,7 @@
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
- diagnoseLogicalNotOnLHSofComparison(*this, LHS, RHS, Loc, OpaqueOpc);
+ diagnoseLogicalNotOnLHSofComparison(*this, LHS, RHS, Loc, Opc);
if (!LHSType->hasFloatingRepresentation() &&
!(LHSType->isBlockPointerType() && IsRelational) &&
@@ -8772,7 +8986,8 @@
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
}
if (LCanPointeeTy != RCanPointeeTy) {
- if (getLangOpts().OpenCL) {
+ // Treat NULL constant as a special case in OpenCL.
+ if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
const PointerType *LHSPtr = LHSType->getAs<PointerType>();
if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
Diag(Loc,
@@ -8901,8 +9116,9 @@
else {
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, false,
- Opc);
+ CheckObjCARCConversion(SourceRange(), LHSType, E,
+ CCK_ImplicitConversion, /*Diagnose=*/true,
+ /*DiagnoseCFAudited=*/false, Opc);
RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
@@ -9087,9 +9303,10 @@
return InvalidOperands(Loc, LHS, RHS);
}
-inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) {
-
+// C99 6.5.[13,14]
+inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ BinaryOperatorKind Opc) {
// Check vector operands differently.
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
@@ -9118,18 +9335,14 @@
Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator)
<< (Opc == BO_LAnd ? "&" : "|")
<< FixItHint::CreateReplacement(SourceRange(
- Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(),
- getLangOpts())),
+ Loc, getLocForEndOfToken(Loc)),
Opc == BO_LAnd ? "&" : "|");
if (Opc == BO_LAnd)
// Suggest replacing "Foo() && kNonZero" with "Foo()"
Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant)
<< FixItHint::CreateRemoval(
- SourceRange(
- Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(),
- 0, getSourceManager(),
- getLangOpts()),
- RHS.get()->getLocEnd()));
+ SourceRange(getLocForEndOfToken(LHS.get()->getLocEnd()),
+ RHS.get()->getLocEnd()));
}
}
@@ -9656,7 +9869,9 @@
return QualType();
}
// Increment of bool sets it to true, but is deprecated.
- S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
+ S.Diag(OpLoc, S.getLangOpts().CPlusPlus1z ? diag::ext_increment_bool
+ : diag::warn_increment_bool)
+ << Op->getSourceRange();
} else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) {
// Error on enum increments and decrements in C++ mode
S.Diag(OpLoc, diag::err_increment_decrement_enum) << IsInc << ResType;
@@ -9856,6 +10071,12 @@
// expressions here, but the result of one is always an lvalue anyway.
}
ValueDecl *dcl = getPrimaryDecl(op);
+
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(dcl))
+ if (!checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ op->getLocStart()))
+ return QualType();
+
Expr::LValueClassification lval = op->ClassifyLValue(Context);
unsigned AddressOfError = AO_No_Error;
@@ -9909,8 +10130,9 @@
QualType MPTy = Context.getMemberPointerType(
op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr());
+ // Under the MS ABI, lock down the inheritance model now.
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
- RequireCompleteType(OpLoc, MPTy, 0);
+ (void)isCompleteType(OpLoc, MPTy);
return MPTy;
} else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
@@ -9965,8 +10187,9 @@
QualType MPTy = Context.getMemberPointerType(
op->getType(),
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ // Under the MS ABI, lock down the inheritance model now.
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
- RequireCompleteType(OpLoc, MPTy, 0);
+ (void)isCompleteType(OpLoc, MPTy);
return MPTy;
}
}
@@ -10371,7 +10594,7 @@
break;
case BO_AndAssign:
case BO_OrAssign: // fallthrough
- DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
@@ -10398,7 +10621,7 @@
&Context.Idents.get("object_setClass"),
SourceLocation(), LookupOrdinaryName);
if (ObjectSetClass && isa<ObjCIsaExpr>(LHS.get())) {
- SourceLocation RHSLocEnd = PP.getLocForEndOfToken(RHS.get()->getLocEnd());
+ SourceLocation RHSLocEnd = getLocForEndOfToken(RHS.get()->getLocEnd());
Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) <<
FixItHint::CreateInsertion(LHS.get()->getLocStart(), "object_setClass(") <<
FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") <<
@@ -10434,17 +10657,17 @@
BinaryOperator *LHSBO = dyn_cast<BinaryOperator>(LHSExpr);
BinaryOperator *RHSBO = dyn_cast<BinaryOperator>(RHSExpr);
- // Check that one of the sides is a comparison operator.
+ // Check that one of the sides is a comparison operator and the other isn't.
bool isLeftComp = LHSBO && LHSBO->isComparisonOp();
bool isRightComp = RHSBO && RHSBO->isComparisonOp();
- if (!isLeftComp && !isRightComp)
+ if (isLeftComp == isRightComp)
return;
// Bitwise operations are sometimes used as eager logical ops.
// Don't diagnose this.
bool isLeftBitwise = LHSBO && LHSBO->isBitwiseOp();
bool isRightBitwise = RHSBO && RHSBO->isBitwiseOp();
- if ((isLeftComp || isLeftBitwise) && (isRightComp || isRightBitwise))
+ if (isLeftBitwise || isRightBitwise)
return;
SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(),
@@ -10466,21 +10689,6 @@
ParensRange);
}
-/// \brief It accepts a '&' expr that is inside a '|' one.
-/// Emit a diagnostic together with a fixit hint that wraps the '&' expression
-/// in parentheses.
-static void
-EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
- BinaryOperator *Bop) {
- assert(Bop->getOpcode() == BO_And);
- Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
- << Bop->getSourceRange() << OpLoc;
- SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::note_precedence_silence)
- << Bop->getOpcodeStr(),
- Bop->getSourceRange());
-}
-
/// \brief It accepts a '&&' expr that is inside a '||' one.
/// Emit a diagnostic together with a fixit hint that wraps the '&&' expression
/// in parentheses.
@@ -10549,12 +10757,21 @@
}
}
-/// \brief Look for '&' in the left or right hand of a '|' expr.
-static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
- Expr *OrArg) {
- if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrArg)) {
- if (Bop->getOpcode() == BO_And)
- return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop);
+/// \brief Look for bitwise op in the left or right hand of a bitwise op with
+/// lower precedence and emit a diagnostic together with a fixit hint that wraps
+/// the '&' expression in parentheses.
+static void DiagnoseBitwiseOpInBitwiseOp(Sema &S, BinaryOperatorKind Opc,
+ SourceLocation OpLoc, Expr *SubExpr) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(SubExpr)) {
+ if (Bop->isBitwiseOp() && Bop->getOpcode() < Opc) {
+ S.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_op_in_bitwise_op)
+ << Bop->getOpcodeStr() << BinaryOperator::getOpcodeStr(Opc)
+ << Bop->getSourceRange() << OpLoc;
+ SuggestParentheses(S, Bop->getOperatorLoc(),
+ S.PDiag(diag::note_precedence_silence)
+ << Bop->getOpcodeStr(),
+ Bop->getSourceRange());
+ }
}
}
@@ -10609,9 +10826,10 @@
DiagnoseBitwisePrecedence(Self, Opc, OpLoc, LHSExpr, RHSExpr);
// Diagnose "arg1 & arg2 | arg3"
- if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) {
- DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, LHSExpr);
- DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, RHSExpr);
+ if ((Opc == BO_Or || Opc == BO_Xor) &&
+ !OpLoc.isMacroID()/* Don't warn in macros. */) {
+ DiagnoseBitwiseOpInBitwiseOp(Self, Opc, OpLoc, LHSExpr);
+ DiagnoseBitwiseOpInBitwiseOp(Self, Opc, OpLoc, RHSExpr);
}
// Warn about arg1 || arg2 && arg3, as GCC 4.3+ does.
@@ -10947,10 +11165,8 @@
if (!ULE->getQualifier())
return false;
- for (UnresolvedLookupExpr::decls_iterator D = ULE->decls_begin(),
- DEnd = ULE->decls_end();
- D != DEnd; ++D) {
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*D)) {
+ for (NamedDecl *D : ULE->decls()) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isInstance())
return true;
} else {
@@ -11170,7 +11386,6 @@
bool DidWarnAboutNonPOD = false;
QualType CurrentType = ArgTy;
- typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
SmallVector<OffsetOfNode, 4> Comps;
SmallVector<Expr*, 4> Exprs;
for (const OffsetOfComponent &OC : Components) {
@@ -11280,7 +11495,8 @@
// If the member was found in a base class, introduce OffsetOfNodes for
// the base class indirections.
CXXBasePaths Paths;
- if (IsDerivedFrom(CurrentType, Context.getTypeDeclType(Parent), Paths)) {
+ if (IsDerivedFrom(OC.LocStart, CurrentType, Context.getTypeDeclType(Parent),
+ Paths)) {
if (Paths.getDetectedVirtual()) {
Diag(OC.LocEnd, diag::err_offsetof_field_of_virtual_base)
<< MemberDecl->getDeclName()
@@ -11289,9 +11505,8 @@
}
CXXBasePath &Path = Paths.front();
- for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end();
- B != BEnd; ++B)
- Comps.push_back(OffsetOfNode(B->Base));
+ for (const CXXBasePathElement &B : Path)
+ Comps.push_back(OffsetOfNode(B.Base));
}
if (IndirectMemberDecl) {
@@ -11559,8 +11774,7 @@
// Set the captured variables on the block.
// FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
SmallVector<BlockDecl::Capture, 4> Captures;
- for (unsigned i = 0, e = BSI->Captures.size(); i != e; i++) {
- CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
+ for (CapturingScopeInfo::Capture &Cap : BSI->Captures) {
if (Cap.isThisCapture())
continue;
BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
@@ -11772,8 +11986,8 @@
return new (Context) GNUNullExpr(Ty, TokenLoc);
}
-bool
-Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) {
+bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
+ bool Diagnose) {
if (!getLangOpts().ObjC1)
return false;
@@ -11799,12 +12013,32 @@
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
if (!SL || !SL->isAscii())
return false;
- Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
- << FixItHint::CreateInsertion(SL->getLocStart(), "@");
+ if (Diagnose)
+ Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
+ << FixItHint::CreateInsertion(SL->getLocStart(), "@");
Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get();
return true;
}
+static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType,
+ const Expr *SrcExpr) {
+ if (!DstType->isFunctionPointerType() ||
+ !SrcExpr->getType()->isFunctionType())
+ return false;
+
+ auto *DRE = dyn_cast<DeclRefExpr>(SrcExpr->IgnoreParenImpCasts());
+ if (!DRE)
+ return false;
+
+ auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
+ if (!FD)
+ return false;
+
+ return !S.checkAddressOfFunctionIsAvailable(FD,
+ /*Complain=*/true,
+ SrcExpr->getLocStart());
+}
+
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
@@ -11937,6 +12171,12 @@
DiagKind = diag::err_arc_weak_unavailable_assign;
break;
case Incompatible:
+ if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) {
+ if (Complained)
+ *Complained = true;
+ return true;
+ }
+
DiagKind = diag::err_typecheck_convert_incompatible;
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
@@ -11975,9 +12215,8 @@
// If we can fix the conversion, suggest the FixIts.
assert(ConvHints.isNull() || Hint.isNull());
if (!ConvHints.isNull()) {
- for (std::vector<FixItHint>::iterator HI = ConvHints.Hints.begin(),
- HE = ConvHints.Hints.end(); HI != HE; ++HI)
- FDiag << *HI;
+ for (FixItHint &H : ConvHints.Hints)
+ FDiag << H;
} else {
FDiag << Hint;
}
@@ -12152,16 +12391,16 @@
if (!Folded || !AllowFold) {
if (!Diagnoser.Suppress) {
Diagnoser.diagnoseNotICE(*this, DiagLoc, E->getSourceRange());
- for (unsigned I = 0, N = Notes.size(); I != N; ++I)
- Diag(Notes[I].first, Notes[I].second);
+ for (const PartialDiagnosticAt &Note : Notes)
+ Diag(Note.first, Note.second);
}
return ExprError();
}
Diagnoser.diagnoseFold(*this, DiagLoc, E->getSourceRange());
- for (unsigned I = 0, N = Notes.size(); I != N; ++I)
- Diag(Notes[I].first, Notes[I].second);
+ for (const PartialDiagnosticAt &Note : Notes)
+ Diag(Note.first, Note.second);
if (Result)
*Result = EvalResult.Val.getInt();
@@ -12595,10 +12834,15 @@
// Compute the type of an expression that refers to this variable.
DeclRefType = CaptureType.getNonReferenceType();
-
+
+ // Similarly to mutable captures in lambda, all the OpenMP captures by copy
+ // are mutable in the sense that user can change their value - they are
+ // private instances of the captured declarations.
const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
if (Cap.isCopyCapture() &&
- !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable))
+ !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable) &&
+ !(isa<CapturedRegionScopeInfo>(CSI) &&
+ cast<CapturedRegionScopeInfo>(CSI)->CapRegionKind == CR_OpenMP))
DeclRefType.addConst();
return true;
}
@@ -12786,9 +13030,17 @@
// By default, capture variables by reference.
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
- if (S.getLangOpts().OpenMP && S.IsOpenMPCapturedVar(Var))
- DeclRefType = DeclRefType.getUnqualifiedType();
- CaptureType = S.Context.getLValueReferenceType(DeclRefType);
+ if (S.getLangOpts().OpenMP) {
+ ByRef = S.IsOpenMPCapturedByRef(Var, RSI);
+ if (S.IsOpenMPCapturedVar(Var))
+ DeclRefType = DeclRefType.getUnqualifiedType();
+ }
+
+ if (ByRef)
+ CaptureType = S.Context.getLValueReferenceType(DeclRefType);
+ else
+ CaptureType = DeclRefType;
+
Expr *CopyExpr = nullptr;
if (BuildAndDiagnose) {
// The current implementation assumes that all variables are captured
@@ -13044,119 +13296,7 @@
QualType QTy = Var->getType();
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
QTy = PVD->getOriginalType();
- do {
- const Type *Ty = QTy.getTypePtr();
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- QTy = QualType();
- break;
- // These types are never variably-modified.
- case Type::Builtin:
- case Type::Complex:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Record:
- case Type::Enum:
- case Type::Elaborated:
- case Type::TemplateSpecialization:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::ObjCObjectPointer:
- llvm_unreachable("type class is never variably-modified!");
- case Type::Adjusted:
- QTy = cast<AdjustedType>(Ty)->getOriginalType();
- break;
- case Type::Decayed:
- QTy = cast<DecayedType>(Ty)->getPointeeType();
- break;
- case Type::Pointer:
- QTy = cast<PointerType>(Ty)->getPointeeType();
- break;
- case Type::BlockPointer:
- QTy = cast<BlockPointerType>(Ty)->getPointeeType();
- break;
- case Type::LValueReference:
- case Type::RValueReference:
- QTy = cast<ReferenceType>(Ty)->getPointeeType();
- break;
- case Type::MemberPointer:
- QTy = cast<MemberPointerType>(Ty)->getPointeeType();
- break;
- case Type::ConstantArray:
- case Type::IncompleteArray:
- // Losing element qualification here is fine.
- QTy = cast<ArrayType>(Ty)->getElementType();
- break;
- case Type::VariableArray: {
- // Losing element qualification here is fine.
- const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
-
- // Unknown size indication requires no size computation.
- // Otherwise, evaluate and record it.
- if (auto Size = VAT->getSizeExpr()) {
- if (!CSI->isVLATypeCaptured(VAT)) {
- RecordDecl *CapRecord = nullptr;
- if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
- CapRecord = LSI->Lambda;
- } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- CapRecord = CRSI->TheRecordDecl;
- }
- if (CapRecord) {
- auto ExprLoc = Size->getExprLoc();
- auto SizeType = Context.getSizeType();
- // Build the non-static data member.
- auto Field = FieldDecl::Create(
- Context, CapRecord, ExprLoc, ExprLoc,
- /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
- /*BW*/ nullptr, /*Mutable*/ false,
- /*InitStyle*/ ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- Field->setCapturedVLAType(VAT);
- CapRecord->addDecl(Field);
-
- CSI->addVLATypeCapture(ExprLoc, SizeType);
- }
- }
- }
- QTy = VAT->getElementType();
- break;
- }
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- QTy = cast<FunctionType>(Ty)->getReturnType();
- break;
- case Type::Paren:
- case Type::TypeOf:
- case Type::UnaryTransform:
- case Type::Attributed:
- case Type::SubstTemplateTypeParm:
- case Type::PackExpansion:
- // Keep walking after single level desugaring.
- QTy = QTy.getSingleStepDesugaredType(getASTContext());
- break;
- case Type::Typedef:
- QTy = cast<TypedefType>(Ty)->desugar();
- break;
- case Type::Decltype:
- QTy = cast<DecltypeType>(Ty)->desugar();
- break;
- case Type::Auto:
- QTy = cast<AutoType>(Ty)->getDeducedType();
- break;
- case Type::TypeOfExpr:
- QTy = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
- break;
- case Type::Atomic:
- QTy = cast<AtomicType>(Ty)->getValueType();
- break;
- }
- } while (!QTy.isNull() && QTy->isVariablyModifiedType());
+ captureVariablyModifiedType(Context, QTy, CSI);
}
if (getLangOpts().OpenMP) {
@@ -13338,15 +13478,13 @@
}
void Sema::CleanupVarDeclMarking() {
- for (llvm::SmallPtrSetIterator<Expr*> i = MaybeODRUseExprs.begin(),
- e = MaybeODRUseExprs.end();
- i != e; ++i) {
+ for (Expr *E : MaybeODRUseExprs) {
VarDecl *Var;
SourceLocation Loc;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*i)) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
Var = cast<VarDecl>(DRE->getDecl());
Loc = DRE->getLocation();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(*i)) {
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
Var = cast<VarDecl>(ME->getMemberDecl());
Loc = ME->getMemberLoc();
} else {
@@ -13403,7 +13541,7 @@
}
if (!isTemplateInstantiation(TSK))
- return;
+ return;
// Instantiate, but do not mark as odr-used, variable templates.
MarkODRUsed = false;
@@ -13820,7 +13958,7 @@
Diag(Loc, diagnostic) << E->getSourceRange();
SourceLocation Open = E->getLocStart();
- SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
+ SourceLocation Close = getLocForEndOfToken(E->getSourceRange().getEnd());
Diag(Loc, diag::note_condition_assign_silence)
<< FixItHint::CreateInsertion(Open, "(")
<< FixItHint::CreateInsertion(Close, ")");
@@ -14332,6 +14470,12 @@
ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
Expr *CastExpr, CastKind &CastKind,
ExprValueKind &VK, CXXCastPath &Path) {
+ // The type we're casting to must be either void or complete.
+ if (!CastType->isVoidType() &&
+ RequireCompleteType(TypeRange.getBegin(), CastType,
+ diag::err_typecheck_cast_to_incomplete))
+ return ExprError();
+
// Rewrite the casted expression from scratch.
ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr);
if (!result.isUsable()) return ExprError();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index dfaa450..32aa5a6 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -113,7 +113,7 @@
bool LookInScope = false;
if (SS.isInvalid())
- return ParsedType();
+ return nullptr;
// If we have an object type, it's because we are in a
// pseudo-destructor-expression or a member access expression, and
@@ -198,7 +198,7 @@
// FIXME: Should we be suppressing ambiguities here?
if (Found.isAmbiguous())
- return ParsedType();
+ return nullptr;
if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
QualType T = Context.getTypeDeclType(Type);
@@ -320,12 +320,12 @@
}
}
- return ParsedType();
+ return nullptr;
}
ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType)
- return ParsedType();
+ return nullptr;
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype
&& "only get destructor types from declspecs");
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
@@ -336,7 +336,7 @@
Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch)
<< T << SearchType;
- return ParsedType();
+ return nullptr;
}
bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
@@ -2717,6 +2717,8 @@
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex.get()->getSourceRange());
} else if (!Pointee->isDependentType()) {
+ // FIXME: This can result in errors if the definition was imported from a
+ // module but is hidden.
if (!RequireCompleteType(StartLoc, Pointee,
diag::warn_delete_incomplete, Ex.get())) {
if (const RecordType *RT = PointeeElem->getAs<RecordType>())
@@ -2727,7 +2729,7 @@
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
<< Type << Ex.get()->getSourceRange()
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]");
+ << FixItHint::CreateInsertion(getLocForEndOfToken(StartLoc), "[]");
ArrayForm = true;
}
@@ -2763,36 +2765,16 @@
return ExprError();
}
- // C++ [expr.delete]p3:
- // In the first alternative (delete object), if the static type of the
- // object to be deleted is different from its dynamic type, the static
- // type shall be a base class of the dynamic type of the object to be
- // deleted and the static type shall have a virtual destructor or the
- // behavior is undefined.
- //
- // Note: a final class cannot be derived from, no issue there
- if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) {
- CXXDestructorDecl *dtor = PointeeRD->getDestructor();
- if (dtor && !dtor->isVirtual()) {
- if (PointeeRD->isAbstract()) {
- // If the class is abstract, we warn by default, because we're
- // sure the code has undefined behavior.
- Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor)
- << PointeeElem;
- } else if (!ArrayForm) {
- // Otherwise, if this is not an array delete, it's a bit suspect,
- // but not necessarily wrong.
- Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
- }
- }
- }
-
+ CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc,
+ /*IsDelete=*/true, /*CallCanBeVirtual=*/true,
+ /*WarnOnNonAbstractTypes=*/!ArrayForm,
+ SourceLocation());
}
if (!OperatorDelete)
// Look for a global declaration.
OperatorDelete = FindUsualDeallocationFunction(
- StartLoc, !RequireCompleteType(StartLoc, Pointee, 0) &&
+ StartLoc, isCompleteType(StartLoc, Pointee) &&
(!ArrayForm || UsualArrayDeleteWantsSize ||
Pointee.isDestructedType()),
DeleteName);
@@ -2815,6 +2797,45 @@
return Result;
}
+void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
+ bool IsDelete, bool CallCanBeVirtual,
+ bool WarnOnNonAbstractTypes,
+ SourceLocation DtorLoc) {
+ if (!dtor || dtor->isVirtual() || !CallCanBeVirtual)
+ return;
+
+ // C++ [expr.delete]p3:
+ // In the first alternative (delete object), if the static type of the
+ // object to be deleted is different from its dynamic type, the static
+ // type shall be a base class of the dynamic type of the object to be
+ // deleted and the static type shall have a virtual destructor or the
+ // behavior is undefined.
+ //
+ const CXXRecordDecl *PointeeRD = dtor->getParent();
+ // Note: a final class cannot be derived from, no issue there
+ if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>())
+ return;
+
+ QualType ClassType = dtor->getThisType(Context)->getPointeeType();
+ if (PointeeRD->isAbstract()) {
+ // If the class is abstract, we warn by default, because we're
+ // sure the code has undefined behavior.
+ Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1)
+ << ClassType;
+ } else if (WarnOnNonAbstractTypes) {
+ // Otherwise, if this is not an array delete, it's a bit suspect,
+ // but not necessarily wrong.
+ Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1)
+ << ClassType;
+ }
+ if (!IsDelete) {
+ std::string TypeStr;
+ ClassType.getAsStringInternal(TypeStr, getPrintingPolicy());
+ Diag(DtorLoc, diag::note_delete_non_virtual)
+ << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::");
+ }
+}
+
/// \brief Check the use of the given variable as a C++ condition in an if,
/// while, do-while, or switch statement.
ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
@@ -3118,6 +3139,7 @@
ToType = ToAtomic->getValueType();
}
+ QualType InitialFromType = FromType;
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -3308,8 +3330,8 @@
// We may not have been able to figure out what this member pointer resolved
// to up until this exact point. Attempt to lock-in it's inheritance model.
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- RequireCompleteType(From->getExprLoc(), From->getType(), 0);
- RequireCompleteType(From->getExprLoc(), ToType, 0);
+ (void)isCompleteType(From->getExprLoc(), From->getType());
+ (void)isCompleteType(From->getExprLoc(), ToType);
}
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
@@ -3350,20 +3372,13 @@
VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
- case ICK_Vector_Splat:
+ case ICK_Vector_Splat: {
// Vector splat from any arithmetic type to a vector.
- // Cast to the element type.
- {
- QualType elType = ToType->getAs<ExtVectorType>()->getElementType();
- if (elType != From->getType()) {
- ExprResult E = From;
- From = ImpCastExprToType(From, elType,
- PrepareScalarCast(E, elType)).get();
- }
- From = ImpCastExprToType(From, ToType, CK_VectorSplat,
- VK_RValue, /*BasePath=*/nullptr, CCK).get();
- }
+ Expr *Elem = prepareVectorSplat(ToType, From).get();
+ From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue,
+ /*BasePath=*/nullptr, CCK).get();
break;
+ }
case ICK_Complex_Real:
// Case 1. x -> _Complex y
@@ -3488,6 +3503,12 @@
VK_RValue, nullptr, CCK).get();
}
+ // If this conversion sequence succeeded and involved implicitly converting a
+ // _Nullable type to a _Nonnull one, complain.
+ if (CCK == CCK_ImplicitConversion)
+ diagnoseNullableToNonnullConversion(ToType, InitialFromType,
+ From->getLocStart());
+
return From;
}
@@ -3550,27 +3571,43 @@
case UTT_IsVolatile:
case UTT_IsSigned:
case UTT_IsUnsigned:
+
+ // This type trait always returns false, checking the type is moot.
+ case UTT_IsInterfaceClass:
return true;
- // C++0x [meta.unary.prop] Table 49 requires the following traits to be
- // applied to a complete type.
+ // C++14 [meta.unary.prop]:
+ // If T is a non-union class type, T shall be a complete type.
+ case UTT_IsEmpty:
+ case UTT_IsPolymorphic:
+ case UTT_IsAbstract:
+ if (const auto *RD = ArgTy->getAsCXXRecordDecl())
+ if (!RD->isUnion())
+ return !S.RequireCompleteType(
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+ return true;
+
+ // C++14 [meta.unary.prop]:
+ // If T is a class type, T shall be a complete type.
+ case UTT_IsFinal:
+ case UTT_IsSealed:
+ if (ArgTy->getAsCXXRecordDecl())
+ return !S.RequireCompleteType(
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+ return true;
+
+ // C++0x [meta.unary.prop] Table 49 requires the following traits to be
+ // applied to a complete type.
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
- case UTT_IsEmpty:
- case UTT_IsPolymorphic:
- case UTT_IsAbstract:
- case UTT_IsInterfaceClass:
+
case UTT_IsDestructible:
case UTT_IsNothrowDestructible:
// Fall-through
- // These traits require a complete type.
- case UTT_IsFinal:
- case UTT_IsSealed:
-
// These trait expressions are designed to help implement predicates in
// [meta.unary.prop] despite not being named the same. They are specified
// by both GCC and the Embarcadero C++ compiler, and require the complete
@@ -3729,24 +3766,21 @@
return false;
case UTT_IsPolymorphic:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- return RD->isPolymorphic();
+ return !RD->isUnion() && RD->isPolymorphic();
return false;
case UTT_IsAbstract:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- return RD->isAbstract();
+ return !RD->isUnion() && RD->isAbstract();
return false;
+ // __is_interface_class only returns true when CL is invoked in /CLR mode and
+ // even then only when it is used with the 'interface struct ...' syntax
+ // Clang doesn't support /CLR which makes this type trait moot.
case UTT_IsInterfaceClass:
- if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- return RD->isInterface();
return false;
case UTT_IsFinal:
- if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- return RD->hasAttr<FinalAttr>();
- return false;
case UTT_IsSealed:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
- if (FinalAttr *FA = RD->getAttr<FinalAttr>())
- return FA->isSpelledAsSealed();
+ return RD->hasAttr<FinalAttr>();
return false;
case UTT_IsSigned:
return T->isSignedIntegerType();
@@ -4084,12 +4118,13 @@
return false;
}
- // Make sure the first argument is a complete type.
- if (Args[0]->getType()->isIncompleteType())
+ // Make sure the first argument is not incomplete nor a function type.
+ QualType T = Args[0]->getType();
+ if (T->isIncompleteType() || T->isFunctionType())
return false;
// Make sure the first argument is not an abstract type.
- CXXRecordDecl *RD = Args[0]->getType()->getAsCXXRecordDecl();
+ CXXRecordDecl *RD = T->getAsCXXRecordDecl();
if (RD && RD->isAbstract())
return false;
@@ -4097,13 +4132,13 @@
SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
for (unsigned I = 1, N = Args.size(); I != N; ++I) {
- QualType T = Args[I]->getType();
- if (T->isObjectType() || T->isFunctionType())
- T = S.Context.getRValueReferenceType(T);
+ QualType ArgTy = Args[I]->getType();
+ if (ArgTy->isObjectType() || ArgTy->isFunctionType())
+ ArgTy = S.Context.getRValueReferenceType(ArgTy);
OpaqueArgExprs.push_back(
- OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(),
- T.getNonLValueExprType(S.Context),
- Expr::getValueKindForType(T)));
+ OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(),
+ ArgTy.getNonLValueExprType(S.Context),
+ Expr::getValueKindForType(ArgTy)));
}
for (Expr &E : OpaqueArgExprs)
ArgExprs.push_back(&E);
@@ -4134,7 +4169,7 @@
// Under Objective-C ARC, if the destination has non-trivial Objective-C
// lifetime, this is a non-trivial construction.
if (S.getLangOpts().ObjCAutoRefCount &&
- hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
+ hasNontrivialObjCLifetime(T.getNonReferenceType()))
return false;
// The initialization succeeded; now make sure there are no non-trivial
@@ -4270,8 +4305,7 @@
return LhsT->isVoidType();
// A function definition requires a complete, non-abstract return type.
- if (Self.RequireCompleteType(KeyLoc, RhsT, 0) ||
- Self.RequireNonAbstractType(KeyLoc, RhsT, 0))
+ if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT))
return false;
// Compute the result of add_rvalue_reference.
@@ -4557,7 +4591,7 @@
return QualType();
}
- if (!IsDerivedFrom(LHSType, Class)) {
+ if (!IsDerivedFrom(Loc, LHSType, Class)) {
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
<< (int)isIndirect << LHS.get()->getType();
return QualType();
@@ -4685,9 +4719,9 @@
const RecordType *FRec = FTy->getAs<RecordType>();
const RecordType *TRec = TTy->getAs<RecordType>();
bool FDerivedFromT = FRec && TRec && FRec != TRec &&
- Self.IsDerivedFrom(FTy, TTy);
- if (FRec && TRec &&
- (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
+ Self.IsDerivedFrom(QuestionLoc, FTy, TTy);
+ if (FRec && TRec && (FRec == TRec || FDerivedFromT ||
+ Self.IsDerivedFrom(QuestionLoc, TTy, FTy))) {
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
@@ -5722,11 +5756,16 @@
//
// This also indicates that we could be parsing a pseudo-destructor-name.
// Note that Objective-C class and object types can be pseudo-destructor
- // expressions or normal member (ivar or property) access expressions.
+ // expressions or normal member (ivar or property) access expressions, and
+ // it's legal for the type to be incomplete if this is a pseudo-destructor
+ // call. We'll do more incomplete-type checks later in the lookup process,
+ // so just skip this check for ObjC types.
if (BaseType->isObjCObjectOrInterfaceType()) {
+ ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
+ return Base;
} else if (!BaseType->isRecordType()) {
- ObjectType = ParsedType();
+ ObjectType = nullptr;
MayBePseudoDestructor = true;
return Base;
}
@@ -6382,7 +6421,7 @@
else if (SS && !TC.WillReplaceSpecifier())
NewSS = *SS;
- if (auto *ND = TC.getCorrectionDecl()) {
+ if (auto *ND = TC.getFoundDecl()) {
R.setLookupName(ND->getDeclName());
R.addDecl(ND);
if (ND->isCXXClassMember()) {
@@ -6503,9 +6542,9 @@
if (!E)
return nullptr;
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
- return DRE->getDecl();
+ return DRE->getFoundDecl();
if (auto *ME = dyn_cast<MemberExpr>(E))
- return ME->getMemberDecl();
+ return ME->getFoundDecl();
// FIXME: Add any other expr types that could be be seen by the delayed typo
// correction TreeTransform for which the corresponding TypoCorrection could
// contain multiple decls.
@@ -6610,7 +6649,7 @@
// For the first TypoExpr and an uncached TypoExpr, find the next likely
// typo correction and return it.
while (TypoCorrection TC = State.Consumer->getNextCorrection()) {
- if (InitDecl && TC.getCorrectionDecl() == InitDecl)
+ if (InitDecl && TC.getFoundDecl() == InitDecl)
continue;
ExprResult NE = State.RecoveryHandler ?
State.RecoveryHandler(SemaRef, E, TC) :
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 9c345f8..f62b5a5 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -380,7 +380,8 @@
const Selector &Sel,
ASTContext &Context) {
if (Member)
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
return OMD;
@@ -401,7 +402,8 @@
Decl *GDecl = nullptr;
for (const auto *I : QIdTy->quals()) {
if (Member)
- if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
GDecl = PD;
break;
}
@@ -1324,7 +1326,9 @@
D = CAT->getClassInterface();
ClassDeclared = cast<ObjCInterfaceDecl>(D);
} else {
- if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
+ if (IsArrow &&
+ IDecl->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
S.Diag(MemberLoc, diag::err_property_found_suggest)
<< Member << BaseExpr.get()->getType()
<< FixItHint::CreateReplacement(OpLoc, ".");
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 3257741..53f39e3 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -32,24 +32,21 @@
using llvm::makeArrayRef;
ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
- Expr **strings,
- unsigned NumStrings) {
- StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings);
-
+ ArrayRef<Expr *> Strings) {
// Most ObjC strings are formed out of a single piece. However, we *can*
// have strings formed out of multiple @ strings with multiple pptokens in
// each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one
// StringLiteral for ObjCStringLiteral to hold onto.
- StringLiteral *S = Strings[0];
+ StringLiteral *S = cast<StringLiteral>(Strings[0]);
// If we have a multi-part string, merge it all together.
- if (NumStrings != 1) {
+ if (Strings.size() != 1) {
// Concatenate objc strings.
SmallString<128> StrBuf;
SmallVector<SourceLocation, 8> StrLocs;
- for (unsigned i = 0; i != NumStrings; ++i) {
- S = Strings[i];
+ for (Expr *E : Strings) {
+ S = cast<StringLiteral>(E);
// ObjC strings can't be wide or UTF.
if (!S->isAscii()) {
@@ -322,6 +319,7 @@
// to use to determine the Objective-c literal kind.
switch (Char->getKind()) {
case CharacterLiteral::Ascii:
+ case CharacterLiteral::UTF8:
NumberType = Context.CharTy;
break;
@@ -580,6 +578,7 @@
// to use to determine the Objective-c literal kind.
switch (Char->getKind()) {
case CharacterLiteral::Ascii:
+ case CharacterLiteral::UTF8:
ValueType = Context.CharTy;
break;
@@ -759,9 +758,9 @@
BaseExpr = Result.get();
// Build the pseudo-object expression.
- return ObjCSubscriptRefExpr::Create(Context, BaseExpr, IndexExpr,
- Context.PseudoObjectTy, getterMethod,
- setterMethod, RB);
+ return new (Context) ObjCSubscriptRefExpr(
+ BaseExpr, IndexExpr, Context.PseudoObjectTy, VK_LValue, OK_ObjCSubscript,
+ getterMethod, setterMethod, RB);
}
ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
@@ -868,9 +867,8 @@
ArrayWithObjectsMethod, SR));
}
-ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
- ObjCDictionaryElement *Elements,
- unsigned NumElements) {
+ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
+ MutableArrayRef<ObjCDictionaryElement> Elements) {
SourceLocation Loc = SR.getBegin();
if (!NSDictionaryDecl) {
@@ -1007,31 +1005,31 @@
// Check that each of the keys and values provided is valid in a collection
// literal, performing conversions as necessary.
bool HasPackExpansions = false;
- for (unsigned I = 0, N = NumElements; I != N; ++I) {
+ for (ObjCDictionaryElement &Element : Elements) {
// Check the key.
- ExprResult Key = CheckObjCCollectionLiteralElement(*this, Elements[I].Key,
+ ExprResult Key = CheckObjCCollectionLiteralElement(*this, Element.Key,
KeyT);
if (Key.isInvalid())
return ExprError();
// Check the value.
ExprResult Value
- = CheckObjCCollectionLiteralElement(*this, Elements[I].Value, ValueT);
+ = CheckObjCCollectionLiteralElement(*this, Element.Value, ValueT);
if (Value.isInvalid())
return ExprError();
- Elements[I].Key = Key.get();
- Elements[I].Value = Value.get();
+ Element.Key = Key.get();
+ Element.Value = Value.get();
- if (Elements[I].EllipsisLoc.isInvalid())
+ if (Element.EllipsisLoc.isInvalid())
continue;
- if (!Elements[I].Key->containsUnexpandedParameterPack() &&
- !Elements[I].Value->containsUnexpandedParameterPack()) {
- Diag(Elements[I].EllipsisLoc,
+ if (!Element.Key->containsUnexpandedParameterPack() &&
+ !Element.Value->containsUnexpandedParameterPack()) {
+ Diag(Element.EllipsisLoc,
diag::err_pack_expansion_without_parameter_packs)
- << SourceRange(Elements[I].Key->getLocStart(),
- Elements[I].Value->getLocEnd());
+ << SourceRange(Element.Key->getLocStart(),
+ Element.Value->getLocEnd());
return ExprError();
}
@@ -1043,7 +1041,7 @@
= Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(NSDictionaryDecl));
return MaybeBindToTemporary(ObjCDictionaryLiteral::Create(
- Context, makeArrayRef(Elements, NumElements), HasPackExpansions, Ty,
+ Context, Elements, HasPackExpansions, Ty,
DictionaryWithObjectsMethod, SR));
}
@@ -1092,7 +1090,7 @@
QualType EncodedType = GetTypeFromParser(ty, &TInfo);
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(EncodedType,
- PP.getLocForEndOfToken(LParenLoc));
+ getLocForEndOfToken(LParenLoc));
return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
}
@@ -1780,7 +1778,8 @@
MemberName, BaseRange))
return ExprError();
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -1795,7 +1794,8 @@
}
// Check protocols on qualified interfaces.
for (const auto *I : OPT->quals())
- if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -1854,8 +1854,9 @@
// Special warning if member name used in a property-dot for a setter accessor
// does not use a property with same name; e.g. obj.X = ... for a property with
// name 'x'.
- if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor()
- && !IFace->FindPropertyDeclaration(Member)) {
+ if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() &&
+ !IFace->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
// Do not warn if user is using property-dot syntax to make call to
// user named setter.
@@ -2042,7 +2043,7 @@
bool IsSuper,
bool HasTrailingDot,
ParsedType &ReceiverType) {
- ReceiverType = ParsedType();
+ ReceiverType = nullptr;
// If the identifier is "super" and there is no trailing dot, we're
// messaging super. If the identifier is "super" and there is a
@@ -2726,6 +2727,8 @@
// Try to complete the type. Under ARC, this is a hard error from which
// we don't try to recover.
+ // FIXME: In the non-ARC case, this will still be a hard error if the
+ // definition is found in a module that's not visible.
const ObjCInterfaceDecl *forwardClass = nullptr;
if (RequireCompleteType(Loc, OCIType->getPointeeType(),
getLangOpts().ObjCAutoRefCount
@@ -3397,7 +3400,7 @@
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
BridgeCall));
DiagB.AddFixItHint(FixItHint::CreateInsertion(
- S.PP.getLocForEndOfToken(range.getEnd()),
+ S.getLocForEndOfToken(range.getEnd()),
")"));
}
return;
@@ -3430,7 +3433,7 @@
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
castCode));
DiagB.AddFixItHint(FixItHint::CreateInsertion(
- S.PP.getLocForEndOfToken(range.getEnd()),
+ S.getLocForEndOfToken(range.getEnd()),
")"));
}
}
@@ -3498,7 +3501,7 @@
}
// Check whether this could be fixed with a bridge cast.
- SourceLocation afterLParen = S.PP.getLocForEndOfToken(castRange.getBegin());
+ SourceLocation afterLParen = S.getLocForEndOfToken(castRange.getBegin());
SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc;
// Bridge from an ARC type to a CF type.
@@ -3816,7 +3819,7 @@
ObjCMethodDecl *&ClassMethod,
ObjCMethodDecl *&InstanceMethod,
TypedefNameDecl *&TDNDecl,
- bool CfToNs) {
+ bool CfToNs, bool Diagnose) {
QualType T = CfToNs ? SrcType : DestType;
ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl);
if (!ObjCBAttr)
@@ -3832,20 +3835,24 @@
LookupResult R(*this, DeclarationName(RCId), SourceLocation(),
Sema::LookupOrdinaryName);
if (!LookupName(R, TUScope)) {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
Target = R.getFoundDecl();
if (Target && isa<ObjCInterfaceDecl>(Target))
RelatedClass = cast<ObjCInterfaceDecl>(Target);
else {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- if (Target)
- Diag(Target->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ Diag(Target->getLocStart(), diag::note_declared_at);
+ }
return false;
}
@@ -3854,9 +3861,11 @@
Selector Sel = Context.Selectors.getUnarySelector(CMId);
ClassMethod = RelatedClass->lookupMethod(Sel, false);
if (!ClassMethod) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << false;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << false;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
}
@@ -3866,9 +3875,11 @@
Selector Sel = Context.Selectors.getNullarySelector(IMId);
InstanceMethod = RelatedClass->lookupMethod(Sel, true);
if (!InstanceMethod) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << true;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << true;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
}
@@ -3878,7 +3889,7 @@
bool
Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
QualType DestType, QualType SrcType,
- Expr *&SrcExpr) {
+ Expr *&SrcExpr, bool Diagnose) {
ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType);
ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType);
bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable);
@@ -3891,27 +3902,29 @@
ObjCMethodDecl *InstanceMethod = nullptr;
TypedefNameDecl *TDNDecl = nullptr;
if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass,
- ClassMethod, InstanceMethod, TDNDecl, CfToNs))
+ ClassMethod, InstanceMethod, TDNDecl,
+ CfToNs, Diagnose))
return false;
if (CfToNs) {
// Implicit conversion from CF to ObjC object is needed.
if (ClassMethod) {
- std::string ExpressionString = "[";
- ExpressionString += RelatedClass->getNameAsString();
- ExpressionString += " ";
- ExpressionString += ClassMethod->getSelector().getAsString();
- SourceLocation SrcExprEndLoc = PP.getLocForEndOfToken(SrcExpr->getLocEnd());
- // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << ClassMethod->getSelector() << false
- << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString)
- << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
- Diag(RelatedClass->getLocStart(), diag::note_declared_at);
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ std::string ExpressionString = "[";
+ ExpressionString += RelatedClass->getNameAsString();
+ ExpressionString += " ";
+ ExpressionString += ClassMethod->getSelector().getAsString();
+ SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd());
+ // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << ClassMethod->getSelector() << false
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString)
+ << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
- QualType receiverType =
- Context.getObjCInterfaceType(RelatedClass);
+ QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
// Argument.
Expr *args[] = { SrcExpr };
ExprResult msg = BuildClassMessageImplicit(receiverType, false,
@@ -3925,30 +3938,34 @@
else {
// Implicit conversion from ObjC type to CF object is needed.
if (InstanceMethod) {
- std::string ExpressionString;
- SourceLocation SrcExprEndLoc = PP.getLocForEndOfToken(SrcExpr->getLocEnd());
- if (InstanceMethod->isPropertyAccessor())
- if (const ObjCPropertyDecl *PDecl = InstanceMethod->findPropertyDecl()) {
- // fixit: ObjectExpr.propertyname when it is aproperty accessor.
- ExpressionString = ".";
- ExpressionString += PDecl->getNameAsString();
+ if (Diagnose) {
+ std::string ExpressionString;
+ SourceLocation SrcExprEndLoc =
+ getLocForEndOfToken(SrcExpr->getLocEnd());
+ if (InstanceMethod->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl =
+ InstanceMethod->findPropertyDecl()) {
+ // fixit: ObjectExpr.propertyname when it is aproperty accessor.
+ ExpressionString = ".";
+ ExpressionString += PDecl->getNameAsString();
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ }
+ if (ExpressionString.empty()) {
+ // Provide a fixit: [ObjectExpr InstanceMethod]
+ ExpressionString = " ";
+ ExpressionString += InstanceMethod->getSelector().getAsString();
+ ExpressionString += "]";
+
Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[")
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
}
- if (ExpressionString.empty()) {
- // Provide a fixit: [ObjectExpr InstanceMethod]
- ExpressionString = " ";
- ExpressionString += InstanceMethod->getSelector().getAsString();
- ExpressionString += "]";
-
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[")
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
}
- Diag(RelatedClass->getLocStart(), diag::note_declared_at);
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
ExprResult msg =
BuildInstanceMessageImplicit(SrcExpr, SrcType,
@@ -3965,6 +3982,7 @@
Sema::ARCConversionResult
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *&castExpr, CheckedConversionKind CCK,
+ bool Diagnose,
bool DiagnoseCFAudited,
BinaryOperatorKind Opc) {
QualType castExprType = castExpr->getType();
@@ -3980,9 +3998,9 @@
if (exprACTC == castACTC) {
// check for viablity and report error if casting an rvalue to a
// life-time qualifier.
- if ((castACTC == ACTC_retainable) &&
+ if (Diagnose && castACTC == ACTC_retainable &&
(CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
- (castType != castExprType)) {
+ castType != castExprType) {
const Type *DT = castType.getTypePtr();
QualType QDT = castType;
// We desugar some types but not others. We ignore those
@@ -4051,19 +4069,20 @@
// to 'NSString *'. Let caller issue a normal mismatched diagnostic with
// suitable fix-it.
if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
- ConversionToObjCStringLiteralCheck(castType, castExpr))
+ ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose))
return ACR_okay;
// Do not issue "bridge cast" diagnostic when implicit casting
// a retainable object to a CF type parameter belonging to an audited
// CF API function. Let caller issue a normal type mismatched diagnostic
// instead.
- if (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
- castACTC != ACTC_coreFoundation)
+ if (Diagnose &&
+ (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
+ castACTC != ACTC_coreFoundation))
if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
(Opc == BO_NE || Opc == BO_EQ)))
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, castExpr, exprACTC, CCK);
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr,
+ castExpr, exprACTC, CCK);
return ACR_okay;
}
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index 2e327ec..714fbed 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -42,7 +42,7 @@
const CanQualType FromUnq = From.getUnqualifiedType();
const CanQualType ToUnq = To.getUnqualifiedType();
- if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) &&
+ if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
To.isAtLeastAsQualifiedAs(From))
return true;
return false;
@@ -58,8 +58,8 @@
const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
- const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange()
- .getEnd());
+ const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
+ .getEnd());
// Strip the implicit casts - those are implied by the compiler, not the
// original source code.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 461b3b6..c60ea86 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -805,7 +805,8 @@
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
// Update the structured sub-object initializer so that it's ending
// range corresponds with the end of the last initializer it used.
- if (EndIndex < ParentIList->getNumInits()) {
+ if (EndIndex < ParentIList->getNumInits() &&
+ ParentIList->getInit(EndIndex)) {
SourceLocation EndLoc
= ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
StructuredSubobjectInitList->setRBraceLoc(EndLoc);
@@ -2275,7 +2276,7 @@
if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
FieldType, nullptr, nullptr, Index,
StructuredList, newStructuredIndex,
- true, false))
+ FinishSubobjectInit, false))
return true;
}
@@ -2466,11 +2467,11 @@
Index = OldIndex;
ElementEntity.setElementIndex(ElementIndex);
- if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1,
- ElementType, nullptr, nullptr, Index,
- StructuredList, ElementIndex,
- (DesignatedStartIndex == DesignatedEndIndex),
- false))
+ if (CheckDesignatedInitializer(
+ ElementEntity, IList, DIE, DesigIdx + 1, ElementType, nullptr,
+ nullptr, Index, StructuredList, ElementIndex,
+ FinishSubobjectInit && (DesignatedStartIndex == DesignatedEndIndex),
+ false))
return true;
// Move to the next index in the array that we'll be initializing.
@@ -3011,6 +3012,7 @@
case FK_VariableLengthArrayHasInitializer:
case FK_PlaceholderType:
case FK_ExplicitConstructor:
+ case FK_AddressOfUnaddressableFunction:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -3326,7 +3328,7 @@
if (!S.isStdInitializerList(DestType, &E))
return false;
- if (S.RequireCompleteType(List->getExprLoc(), E, 0)) {
+ if (!S.isCompleteType(List->getExprLoc(), E)) {
Sequence.setIncompleteTypeFailure(E);
return true;
}
@@ -3436,7 +3438,7 @@
"IsListInit must come with a single initializer list argument.");
// The type we're constructing needs to be complete.
- if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ if (!S.isCompleteType(Kind.getLocation(), DestType)) {
Sequence.setIncompleteTypeFailure(DestType);
return;
}
@@ -3677,7 +3679,7 @@
}
if (DestType->isRecordType() &&
- S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {
+ !S.isCompleteType(InitList->getLocStart(), DestType)) {
Sequence.setIncompleteTypeFailure(DestType);
return;
}
@@ -3697,7 +3699,7 @@
if (DestType->isRecordType()) {
QualType InitType = InitList->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
- S.IsDerivedFrom(InitType, DestType)) {
+ S.IsDerivedFrom(InitList->getLocStart(), InitType, DestType)) {
Expr *InitAsExpr = InitList->getInit(0);
TryConstructorInitialization(S, Entity, Kind, InitAsExpr, DestType,
Sequence, /*InitListSyntax*/ false,
@@ -3731,7 +3733,9 @@
// C++11 [dcl.init.list]p3:
// - If T is an aggregate, aggregate initialization is performed.
- if (DestType->isRecordType() && !DestType->isAggregateType()) {
+ if ((DestType->isRecordType() && !DestType->isAggregateType()) ||
+ (S.getLangOpts().CPlusPlus11 &&
+ S.isStdInitializerList(DestType, nullptr))) {
if (S.getLangOpts().CPlusPlus11) {
// - Otherwise, if the initializer list has no elements and T is a
// class type with a default constructor, the object is
@@ -3837,7 +3841,7 @@
const RecordType *T1RecordType = nullptr;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
- !S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
+ S.isCompleteType(Kind.getLocation(), T1)) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
@@ -3873,7 +3877,7 @@
const RecordType *T2RecordType = nullptr;
if ((T2RecordType = T2->getAs<RecordType>()) &&
- !S.RequireCompleteType(Kind.getLocation(), T2, 0)) {
+ S.isCompleteType(Kind.getLocation(), T2)) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
@@ -4458,7 +4462,7 @@
= cast<CXXRecordDecl>(DestRecordType->getDecl());
// Try to complete the type we're converting to.
- if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ if (S.isCompleteType(Kind.getLocation(), DestType)) {
DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
// The container holding the constructors can under certain conditions
// be changed while iterating. To be safe we copy the lookup results
@@ -4504,7 +4508,7 @@
// We can only enumerate the conversion functions for a complete type; if
// the type isn't complete, simply skip this step.
- if (!S.RequireCompleteType(DeclLoc, SourceType, 0)) {
+ if (S.isCompleteType(DeclLoc, SourceType)) {
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
@@ -4801,6 +4805,17 @@
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
}
+/// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the
+/// address of that function, this returns true. Otherwise, it returns false.
+static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) {
+ auto *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE || !isa<FunctionDecl>(DRE->getDecl()))
+ return false;
+
+ return !S.checkAddressOfFunctionIsAvailable(
+ cast<FunctionDecl>(DRE->getDecl()));
+}
+
void InitializationSequence::InitializeFrom(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4982,7 +4997,7 @@
}
assert(S.getLangOpts().CPlusPlus);
-
+
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
// - If the initialization is direct-initialization, or if it is
@@ -4992,7 +5007,7 @@
if (Kind.getKind() == InitializationKind::IK_Direct ||
(Kind.getKind() == InitializationKind::IK_Copy &&
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
- S.IsDerivedFrom(SourceType, DestType))))
+ S.IsDerivedFrom(Initializer->getLocStart(), SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args,
DestType, *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
@@ -5021,7 +5036,8 @@
bool NeedAtomicConversion = false;
if (const AtomicType *Atomic = DestType->getAs<AtomicType>()) {
if (Context.hasSameUnqualifiedType(SourceType, Atomic->getValueType()) ||
- S.IsDerivedFrom(SourceType, Atomic->getValueType())) {
+ S.IsDerivedFrom(Initializer->getLocStart(), SourceType,
+ Atomic->getValueType())) {
DestType = Atomic->getValueType();
NeedAtomicConversion = true;
}
@@ -5079,6 +5095,9 @@
!S.ResolveAddressOfOverloadedFunction(Initializer, DestType,
false, dap))
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+ else if (Initializer->getType()->isFunctionType() &&
+ isExprAnUnaddressableFunction(S, Initializer))
+ SetFailed(InitializationSequence::FK_AddressOfUnaddressableFunction);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
@@ -6360,7 +6379,7 @@
CastKind = CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
- S.IsDerivedFrom(SourceType, Class))
+ S.IsDerivedFrom(Loc, SourceType, Class))
IsCopy = true;
CreatedObject = true;
@@ -6926,6 +6945,13 @@
break;
}
+ case FK_AddressOfUnaddressableFunction: {
+ auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(Args[0])->getDecl());
+ S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ Args[0]->getLocStart());
+ break;
+ }
+
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
@@ -7248,6 +7274,10 @@
OS << "array requires initializer list";
break;
+ case FK_AddressOfUnaddressableFunction:
+ OS << "address of unaddressable function was taken";
+ break;
+
case FK_ArrayNeedsInitListOrStringLiteral:
OS << "array requires initializer list or string literal";
break;
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index a8f109d..1a62f0d 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -226,15 +226,16 @@
if (LSI->GLTemplateParameterList)
return LSI->GLTemplateParameterList;
- if (LSI->AutoTemplateParams.size()) {
+ if (!LSI->AutoTemplateParams.empty()) {
SourceRange IntroRange = LSI->IntroducerRange;
SourceLocation LAngleLoc = IntroRange.getBegin();
SourceLocation RAngleLoc = IntroRange.getEnd();
LSI->GLTemplateParameterList = TemplateParameterList::Create(
SemaRef.Context,
/*Template kw loc*/ SourceLocation(), LAngleLoc,
- (NamedDecl **)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size(), RAngleLoc);
+ llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
+ LSI->AutoTemplateParams.size()),
+ RAngleLoc);
}
return LSI->GLTemplateParameterList;
}
@@ -616,6 +617,8 @@
assert(CSI.HasImplicitReturnType);
// If it was ever a placeholder, it had to been deduced to DependentTy.
assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType());
+ assert((!isa<LambdaScopeInfo>(CSI) || !getLangOpts().CPlusPlus14) &&
+ "lambda expressions use auto deduction in C++14 onwards");
// C++ core issue 975:
// If a lambda-expression does not include a trailing-return-type,
@@ -699,18 +702,11 @@
}
}
-QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
- bool ByRef,
- IdentifierInfo *Id,
- Expr *&Init) {
-
- // We do not need to distinguish between direct-list-initialization
- // and copy-list-initialization here, because we will always deduce
- // std::initializer_list<T>, and direct- and copy-list-initialization
- // always behave the same for such a type.
- // FIXME: We should model whether an '=' was present.
- const bool IsDirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
-
+QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
+ bool ByRef,
+ IdentifierInfo *Id,
+ bool IsDirectInit,
+ Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -723,50 +719,16 @@
}
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
- // Are we a non-list direct initialization?
- ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
-
- Expr *DeduceInit = Init;
- // Initializer could be a C++ direct-initializer. Deduction only works if it
- // contains exactly one expression.
- if (CXXDirectInit) {
- if (CXXDirectInit->getNumExprs() == 0) {
- Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_no_expression)
- << DeclarationName(Id) << TSI->getType() << Loc;
- return QualType();
- } else if (CXXDirectInit->getNumExprs() > 1) {
- Diag(CXXDirectInit->getExpr(1)->getLocStart(),
- diag::err_init_capture_multiple_expressions)
- << DeclarationName(Id) << TSI->getType() << Loc;
- return QualType();
- } else {
- DeduceInit = CXXDirectInit->getExpr(0);
- if (isa<InitListExpr>(DeduceInit))
- Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_paren_braces)
- << DeclarationName(Id) << Loc;
- }
- }
-
- // Now deduce against the initialization expression and store the deduced
- // type below.
- QualType DeducedType;
- if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
- if (isa<InitListExpr>(Init))
- Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
- << DeclarationName(Id)
- << (DeduceInit->getType().isNull() ? TSI->getType()
- : DeduceInit->getType())
- << DeduceInit->getSourceRange();
- else
- Diag(Loc, diag::err_init_capture_deduction_failure)
- << DeclarationName(Id) << TSI->getType()
- << (DeduceInit->getType().isNull() ? TSI->getType()
- : DeduceInit->getType())
- << DeduceInit->getSourceRange();
- }
+ // Deduce the type of the init capture.
+ QualType DeducedType = deduceVarTypeFromInitializer(
+ /*VarDecl*/nullptr, DeclarationName(Id), DeductType, TSI,
+ SourceRange(Loc, Loc), IsDirectInit, Init);
if (DeducedType.isNull())
return QualType();
+ // Are we a non-list direct initialization?
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+
// Perform initialization analysis and ensure any implicit conversions
// (such as lvalue-to-rvalue) are enforced.
InitializedEntity Entity =
@@ -803,9 +765,10 @@
return DeducedType;
}
-VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
- QualType InitCaptureType, IdentifierInfo *Id, Expr *Init) {
-
+VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
+ QualType InitCaptureType,
+ IdentifierInfo *Id,
+ unsigned InitStyle, Expr *Init) {
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
Loc);
// Create a dummy variable representing the init-capture. This is not actually
@@ -816,6 +779,8 @@
Loc, Id, InitCaptureType, TSI, SC_Auto);
NewVD->setInitCapture(true);
NewVD->setReferenced(true);
+ // FIXME: Pass in a VarDecl::InitializationStyle.
+ NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle));
NewVD->markUsed(Context);
NewVD->setInit(Init);
return NewVD;
@@ -1014,8 +979,23 @@
// in this case.
if (C->InitCaptureType.get().isNull())
continue;
- Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
- C->Id, C->Init.get());
+
+ unsigned InitStyle;
+ switch (C->InitKind) {
+ case LambdaCaptureInitKind::NoInit:
+ llvm_unreachable("not an init-capture?");
+ case LambdaCaptureInitKind::CopyInit:
+ InitStyle = VarDecl::CInit;
+ break;
+ case LambdaCaptureInitKind::DirectInit:
+ InitStyle = VarDecl::CallInit;
+ break;
+ case LambdaCaptureInitKind::ListInit:
+ InitStyle = VarDecl::ListInit;
+ break;
+ }
+ Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
+ C->Id, InitStyle, C->Init.get());
// C++1y [expr.prim.lambda]p11:
// An init-capture behaves as if it declares and explicitly
// captures a variable [...] whose declarative region is the
@@ -1023,6 +1003,9 @@
if (Var)
PushOnScopeChains(Var, CurScope, false);
} else {
+ assert(C->InitKind == LambdaCaptureInitKind::NoInit &&
+ "init capture has valid but null init?");
+
// C++11 [expr.prim.lambda]p8:
// If a lambda-capture includes a capture-default that is &, the
// identifiers in the lambda-capture shall not be preceded by &.
@@ -1161,6 +1144,12 @@
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
+ // This conversion is explicitly disabled if the lambda's function has
+ // pass_object_size attributes on any of its parameters.
+ if (std::any_of(CallOperator->param_begin(), CallOperator->param_end(),
+ std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)))
+ return;
+
// Add the conversion to function pointer.
const FunctionProtoType *CallOpProto =
CallOperator->getType()->getAs<FunctionProtoType>();
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index a020dcf..f28cd27 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -368,13 +368,17 @@
auto *DUnderlying = D->getUnderlyingDecl();
auto *EUnderlying = Existing->getUnderlyingDecl();
- // If they have different underlying declarations, pick one arbitrarily
- // (this happens when two type declarations denote the same type).
- // FIXME: Should we prefer a struct declaration over a typedef or vice versa?
- // If a name could be a typedef-name or a class-name, which is it?
+ // If they have different underlying declarations, prefer a typedef over the
+ // original type (this happens when two type declarations denote the same
+ // type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef
+ // might carry additional semantic information, such as an alignment override.
+ // However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag
+ // declaration over a typedef.
if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) {
assert(isa<TypeDecl>(DUnderlying) && isa<TypeDecl>(EUnderlying));
- return false;
+ bool HaveTag = isa<TagDecl>(EUnderlying);
+ bool WantTag = Kind == Sema::LookupTagName;
+ return HaveTag != WantTag;
}
// Pick the function with more default arguments.
@@ -434,6 +438,23 @@
return !S.isVisible(Existing);
}
+/// Determine whether \p D can hide a tag declaration.
+static bool canHideTag(NamedDecl *D) {
+ // C++ [basic.scope.declarative]p4:
+ // Given a set of declarations in a single declarative region [...]
+ // exactly one declaration shall declare a class name or enumeration name
+ // that is not a typedef name and the other declarations shall all refer to
+ // the same variable or enumerator, or all refer to functions and function
+ // templates; in this case the class name or enumeration name is hidden.
+ // C++ [basic.scope.hiding]p2:
+ // A class name or enumeration name can be hidden by the name of a
+ // variable, data member, function, or enumerator declared in the same
+ // scope.
+ D = D->getUnderlyingDecl();
+ return isa<VarDecl>(D) || isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D);
+}
+
/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
@@ -489,15 +510,12 @@
// no ambiguity if they all refer to the same type, so unique based on the
// canonical type.
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
- // FIXME: Why are nested type declarations treated differently?
- if (!TD->getDeclContext()->isRecord()) {
- QualType T = getSema().Context.getTypeDeclType(TD);
- auto UniqueResult = UniqueTypes.insert(
- std::make_pair(getSema().Context.getCanonicalType(T), I));
- if (!UniqueResult.second) {
- // The type is not unique.
- ExistingI = UniqueResult.first->second;
- }
+ QualType T = getSema().Context.getTypeDeclType(TD);
+ auto UniqueResult = UniqueTypes.insert(
+ std::make_pair(getSema().Context.getCanonicalType(T), I));
+ if (!UniqueResult.second) {
+ // The type is not unique.
+ ExistingI = UniqueResult.first->second;
}
}
@@ -564,10 +582,13 @@
// wherever the object, function, or enumerator name is visible.
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
- if (HideTags && HasTag && !Ambiguous &&
+ if (N > 1 && HideTags && HasTag && !Ambiguous &&
(HasFunction || HasNonFunction || HasUnresolved)) {
- if (getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
- getContextForScopeMatching(Decls[UniqueTagIndex ? 0 : N - 1])))
+ NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1];
+ if (isa<TagDecl>(Decls[UniqueTagIndex]->getUnderlyingDecl()) &&
+ getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
+ getContextForScopeMatching(OtherDecl)) &&
+ canHideTag(OtherDecl))
Decls[UniqueTagIndex] = Decls[--N];
else
Ambiguous = true;
@@ -629,6 +650,13 @@
}
}
+LLVM_DUMP_METHOD void LookupResult::dump() {
+ llvm::errs() << "lookup results for " << getLookupName().getAsString()
+ << ":\n";
+ for (NamedDecl *D : *this)
+ D->dump();
+}
+
/// \brief Lookup a builtin function, when name lookup would otherwise
/// fail.
static bool LookupBuiltin(Sema &S, LookupResult &R) {
@@ -1514,18 +1542,22 @@
// Check whether DeclModule is transitively exported to an import of
// the lookup set.
- for (llvm::DenseSet<Module *>::iterator I = LookupModules.begin(),
- E = LookupModules.end();
- I != E; ++I)
- if ((*I)->isModuleVisible(DeclModule))
- return true;
- return false;
+ return std::any_of(LookupModules.begin(), LookupModules.end(),
+ [&](Module *M) { return M->isModuleVisible(DeclModule); });
}
bool Sema::isVisibleSlow(const NamedDecl *D) {
return LookupResult::isVisible(*this, const_cast<NamedDecl*>(D));
}
+bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) {
+ for (auto *D : R) {
+ if (isVisible(D))
+ return true;
+ }
+ return New->isExternallyVisible();
+}
+
/// \brief Retrieve the visible declaration corresponding to D, if any.
///
/// This routine determines whether the declaration D is visible in the current
@@ -1878,7 +1910,18 @@
cast<TagDecl>(LookupCtx)->isBeingDefined()) &&
"Declaration context must already be complete!");
- // Perform qualified name lookup into the LookupCtx.
+ struct QualifiedLookupInScope {
+ bool oldVal;
+ DeclContext *Context;
+ // Set flag in DeclContext informing debugger that we're looking for qualified name
+ QualifiedLookupInScope(DeclContext *ctx) : Context(ctx) {
+ oldVal = ctx->setUseQualifiedLookup();
+ }
+ ~QualifiedLookupInScope() {
+ Context->setUseQualifiedLookup(oldVal);
+ }
+ } QL(LookupCtx);
+
if (LookupDirect(*this, R, LookupCtx)) {
R.resolveKind();
if (isa<CXXRecordDecl>(LookupCtx))
@@ -2392,7 +2435,8 @@
}
// Only recurse into base classes for complete types.
- if (!Class->hasDefinition())
+ if (!Result.S.isCompleteType(Result.InstantiationLoc,
+ Result.S.Context.getRecordType(Class)))
return;
// Add direct and indirect base classes along with their associated
@@ -2485,10 +2529,8 @@
// classes. Its associated namespaces are the namespaces in
// which its associated classes are defined.
case Type::Record: {
- Result.S.RequireCompleteType(Result.InstantiationLoc, QualType(T, 0),
- /*no diagnostic*/ 0);
- CXXRecordDecl *Class
- = cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
+ CXXRecordDecl *Class =
+ cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
addAssociatedClassesAndNamespaces(Result, Class);
break;
}
@@ -2581,6 +2623,9 @@
case Type::Atomic:
T = cast<AtomicType>(T)->getValueType().getTypePtr();
continue;
+ case Type::Pipe:
+ T = cast<PipeType>(T)->getElementType().getTypePtr();
+ continue;
}
if (Queue.empty())
@@ -3172,7 +3217,8 @@
for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) {
DeclContext *LexDC = DI->getLexicalDeclContext();
if (isa<CXXRecordDecl>(LexDC) &&
- AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) {
+ AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)) &&
+ isVisible(cast<NamedDecl>(DI))) {
DeclaredInAssociatedClass = true;
break;
}
@@ -3269,9 +3315,6 @@
} // end anonymous namespace
NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
- // Look through using declarations.
- ND = ND->getUnderlyingDecl();
-
unsigned IDNS = ND->getIdentifierNamespace();
std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin();
for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend();
@@ -3844,9 +3887,12 @@
if (const Type *T = NNS->getAsType())
SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization;
}
- for (const auto *TI : SemaRef.getASTContext().types()) {
- if (!TI->isClassType() && isa<TemplateSpecializationType>(TI))
- continue;
+ // Do not transform this into an iterator-based loop. The loop body can
+ // trigger the creation of further types (through lazy deserialization) and
+ // invalide iterators into this list.
+ auto &Types = SemaRef.getASTContext().getTypes();
+ for (unsigned I = 0; I != Types.size(); ++I) {
+ const auto *TI = Types[I];
if (CXXRecordDecl *CD = TI->getAsCXXRecordDecl()) {
CD = CD->getCanonicalDecl();
if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() &&
@@ -4161,7 +4207,8 @@
}
}
- if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) {
+ if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(
+ Name, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
Res.addDecl(Prop);
Res.resolveKind();
return;
@@ -4683,7 +4730,7 @@
if (isKeyword())
CorrectionDecls.clear();
- CorrectionDecls.push_back(CDecl->getUnderlyingDecl());
+ CorrectionDecls.push_back(CDecl);
if (!CorrectionName)
CorrectionName = CDecl->getDeclName();
@@ -4912,7 +4959,7 @@
// Maybe we're just missing a module import.
if (Correction.requiresImport()) {
- NamedDecl *Decl = Correction.getCorrectionDecl();
+ NamedDecl *Decl = Correction.getFoundDecl();
assert(Decl && "import required but no declaration to import");
diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl,
@@ -4924,7 +4971,7 @@
<< CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint());
NamedDecl *ChosenDecl =
- Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl();
+ Correction.isKeyword() ? nullptr : Correction.getFoundDecl();
if (PrevNote.getDiagID() && ChosenDecl)
Diag(ChosenDecl->getLocation(), PrevNote)
<< CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo);
@@ -4952,3 +4999,12 @@
void Sema::clearDelayedTypo(TypoExpr *TE) {
DelayedTypos.erase(TE);
}
+
+void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) {
+ DeclarationNameInfo Name(II, IILoc);
+ LookupResult R(*this, Name, LookupAnyName, Sema::NotForRedeclaration);
+ R.suppressDiagnostics();
+ R.setHideTags(false);
+ LookupName(R, S);
+ R.dump();
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 6006776..c9d2da8 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -153,13 +153,26 @@
return 0;
}
+static const unsigned OwnershipMask =
+ (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_weak |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
static unsigned getOwnershipRule(unsigned attr) {
- return attr & (ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_weak |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ unsigned result = attr & OwnershipMask;
+
+ // From an ownership perspective, assign and unsafe_unretained are
+ // identical; make sure one also implies the other.
+ if (result & (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained)) {
+ result |= ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ }
+
+ return result;
}
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
@@ -168,7 +181,6 @@
ObjCDeclSpec &ODS,
Selector GetterSel,
Selector SetterSel,
- bool *isOverridingProperty,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC) {
unsigned Attributes = ODS.getPropertyAttributes();
@@ -182,19 +194,6 @@
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
- // Property defaults to 'assign' if it is readwrite, unless this is ARC
- // and the type is retainable.
- bool isAssign;
- if (Attributes & (ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained)) {
- isAssign = true;
- } else if (getOwnershipRule(Attributes) || !isReadWrite) {
- isAssign = false;
- } else {
- isAssign = (!getLangOpts().ObjCAutoRefCount ||
- !T->isObjCRetainableType());
- }
-
// Proceed with constructing the ObjCPropertyDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
ObjCPropertyDecl *Res = nullptr;
@@ -202,11 +201,10 @@
if (CDecl->IsClassExtension()) {
Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
FD, GetterSel, SetterSel,
- isAssign, isReadWrite,
+ isReadWrite,
Attributes,
ODS.getPropertyAttributes(),
- isOverridingProperty, T, TSI,
- MethodImplKind);
+ T, TSI, MethodImplKind);
if (!Res)
return nullptr;
}
@@ -214,7 +212,7 @@
if (!Res) {
Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
- GetterSel, SetterSel, isAssign, isReadWrite,
+ GetterSel, SetterSel, isReadWrite,
Attributes, ODS.getPropertyAttributes(),
T, TSI, MethodImplKind);
if (lexicalDC)
@@ -305,6 +303,8 @@
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
}
@@ -339,17 +339,84 @@
}
+/// Check for a mismatch in the atomicity of the given properties.
+static void checkAtomicPropertyMismatch(Sema &S,
+ ObjCPropertyDecl *OldProperty,
+ ObjCPropertyDecl *NewProperty,
+ bool PropagateAtomicity) {
+ // If the atomicity of both matches, we're done.
+ bool OldIsAtomic =
+ (OldProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ == 0;
+ bool NewIsAtomic =
+ (NewProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ == 0;
+ if (OldIsAtomic == NewIsAtomic) return;
+
+ // Determine whether the given property is readonly and implicitly
+ // atomic.
+ auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
+ // Is it readonly?
+ auto Attrs = Property->getPropertyAttributes();
+ if ((Attrs & ObjCPropertyDecl::OBJC_PR_readonly) == 0) return false;
+
+ // Is it nonatomic?
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) return false;
+
+ // Was 'atomic' specified directly?
+ if (Property->getPropertyAttributesAsWritten() &
+ ObjCPropertyDecl::OBJC_PR_atomic)
+ return false;
+
+ return true;
+ };
+
+ // If we're allowed to propagate atomicity, and the new property did
+ // not specify atomicity at all, propagate.
+ const unsigned AtomicityMask =
+ (ObjCPropertyDecl::OBJC_PR_atomic | ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if (PropagateAtomicity &&
+ ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {
+ unsigned Attrs = NewProperty->getPropertyAttributes();
+ Attrs = Attrs & ~AtomicityMask;
+ if (OldIsAtomic)
+ Attrs |= ObjCPropertyDecl::OBJC_PR_atomic;
+ else
+ Attrs |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+
+ NewProperty->overwritePropertyAttributes(Attrs);
+ return;
+ }
+
+ // One of the properties is atomic; if it's a readonly property, and
+ // 'atomic' wasn't explicitly specified, we're okay.
+ if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) ||
+ (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty)))
+ return;
+
+ // Diagnose the conflict.
+ const IdentifierInfo *OldContextName;
+ auto *OldDC = OldProperty->getDeclContext();
+ if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC))
+ OldContextName = Category->getClassInterface()->getIdentifier();
+ else
+ OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier();
+
+ S.Diag(NewProperty->getLocation(), diag::warn_property_attribute)
+ << NewProperty->getDeclName() << "atomic"
+ << OldContextName;
+ S.Diag(OldProperty->getLocation(), diag::note_property_declare);
+}
+
ObjCPropertyDecl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel, Selector SetterSel,
- const bool isAssign,
const bool isReadWrite,
- const unsigned Attributes,
+ unsigned &Attributes,
const unsigned AttributesAsWritten,
- bool *isOverridingProperty,
QualType T,
TypeSourceInfo *TSI,
tok::ObjCKeywordKind MethodImplKind) {
@@ -363,14 +430,16 @@
// already declared.
if (!CCPrimary) {
Diag(CDecl->getLocation(), diag::err_continuation_class);
- *isOverridingProperty = true;
return nullptr;
}
+ bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
+ (Attributes & ObjCDeclSpec::DQ_PR_class);
+
// Find the property in the extended class's primary class or
// extensions.
- ObjCPropertyDecl *PIDecl =
- CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
+ ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(
+ PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));
// If we found a property in an extension, complain.
if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
@@ -379,11 +448,73 @@
return nullptr;
}
+ // Check for consistency with the previous declaration, if there is one.
+ if (PIDecl) {
+ // A readonly property declared in the primary class can be refined
+ // by adding a readwrite property within an extension.
+ // Anything else is an error.
+ if (!(PIDecl->isReadOnly() && isReadWrite)) {
+ // Tailor the diagnostics for the common case where a readwrite
+ // property is declared both in the @interface and the continuation.
+ // This is a common error where the user often intended the original
+ // declaration to be readonly.
+ unsigned diag =
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite) &&
+ (PIDecl->getPropertyAttributesAsWritten() &
+ ObjCPropertyDecl::OBJC_PR_readwrite)
+ ? diag::err_use_continuation_class_redeclaration_readwrite
+ : diag::err_use_continuation_class;
+ Diag(AtLoc, diag)
+ << CCPrimary->getDeclName();
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return nullptr;
+ }
+
+ // Check for consistency of getters.
+ if (PIDecl->getGetterName() != GetterSel) {
+ // If the getter was written explicitly, complain.
+ if (AttributesAsWritten & ObjCDeclSpec::DQ_PR_getter) {
+ Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
+ << PIDecl->getGetterName() << GetterSel;
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+
+ // Always adopt the getter from the original declaration.
+ GetterSel = PIDecl->getGetterName();
+ Attributes |= ObjCDeclSpec::DQ_PR_getter;
+ }
+
+ // Check consistency of ownership.
+ unsigned ExistingOwnership
+ = getOwnershipRule(PIDecl->getPropertyAttributes());
+ unsigned NewOwnership = getOwnershipRule(Attributes);
+ if (ExistingOwnership && NewOwnership != ExistingOwnership) {
+ // If the ownership was written explicitly, complain.
+ if (getOwnershipRule(AttributesAsWritten)) {
+ Diag(AtLoc, diag::warn_property_attr_mismatch);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+
+ // Take the ownership from the original property.
+ Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership;
+ }
+
+ // If the redeclaration is 'weak' but the original property is not,
+ if ((Attributes & ObjCPropertyDecl::OBJC_PR_weak) &&
+ !(PIDecl->getPropertyAttributesAsWritten()
+ & ObjCPropertyDecl::OBJC_PR_weak) &&
+ PIDecl->getType()->getAs<ObjCObjectPointerType>() &&
+ PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {
+ Diag(AtLoc, diag::warn_property_implicitly_mismatched);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ }
+
// Create a new ObjCPropertyDecl with the DeclContext being
// the class extension.
ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
FD, GetterSel, SetterSel,
- isAssign, isReadWrite,
+ isReadWrite,
Attributes, AttributesAsWritten,
T, TSI, MethodImplKind, DC);
@@ -416,70 +547,10 @@
return nullptr;
}
}
-
- // A readonly property declared in the primary class can be refined
- // by adding a rewrite property within an extension.
- // Anything else is an error.
- unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
- if (!(isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly))) {
- // Tailor the diagnostics for the common case where a readwrite
- // property is declared both in the @interface and the continuation.
- // This is a common error where the user often intended the original
- // declaration to be readonly.
- unsigned diag =
- (Attributes & ObjCDeclSpec::DQ_PR_readwrite) &&
- (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite)
- ? diag::err_use_continuation_class_redeclaration_readwrite
- : diag::err_use_continuation_class;
- Diag(AtLoc, diag)
- << CCPrimary->getDeclName();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- return nullptr;
- }
-
- PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
- PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
- PIkind |= deducePropertyOwnershipFromType(*this, PIDecl->getType());
- unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
- unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
- if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
- (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
- Diag(AtLoc, diag::warn_property_attr_mismatch);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- } else if (getLangOpts().ObjCAutoRefCount) {
- QualType PrimaryPropertyQT =
- Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
- if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
- bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0);
- Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
- PrimaryPropertyQT.getObjCLifetime();
- if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
- !PropertyIsWeak) {
- Diag(AtLoc, diag::warn_property_implicitly_mismatched);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- }
- }
// Check that atomicity of property in class extension matches the previous
// declaration.
- unsigned PDeclAtomicity =
- PDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
- unsigned PIDeclAtomicity =
- PIDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
- if (PDeclAtomicity != PIDeclAtomicity) {
- bool PDeclAtomic = (!PDeclAtomicity || PDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
- bool PIDeclAtomic = (!PIDeclAtomicity || PIDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
- if (PDeclAtomic != PIDeclAtomic) {
- Diag(PDecl->getLocation(), diag::warn_property_attribute)
- << PDecl->getDeclName() << "atomic"
- << cast<ObjCContainerDecl>(PIDecl->getDeclContext())->getName();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- }
-
- *isOverridingProperty = true;
+ checkAtomicPropertyMismatch(*this, PIDecl, PDecl, true);
// Make sure getter/setter are appropriately synthesized.
ProcessPropertyDecl(PDecl);
@@ -493,7 +564,6 @@
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
- const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -503,10 +573,23 @@
DeclContext *lexicalDC){
IdentifierInfo *PropertyId = FD.D.getIdentifier();
- // Issue a warning if property is 'assign' as default and its object, which is
- // gc'able conforms to NSCopying protocol
+ // Property defaults to 'assign' if it is readwrite, unless this is ARC
+ // and the type is retainable.
+ bool isAssign;
+ if (Attributes & (ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained)) {
+ isAssign = true;
+ } else if (getOwnershipRule(Attributes) || !isReadWrite) {
+ isAssign = false;
+ } else {
+ isAssign = (!getLangOpts().ObjCAutoRefCount ||
+ !T->isObjCRetainableType());
+ }
+
+ // Issue a warning if property is 'assign' as default and its
+ // object, which is gc'able conforms to NSCopying protocol
if (getLangOpts().getGC() != LangOptions::NonGC &&
- isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) {
if (const ObjCObjectPointerType *ObjPtrTy =
T->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
@@ -516,6 +599,7 @@
if (IDecl->ClassImplementsProtocol(PNSCopying, true))
Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
+ }
if (T->isObjCObjectType()) {
SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd();
@@ -533,8 +617,11 @@
PropertyId, AtLoc,
LParenLoc, T, TInfo);
- if (ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
+ bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
+ (Attributes & ObjCDeclSpec::DQ_PR_class);
+ // Class property and instance property can have the same name.
+ if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
+ DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
Diag(PDecl->getLocation(), diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
PDecl->setInvalidDecl();
@@ -612,6 +699,9 @@
if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+
return PDecl;
}
@@ -767,6 +857,39 @@
S.Diag(AtLoc, diag::note_property_synthesize);
}
+/// Determine whether any storage attributes were written on the property.
+static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
+ ObjCPropertyQueryKind QueryKind) {
+ if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;
+
+ // If this is a readwrite property in a class extension that refines
+ // a readonly property in the original class definition, check it as
+ // well.
+
+ // If it's a readonly property, we're not interested.
+ if (Prop->isReadOnly()) return false;
+
+ // Is it declared in an extension?
+ auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext());
+ if (!Category || !Category->IsClassExtension()) return false;
+
+ // Find the corresponding property in the primary class definition.
+ auto OrigClass = Category->getClassInterface();
+ for (auto Found : OrigClass->lookup(Prop->getDeclName())) {
+ if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
+ return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
+ }
+
+ // Look through all of the protocols.
+ for (const auto *Proto : OrigClass->all_referenced_protocols()) {
+ if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(
+ Prop->getIdentifier(), QueryKind))
+ return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
+ }
+
+ return false;
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
/// as \@synthesize or \@dynamic.
@@ -777,7 +900,8 @@
bool Synthesize,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar,
- SourceLocation PropertyIvarLoc) {
+ SourceLocation PropertyIvarLoc,
+ ObjCPropertyQueryKind QueryKind) {
ObjCContainerDecl *ClassImpDecl =
dyn_cast<ObjCContainerDecl>(CurContext);
// Make sure we have a context for the property implementation declaration.
@@ -804,11 +928,15 @@
"ActOnPropertyImplDecl - @implementation without @interface");
// Look for this property declaration in the @implementation's @interface
- property = IDecl->FindPropertyDeclaration(PropertyId);
+ property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);
if (!property) {
Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
return nullptr;
}
+ if (property->isClassProperty() && Synthesize) {
+ Diag(PropertyLoc, diag::error_synthesize_on_class_property) << PropertyId;
+ return nullptr;
+ }
unsigned PIkind = property->getPropertyAttributesAsWritten();
if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic |
ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) {
@@ -882,7 +1010,7 @@
if (!Category)
return nullptr;
// Look for this property declaration in @implementation's category
- property = Category->FindPropertyDeclaration(PropertyId);
+ property = Category->FindPropertyDeclaration(PropertyId, QueryKind);
if (!property) {
Diag(PropertyLoc, diag::error_bad_category_property_decl)
<< Category->getDeclName();
@@ -994,7 +1122,7 @@
// It's an error if we have to do this and the user didn't
// explicitly write an ownership attribute on the property.
- if (!property->hasWrittenStorageAttribute() &&
+ if (!hasWrittenStorageAttribute(property, QueryKind) &&
!(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
Diag(PropertyDiagLoc,
diag::err_arc_objc_property_default_assign_on_object);
@@ -1229,7 +1357,7 @@
}
if (ObjCPropertyImplDecl *PPIDecl
- = IC->FindPropertyImplDecl(PropertyId)) {
+ = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return nullptr;
@@ -1268,7 +1396,7 @@
}
if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplDecl(PropertyId)) {
+ CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {
Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return nullptr;
@@ -1326,12 +1454,10 @@
}
}
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "atomic" << inheritedName;
- Diag(SuperProperty->getLocation(), diag::note_property_declare);
- }
+ // Check for nonatomic; note that nonatomic is effectively
+ // meaningless for readonly properties, so don't diagnose if the
+ // atomic property is 'readonly'.
+ checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
if (Property->getSetterName() != SuperProperty->getSetterName()) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "setter" << inheritedName;
@@ -1372,12 +1498,11 @@
QualType PropertyIvarType = property->getType().getNonReferenceType();
bool compat = Context.hasSameType(PropertyIvarType, GetterType);
if (!compat) {
- if (isa<ObjCObjectPointerType>(PropertyIvarType) &&
- isa<ObjCObjectPointerType>(GetterType))
- compat =
- Context.canAssignObjCInterfaces(
- GetterType->getAs<ObjCObjectPointerType>(),
- PropertyIvarType->getAs<ObjCObjectPointerType>());
+ const ObjCObjectPointerType *propertyObjCPtr = nullptr;
+ const ObjCObjectPointerType *getterObjCPtr = nullptr;
+ if ((propertyObjCPtr = PropertyIvarType->getAs<ObjCObjectPointerType>()) &&
+ (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
+ compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)
!= Compatible) {
Diag(Loc, diag::error_property_accessor_type)
@@ -1414,7 +1539,8 @@
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (auto *Prop : IDecl->properties())
- PropMap[Prop->getIdentifier()] = Prop;
+ PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
+ Prop;
// Collect the properties from visible extensions.
for (auto *Ext : IDecl->visible_extensions())
@@ -1428,7 +1554,8 @@
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (auto *Prop : CATDecl->properties())
- PropMap[Prop->getIdentifier()] = Prop;
+ PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
+ Prop;
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : CATDecl->protocols())
@@ -1437,12 +1564,16 @@
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (auto *Prop : PDecl->properties()) {
- ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
+ ObjCPropertyDecl *PropertyFromSuper =
+ SuperPropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
// Exclude property for protocols which conform to class's super-class,
// as super-class has to implement the property.
if (!PropertyFromSuper ||
PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
- ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ ObjCPropertyDecl *&PropEntry =
+ PropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
if (!PropEntry)
PropEntry = Prop;
}
@@ -1482,7 +1613,7 @@
// look up a property declaration whose one of its accessors is implemented
// by this method.
- for (const auto *Property : IFace->properties()) {
+ for (const auto *Property : IFace->instance_properties()) {
if ((Property->getGetterName() == IMD->getSelector() ||
Property->getSetterName() == IMD->getSelector()) &&
(Property->getPropertyIvarDecl() == IV))
@@ -1491,7 +1622,7 @@
// Also look up property declaration in class extension whose one of its
// accessors is implemented by this method.
for (const auto *Ext : IFace->known_extensions())
- for (const auto *Property : Ext->properties())
+ for (const auto *Property : Ext->instance_properties())
if ((Property->getGetterName() == IMD->getSelector() ||
Property->getSetterName() == IMD->getSelector()) &&
(Property->getPropertyIvarDecl() == IV))
@@ -1537,10 +1668,12 @@
ObjCPropertyDecl *Prop = PropertyOrder[i];
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
+ Prop->isClassProperty() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
// Property may have been synthesized by user.
- if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
+ if (IMPDecl->FindPropertyImplDecl(
+ Prop->getIdentifier(), Prop->getQueryKind()))
continue;
if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
@@ -1556,7 +1689,9 @@
Diag(PID->getLocation(), diag::note_property_synthesize);
continue;
}
- ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
+ ObjCPropertyDecl *PropInSuperClass =
+ SuperPropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
if (ObjCProtocolDecl *Proto =
dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
// We won't auto-synthesize properties declared in protocols.
@@ -1599,7 +1734,7 @@
true,
/* property = */ Prop->getIdentifier(),
/* ivar = */ Prop->getDefaultSynthIvarName(Context),
- Prop->getLocation()));
+ Prop->getLocation(), Prop->getQueryKind()));
if (PIDecl) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
@@ -1632,7 +1767,8 @@
// the class is going to implement them.
if (!SMap.count(Method) &&
(PrimaryClass == nullptr ||
- !PrimaryClass->lookupPropertyAccessor(Method, C))) {
+ !PrimaryClass->lookupPropertyAccessor(Method, C,
+ Prop->isClassProperty()))) {
S.Diag(IMPDecl->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
diag::warn_setter_getter_impl_required_in_category :
@@ -1699,9 +1835,11 @@
// Add the properties of 'PDecl' to the list of properties that
// need to be implemented.
for (auto *PropDecl : PDecl->properties()) {
- if ((*LazyMap)[PropDecl->getIdentifier()])
+ if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),
+ PropDecl->isClassProperty())])
continue;
- PropMap[PropDecl->getIdentifier()] = PropDecl;
+ PropMap[std::make_pair(PropDecl->getIdentifier(),
+ PropDecl->isClassProperty())] = PropDecl;
}
}
}
@@ -1715,7 +1853,7 @@
SelectorSet InsMap;
// Collect property accessors implemented in current implementation.
- for (const auto *I : IMPDecl->instance_methods())
+ for (const auto *I : IMPDecl->methods())
InsMap.insert(I->getSelector());
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
@@ -1727,7 +1865,7 @@
// When reporting on missing setter/getters, do not report when
// setter/getter is implemented in category's primary class
// implementation.
- for (const auto *I : IMP->instance_methods())
+ for (const auto *I : IMP->methods())
InsMap.insert(I->getSelector());
}
@@ -1786,13 +1924,13 @@
return;
ObjCContainerDecl::PropertyMap PM;
for (auto *Prop : IDecl->properties())
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
for (const auto *Ext : IDecl->known_extensions())
for (auto *Prop : Ext->properties())
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
- I != E; ++I) {
+ for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
+ I != E; ++I) {
const ObjCPropertyDecl *Property = I->second;
ObjCMethodDecl *GetterMethod = nullptr;
ObjCMethodDecl *SetterMethod = nullptr;
@@ -1803,8 +1941,12 @@
if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) &&
!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
- GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
+ GetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getGetterName()) :
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ SetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getSetterName()) :
+ IMPDecl->getInstanceMethod(Property->getSetterName());
LookedUpGetterSetter = true;
if (GetterMethod) {
Diag(GetterMethod->getLocation(),
@@ -1824,13 +1966,17 @@
if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
!(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
continue;
- if (const ObjCPropertyImplDecl *PIDecl
- = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
+ if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
+ Property->getIdentifier(), Property->getQueryKind())) {
if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!LookedUpGetterSetter) {
- GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
+ GetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getGetterName()) :
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ SetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getSetterName()) :
+ IMPDecl->getInstanceMethod(Property->getSetterName());
}
if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
SourceLocation MethodLoc =
@@ -1873,6 +2019,7 @@
for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !PD->isClassProperty() &&
!D->getInstanceMethod(PD->getGetterName())) {
ObjCMethodDecl *method = PD->getGetterMethodDecl();
if (!method)
@@ -1978,20 +2125,30 @@
if (CD->isInvalidDecl())
return;
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
+ bool IsClassProperty = property->isClassProperty();
+ GetterMethod = IsClassProperty ?
+ CD->getClassMethod(property->getGetterName()) :
+ CD->getInstanceMethod(property->getGetterName());
+
// if setter or getter is not found in class extension, it might be
// in the primary class.
if (!GetterMethod)
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
if (CatDecl->IsClassExtension())
- GetterMethod = CatDecl->getClassInterface()->
+ GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
+ getClassMethod(property->getGetterName()) :
+ CatDecl->getClassInterface()->
getInstanceMethod(property->getGetterName());
- SetterMethod = CD->getInstanceMethod(property->getSetterName());
+ SetterMethod = IsClassProperty ?
+ CD->getClassMethod(property->getSetterName()) :
+ CD->getInstanceMethod(property->getSetterName());
if (!SetterMethod)
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
if (CatDecl->IsClassExtension())
- SetterMethod = CatDecl->getClassInterface()->
+ SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
+ getClassMethod(property->getSetterName()) :
+ CatDecl->getClassInterface()->
getInstanceMethod(property->getSetterName());
DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
@@ -2022,7 +2179,7 @@
// (which is odd, but allowed). Sema should be typechecking that the
// declarations jive in that situation (which it is not currently).
if (!GetterMethod) {
- // No instance method of same name as property getter name was found.
+ // No instance/class method of same name as property getter name was found.
// Declare a getter method and add it to the list of methods
// for this class.
SourceLocation Loc = property->getLocation();
@@ -2042,7 +2199,7 @@
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
resultTy, nullptr, CD,
- /*isInstance=*/true, /*isVariadic=*/false,
+ !IsClassProperty, /*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -2078,7 +2235,8 @@
if (!property->isReadOnly()) {
// Find the default setter and if one not found, add one.
if (!SetterMethod) {
- // No instance method of same name as property setter name was found.
+ // No instance/class method of same name as property setter name was
+ // found.
// Declare a setter method and add it to the list of methods
// for this class.
SourceLocation Loc = property->getLocation();
@@ -2086,7 +2244,7 @@
SetterMethod =
ObjCMethodDecl::Create(Context, Loc, Loc,
property->getSetterName(), Context.VoidTy,
- nullptr, CD, /*isInstance=*/true,
+ nullptr, CD, !IsClassProperty,
/*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
@@ -2149,10 +2307,12 @@
// double bar = [foo bar];
// }
//
- if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
+ if (!IsClassProperty) {
+ if (GetterMethod)
+ AddInstanceMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddInstanceMethodToGlobalPool(SetterMethod);
+ }
ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
if (!CurrentClass) {
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 705e6f5..4d0d313 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -77,6 +77,11 @@
ImplicitDSALoc() {}
};
+public:
+ struct MapInfo {
+ Expr *RefExpr;
+ };
+
private:
struct DSAInfo {
OpenMPClauseKind Attributes;
@@ -84,12 +89,16 @@
};
typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;
- typedef llvm::DenseSet<VarDecl *> LoopControlVariablesSetTy;
+ typedef llvm::DenseMap<VarDecl *, unsigned> LoopControlVariablesMapTy;
+ typedef llvm::SmallDenseMap<VarDecl *, MapInfo, 64> MappedDeclsTy;
+ typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>>
+ CriticalsWithHintsTy;
struct SharingMapTy {
DeclSAMapTy SharingMap;
AlignedMapTy AlignedMap;
- LoopControlVariablesSetTy LCVSet;
+ MappedDeclsTy MappedDecls;
+ LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr;
SourceLocation DefaultAttrLoc;
OpenMPDirectiveKind Directive;
@@ -102,19 +111,19 @@
llvm::PointerIntPair<Expr *, 1, bool> OrderedRegion;
bool NowaitRegion;
bool CancelRegion;
- unsigned CollapseNumber;
+ unsigned AssociatedLoops;
SourceLocation InnerTeamsRegionLoc;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
- : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified),
+ : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified),
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false),
- CancelRegion(false), CollapseNumber(1), InnerTeamsRegionLoc() {}
+ CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {}
SharingMapTy()
- : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified),
+ : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified),
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
ConstructLoc(), OrderedRegion(), NowaitRegion(false),
- CancelRegion(false), CollapseNumber(1), InnerTeamsRegionLoc() {}
+ CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {}
};
typedef SmallVector<SharingMapTy, 64> StackTy;
@@ -126,6 +135,7 @@
OpenMPClauseKind ClauseKindMode;
Sema &SemaRef;
bool ForceCapturing;
+ CriticalsWithHintsTy Criticals;
typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;
@@ -156,6 +166,16 @@
Stack.pop_back();
}
+ void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) {
+ Criticals[D->getDirectiveName().getAsString()] = std::make_pair(D, Hint);
+ }
+ const std::pair<OMPCriticalDirective *, llvm::APSInt>
+ getCriticalWithHint(const DeclarationNameInfo &Name) const {
+ auto I = Criticals.find(Name.getAsString());
+ if (I != Criticals.end())
+ return I->second;
+ return std::make_pair(nullptr, llvm::APSInt());
+ }
/// \brief If 'aligned' declaration for given variable \a D was not seen yet,
/// add it and return NULL; otherwise return previous occurrence's expression
/// for diagnostics.
@@ -165,7 +185,17 @@
void addLoopControlVariable(VarDecl *D);
/// \brief Check if the specified variable is a loop control variable for
/// current region.
- bool isLoopControlVariable(VarDecl *D);
+ /// \return The index of the loop control variable in the list of associated
+ /// for-loops (from outer to inner).
+ unsigned isLoopControlVariable(VarDecl *D);
+ /// \brief Check if the specified variable is a loop control variable for
+ /// parent region.
+ /// \return The index of the loop control variable in the list of associated
+ /// for-loops (from outer to inner).
+ unsigned isParentLoopControlVariable(VarDecl *D);
+ /// \brief Get the loop control variable for the I-th loop (or nullptr) in
+ /// parent directive.
+ VarDecl *getParentLoopControlVariable(unsigned I);
/// \brief Adds explicit data sharing attribute to the specified declaration.
void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);
@@ -215,6 +245,8 @@
return Stack[Stack.size() - 2].Directive;
return OMPD_unknown;
}
+ /// \brief Return the directive associated with the provided scope.
+ OpenMPDirectiveKind getDirectiveForScope(const Scope *S) const;
/// \brief Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
@@ -281,11 +313,9 @@
}
/// \brief Set collapse value for the region.
- void setCollapseNumber(unsigned Val) { Stack.back().CollapseNumber = Val; }
+ void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; }
/// \brief Return collapse value for region.
- unsigned getCollapseNumber() const {
- return Stack.back().CollapseNumber;
- }
+ unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; }
/// \brief Marks current target region as one with closely nested teams
/// region.
@@ -307,10 +337,37 @@
Scope *getCurScope() const { return Stack.back().CurScope; }
Scope *getCurScope() { return Stack.back().CurScope; }
SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
+
+ MapInfo getMapInfoForVar(VarDecl *VD) {
+ MapInfo VarMI = {0};
+ for (auto Cnt = Stack.size() - 1; Cnt > 0; --Cnt) {
+ if (Stack[Cnt].MappedDecls.count(VD)) {
+ VarMI = Stack[Cnt].MappedDecls[VD];
+ break;
+ }
+ }
+ return VarMI;
+ }
+
+ void addMapInfoForVar(VarDecl *VD, MapInfo MI) {
+ if (Stack.size() > 1) {
+ Stack.back().MappedDecls[VD] = MI;
+ }
+ }
+
+ MapInfo IsMappedInCurrentRegion(VarDecl *VD) {
+ assert(Stack.size() > 1 && "Target level is 0");
+ MapInfo VarMI = {0};
+ if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) {
+ VarMI = Stack.back().MappedDecls[VD];
+ }
+ return VarMI;
+ }
};
bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
return isOpenMPParallelDirective(DKind) || DKind == OMPD_task ||
- isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown;
+ isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown ||
+ isOpenMPTaskLoopDirective(DKind);
}
} // namespace
@@ -437,13 +494,32 @@
void DSAStackTy::addLoopControlVariable(VarDecl *D) {
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
D = D->getCanonicalDecl();
- Stack.back().LCVSet.insert(D);
+ Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1));
}
-bool DSAStackTy::isLoopControlVariable(VarDecl *D) {
+unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) {
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
D = D->getCanonicalDecl();
- return Stack.back().LCVSet.count(D) > 0;
+ return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0;
+}
+
+unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) {
+ assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
+ D = D->getCanonicalDecl();
+ return Stack[Stack.size() - 2].LCVMap.count(D) > 0
+ ? Stack[Stack.size() - 2].LCVMap[D]
+ : 0;
+}
+
+VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
+ assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
+ if (Stack[Stack.size() - 2].LCVMap.size() < I)
+ return nullptr;
+ for (auto &Pair : Stack[Stack.size() - 2].LCVMap) {
+ if (Pair.second == I)
+ return Pair.first;
+ }
+ return nullptr;
}
void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
@@ -529,41 +605,20 @@
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++, predetermined, p.1]
- // Variables with automatic storage duration that are declared in a scope
- // inside the construct are private.
- OpenMPDirectiveKind Kind =
- FromParent ? getParentDirective() : getCurrentDirective();
- auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
- StartI = std::next(StartI);
- }
- if (!isParallelOrTaskRegion(Kind)) {
- if (isOpenMPLocal(D, StartI) &&
- ((D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto ||
- D->getStorageClass() == SC_None)) ||
- isa<ParmVarDecl>(D))) {
- DVar.CKind = OMPC_private;
+ // in a Construct, C/C++, predetermined, p.4]
+ // Static data members are shared.
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.7]
+ // Variables with static storage duration that are declared in a scope
+ // inside the construct are shared.
+ if (D->isStaticDataMember()) {
+ DSAVarData DVarTemp =
+ hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent);
+ if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
return DVar;
- }
- // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++, predetermined, p.4]
- // Static data members are shared.
- // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++, predetermined, p.7]
- // Variables with static storage duration that are declared in a scope
- // inside the construct are shared.
- if (D->isStaticDataMember()) {
- DSAVarData DVarTemp =
- hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent);
- if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
- return DVar;
-
- DVar.CKind = OMPC_shared;
- return DVar;
- }
+ DVar.CKind = OMPC_shared;
+ return DVar;
}
QualType Type = D->getType().getNonReferenceType().getCanonicalType();
@@ -575,6 +630,9 @@
// shared.
CXXRecordDecl *RD =
SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
+ if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD))
+ if (auto *CTD = CTSD->getSpecializedTemplate())
+ RD = CTD->getTemplatedDecl();
if (IsConstant &&
!(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
// Variables with const-qualified type having no mutable member may be
@@ -590,6 +648,11 @@
// Explicitly specified attributes and local variables with predetermined
// attributes.
+ auto StartI = std::next(Stack.rbegin());
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
auto I = std::prev(StartI);
if (I->SharingMap.count(D)) {
DVar.RefExpr = I->SharingMap[D].RefExpr;
@@ -695,12 +758,107 @@
return false;
}
+OpenMPDirectiveKind DSAStackTy::getDirectiveForScope(const Scope *S) const {
+ for (auto I = Stack.rbegin(), EE = Stack.rend(); I != EE; ++I)
+ if (I->CurScope == S)
+ return I->Directive;
+ return OMPD_unknown;
+}
+
void Sema::InitDataSharingAttributesStack() {
VarDataSharingAttributesStack = new DSAStackTy(*this);
}
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
+bool Sema::IsOpenMPCapturedByRef(VarDecl *VD,
+ const CapturedRegionScopeInfo *RSI) {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+
+ auto &Ctx = getASTContext();
+ bool IsByRef = true;
+
+ // Find the directive that is associated with the provided scope.
+ auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope);
+ auto Ty = VD->getType();
+
+ if (isOpenMPTargetDirective(DKind)) {
+ // This table summarizes how a given variable should be passed to the device
+ // given its type and the clauses where it appears. This table is based on
+ // the description in OpenMP 4.5 [2.10.4, target Construct] and
+ // OpenMP 4.5 [2.15.5, Data-mapping Attribute Rules and Clauses].
+ //
+ // =========================================================================
+ // | type | defaultmap | pvt | first | is_device_ptr | map | res. |
+ // | |(tofrom:scalar)| | pvt | | | |
+ // =========================================================================
+ // | scl | | | | - | | bycopy|
+ // | scl | | - | x | - | - | bycopy|
+ // | scl | | x | - | - | - | null |
+ // | scl | x | | | - | | byref |
+ // | scl | x | - | x | - | - | bycopy|
+ // | scl | x | x | - | - | - | null |
+ // | scl | | - | - | - | x | byref |
+ // | scl | x | - | - | - | x | byref |
+ //
+ // | agg | n.a. | | | - | | byref |
+ // | agg | n.a. | - | x | - | - | byref |
+ // | agg | n.a. | x | - | - | - | null |
+ // | agg | n.a. | - | - | - | x | byref |
+ // | agg | n.a. | - | - | - | x[] | byref |
+ //
+ // | ptr | n.a. | | | - | | bycopy|
+ // | ptr | n.a. | - | x | - | - | bycopy|
+ // | ptr | n.a. | x | - | - | - | null |
+ // | ptr | n.a. | - | - | - | x | byref |
+ // | ptr | n.a. | - | - | - | x[] | bycopy|
+ // | ptr | n.a. | - | - | x | | bycopy|
+ // | ptr | n.a. | - | - | x | x | bycopy|
+ // | ptr | n.a. | - | - | x | x[] | bycopy|
+ // =========================================================================
+ // Legend:
+ // scl - scalar
+ // ptr - pointer
+ // agg - aggregate
+ // x - applies
+ // - - invalid in this combination
+ // [] - mapped with an array section
+ // byref - should be mapped by reference
+ // byval - should be mapped by value
+ // null - initialize a local variable to null on the device
+ //
+ // Observations:
+ // - All scalar declarations that show up in a map clause have to be passed
+ // by reference, because they may have been mapped in the enclosing data
+ // environment.
+ // - If the scalar value does not fit the size of uintptr, it has to be
+ // passed by reference, regardless the result in the table above.
+ // - For pointers mapped by value that have either an implicit map or an
+ // array section, the runtime library may pass the NULL value to the
+ // device instead of the value passed to it by the compiler.
+
+ // FIXME: Right now, only implicit maps are implemented. Properly mapping
+ // values requires having the map, private, and firstprivate clauses SEMA
+ // and parsing in place, which we don't yet.
+
+ if (Ty->isReferenceType())
+ Ty = Ty->castAs<ReferenceType>()->getPointeeType();
+ IsByRef = !Ty->isScalarType();
+ }
+
+ // When passing data by value, we need to make sure it fits the uintptr size
+ // and alignment, because the runtime library only deals with uintptr types.
+ // If it does not fit the uintptr size, we need to pass the data by reference
+ // instead.
+ if (!IsByRef &&
+ (Ctx.getTypeSizeInChars(Ty) >
+ Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) ||
+ Ctx.getDeclAlign(VD) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType())))
+ IsByRef = true;
+
+ return IsByRef;
+}
+
bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
VD = VD->getCanonicalDecl();
@@ -983,7 +1141,7 @@
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
- return DeclGroupPtrTy();
+ return nullptr;
}
namespace {
@@ -1421,6 +1579,30 @@
Params);
break;
}
+ case OMPD_taskloop: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_taskloop_simd: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_distribute: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
@@ -1440,6 +1622,10 @@
ActOnCapturedRegionError();
return StmtError();
}
+
+ OMPOrderedClause *OC = nullptr;
+ OMPScheduleClause *SC = nullptr;
+ SmallVector<OMPLinearClause *, 4> LCs;
// This is required for proper codegen.
for (auto *Clause : Clauses) {
if (isOpenMPPrivate(Clause->getClauseKind()) ||
@@ -1461,10 +1647,49 @@
// Required for proper codegen of combined directives.
// TODO: add processing for other clauses.
if (auto *E = cast_or_null<Expr>(
- cast<OMPScheduleClause>(Clause)->getHelperChunkSize())) {
- MarkDeclarationsReferencedInExpr(E);
- }
+ cast<OMPScheduleClause>(Clause)->getHelperChunkSize()))
+ MarkDeclarationsReferencedInExpr(E);
}
+ if (Clause->getClauseKind() == OMPC_schedule)
+ SC = cast<OMPScheduleClause>(Clause);
+ else if (Clause->getClauseKind() == OMPC_ordered)
+ OC = cast<OMPOrderedClause>(Clause);
+ else if (Clause->getClauseKind() == OMPC_linear)
+ LCs.push_back(cast<OMPLinearClause>(Clause));
+ }
+ bool ErrorFound = false;
+ // OpenMP, 2.7.1 Loop Construct, Restrictions
+ // The nonmonotonic modifier cannot be specified if an ordered clause is
+ // specified.
+ if (SC &&
+ (SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
+ SC->getSecondScheduleModifier() ==
+ OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
+ OC) {
+ Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
+ ? SC->getFirstScheduleModifierLoc()
+ : SC->getSecondScheduleModifierLoc(),
+ diag::err_omp_schedule_nonmonotonic_ordered)
+ << SourceRange(OC->getLocStart(), OC->getLocEnd());
+ ErrorFound = true;
+ }
+ if (!LCs.empty() && OC && OC->getNumForLoops()) {
+ for (auto *C : LCs) {
+ Diag(C->getLocStart(), diag::err_omp_linear_ordered)
+ << SourceRange(OC->getLocStart(), OC->getLocEnd());
+ }
+ ErrorFound = true;
+ }
+ if (isOpenMPWorksharingDirective(DSAStack->getCurrentDirective()) &&
+ isOpenMPSimdDirective(DSAStack->getCurrentDirective()) && OC &&
+ OC->getNumForLoops()) {
+ Diag(OC->getLocStart(), diag::err_omp_ordered_simd)
+ << getOpenMPDirectiveName(DSAStack->getCurrentDirective());
+ ErrorFound = true;
+ }
+ if (ErrorFound) {
+ ActOnCapturedRegionError();
+ return StmtError();
}
return ActOnCapturedRegionEnd(S.get());
}
@@ -1503,6 +1728,9 @@
// | parallel | cancellation | |
// | | point | ! |
// | parallel | cancel | ! |
+ // | parallel | taskloop | * |
+ // | parallel | taskloop simd | * |
+ // | parallel | distribute | |
// +------------------+-----------------+------------------------------------+
// | for | parallel | * |
// | for | for | + |
@@ -1529,6 +1757,9 @@
// | for | cancellation | |
// | | point | ! |
// | for | cancel | ! |
+ // | for | taskloop | * |
+ // | for | taskloop simd | * |
+ // | for | distribute | |
// +------------------+-----------------+------------------------------------+
// | master | parallel | * |
// | master | for | + |
@@ -1555,6 +1786,9 @@
// | master | cancellation | |
// | | point | |
// | master | cancel | |
+ // | master | taskloop | * |
+ // | master | taskloop simd | * |
+ // | master | distribute | |
// +------------------+-----------------+------------------------------------+
// | critical | parallel | * |
// | critical | for | + |
@@ -1580,6 +1814,9 @@
// | critical | cancellation | |
// | | point | |
// | critical | cancel | |
+ // | critical | taskloop | * |
+ // | critical | taskloop simd | * |
+ // | critical | distribute | |
// +------------------+-----------------+------------------------------------+
// | simd | parallel | |
// | simd | for | |
@@ -1606,6 +1843,9 @@
// | simd | cancellation | |
// | | point | |
// | simd | cancel | |
+ // | simd | taskloop | |
+ // | simd | taskloop simd | |
+ // | simd | distribute | |
// +------------------+-----------------+------------------------------------+
// | for simd | parallel | |
// | for simd | for | |
@@ -1632,6 +1872,9 @@
// | for simd | cancellation | |
// | | point | |
// | for simd | cancel | |
+ // | for simd | taskloop | |
+ // | for simd | taskloop simd | |
+ // | for simd | distribute | |
// +------------------+-----------------+------------------------------------+
// | parallel for simd| parallel | |
// | parallel for simd| for | |
@@ -1658,6 +1901,9 @@
// | parallel for simd| cancellation | |
// | | point | |
// | parallel for simd| cancel | |
+ // | parallel for simd| taskloop | |
+ // | parallel for simd| taskloop simd | |
+ // | parallel for simd| distribute | |
// +------------------+-----------------+------------------------------------+
// | sections | parallel | * |
// | sections | for | + |
@@ -1684,6 +1930,9 @@
// | sections | cancellation | |
// | | point | ! |
// | sections | cancel | ! |
+ // | sections | taskloop | * |
+ // | sections | taskloop simd | * |
+ // | sections | distribute | |
// +------------------+-----------------+------------------------------------+
// | section | parallel | * |
// | section | for | + |
@@ -1710,6 +1959,9 @@
// | section | cancellation | |
// | | point | ! |
// | section | cancel | ! |
+ // | section | taskloop | * |
+ // | section | taskloop simd | * |
+ // | section | distribute | |
// +------------------+-----------------+------------------------------------+
// | single | parallel | * |
// | single | for | + |
@@ -1736,6 +1988,9 @@
// | single | cancellation | |
// | | point | |
// | single | cancel | |
+ // | single | taskloop | * |
+ // | single | taskloop simd | * |
+ // | single | distribute | |
// +------------------+-----------------+------------------------------------+
// | parallel for | parallel | * |
// | parallel for | for | + |
@@ -1762,6 +2017,9 @@
// | parallel for | cancellation | |
// | | point | ! |
// | parallel for | cancel | ! |
+ // | parallel for | taskloop | * |
+ // | parallel for | taskloop simd | * |
+ // | parallel for | distribute | |
// +------------------+-----------------+------------------------------------+
// | parallel sections| parallel | * |
// | parallel sections| for | + |
@@ -1788,6 +2046,9 @@
// | parallel sections| cancellation | |
// | | point | ! |
// | parallel sections| cancel | ! |
+ // | parallel sections| taskloop | * |
+ // | parallel sections| taskloop simd | * |
+ // | parallel sections| distribute | |
// +------------------+-----------------+------------------------------------+
// | task | parallel | * |
// | task | for | + |
@@ -1814,6 +2075,9 @@
// | task | cancellation | |
// | | point | ! |
// | task | cancel | ! |
+ // | task | taskloop | * |
+ // | task | taskloop simd | * |
+ // | task | distribute | |
// +------------------+-----------------+------------------------------------+
// | ordered | parallel | * |
// | ordered | for | + |
@@ -1840,6 +2104,9 @@
// | ordered | cancellation | |
// | | point | |
// | ordered | cancel | |
+ // | ordered | taskloop | * |
+ // | ordered | taskloop simd | * |
+ // | ordered | distribute | |
// +------------------+-----------------+------------------------------------+
// | atomic | parallel | |
// | atomic | for | |
@@ -1866,6 +2133,9 @@
// | atomic | cancellation | |
// | | point | |
// | atomic | cancel | |
+ // | atomic | taskloop | |
+ // | atomic | taskloop simd | |
+ // | atomic | distribute | |
// +------------------+-----------------+------------------------------------+
// | target | parallel | * |
// | target | for | * |
@@ -1892,6 +2162,9 @@
// | target | cancellation | |
// | | point | |
// | target | cancel | |
+ // | target | taskloop | * |
+ // | target | taskloop simd | * |
+ // | target | distribute | |
// +------------------+-----------------+------------------------------------+
// | teams | parallel | * |
// | teams | for | + |
@@ -1918,6 +2191,95 @@
// | teams | cancellation | |
// | | point | |
// | teams | cancel | |
+ // | teams | taskloop | + |
+ // | teams | taskloop simd | + |
+ // | teams | distribute | ! |
+ // +------------------+-----------------+------------------------------------+
+ // | taskloop | parallel | * |
+ // | taskloop | for | + |
+ // | taskloop | for simd | + |
+ // | taskloop | master | + |
+ // | taskloop | critical | * |
+ // | taskloop | simd | * |
+ // | taskloop | sections | + |
+ // | taskloop | section | + |
+ // | taskloop | single | + |
+ // | taskloop | parallel for | * |
+ // | taskloop |parallel for simd| * |
+ // | taskloop |parallel sections| * |
+ // | taskloop | task | * |
+ // | taskloop | taskyield | * |
+ // | taskloop | barrier | + |
+ // | taskloop | taskwait | * |
+ // | taskloop | taskgroup | * |
+ // | taskloop | flush | * |
+ // | taskloop | ordered | + |
+ // | taskloop | atomic | * |
+ // | taskloop | target | * |
+ // | taskloop | teams | + |
+ // | taskloop | cancellation | |
+ // | | point | |
+ // | taskloop | cancel | |
+ // | taskloop | taskloop | * |
+ // | taskloop | distribute | |
+ // +------------------+-----------------+------------------------------------+
+ // | taskloop simd | parallel | |
+ // | taskloop simd | for | |
+ // | taskloop simd | for simd | |
+ // | taskloop simd | master | |
+ // | taskloop simd | critical | |
+ // | taskloop simd | simd | |
+ // | taskloop simd | sections | |
+ // | taskloop simd | section | |
+ // | taskloop simd | single | |
+ // | taskloop simd | parallel for | |
+ // | taskloop simd |parallel for simd| |
+ // | taskloop simd |parallel sections| |
+ // | taskloop simd | task | |
+ // | taskloop simd | taskyield | |
+ // | taskloop simd | barrier | |
+ // | taskloop simd | taskwait | |
+ // | taskloop simd | taskgroup | |
+ // | taskloop simd | flush | |
+ // | taskloop simd | ordered | + (with simd clause) |
+ // | taskloop simd | atomic | |
+ // | taskloop simd | target | |
+ // | taskloop simd | teams | |
+ // | taskloop simd | cancellation | |
+ // | | point | |
+ // | taskloop simd | cancel | |
+ // | taskloop simd | taskloop | |
+ // | taskloop simd | taskloop simd | |
+ // | taskloop simd | distribute | |
+ // +------------------+-----------------+------------------------------------+
+ // | distribute | parallel | * |
+ // | distribute | for | * |
+ // | distribute | for simd | * |
+ // | distribute | master | * |
+ // | distribute | critical | * |
+ // | distribute | simd | * |
+ // | distribute | sections | * |
+ // | distribute | section | * |
+ // | distribute | single | * |
+ // | distribute | parallel for | * |
+ // | distribute |parallel for simd| * |
+ // | distribute |parallel sections| * |
+ // | distribute | task | * |
+ // | distribute | taskyield | * |
+ // | distribute | barrier | * |
+ // | distribute | taskwait | * |
+ // | distribute | taskgroup | * |
+ // | distribute | flush | * |
+ // | distribute | ordered | + |
+ // | distribute | atomic | * |
+ // | distribute | target | |
+ // | distribute | teams | |
+ // | distribute | cancellation | + |
+ // | | point | |
+ // | distribute | cancel | + |
+ // | distribute | taskloop | * |
+ // | distribute | taskloop simd | * |
+ // | distribute | distribute | |
// +------------------+-----------------+------------------------------------+
if (Stack->getCurScope()) {
auto ParentRegion = Stack->getParentDirective();
@@ -1927,7 +2289,8 @@
NoRecommend,
ShouldBeInParallelRegion,
ShouldBeInOrderedRegion,
- ShouldBeInTargetRegion
+ ShouldBeInTargetRegion,
+ ShouldBeInTeamsRegion
} Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
@@ -1988,7 +2351,8 @@
// A master region may not be closely nested inside a worksharing,
// atomic, or explicit task region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
- ParentRegion == OMPD_task;
+ ParentRegion == OMPD_task ||
+ isOpenMPTaskLoopDirective(ParentRegion);
} else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
// OpenMP [2.16, Nesting of Regions]
// A critical region may not be nested (closely or otherwise) inside a
@@ -2025,7 +2389,8 @@
NestingProhibited =
isOpenMPWorksharingDirective(ParentRegion) ||
ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
+ ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered ||
+ isOpenMPTaskLoopDirective(ParentRegion);
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
!isOpenMPParallelDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
@@ -2034,7 +2399,8 @@
NestingProhibited =
isOpenMPWorksharingDirective(ParentRegion) ||
ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
+ ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered ||
+ isOpenMPTaskLoopDirective(ParentRegion);
Recommend = ShouldBeInParallelRegion;
} else if (CurrentRegion == OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
@@ -2047,6 +2413,7 @@
// that can appear in the simd region.
NestingProhibited = ParentRegion == OMPD_critical ||
ParentRegion == OMPD_task ||
+ isOpenMPTaskLoopDirective(ParentRegion) ||
!(isOpenMPSimdDirective(ParentRegion) ||
Stack->isParentOrderedRegion());
Recommend = ShouldBeInOrderedRegion;
@@ -2063,10 +2430,17 @@
// distribute, parallel, parallel sections, parallel workshare, and the
// parallel loop and parallel loop SIMD constructs are the only OpenMP
// constructs that can be closely nested in the teams region.
- // TODO: add distribute directive.
- NestingProhibited = !isOpenMPParallelDirective(CurrentRegion);
+ NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) &&
+ !isOpenMPDistributeDirective(CurrentRegion);
Recommend = ShouldBeInParallelRegion;
}
+ if (!NestingProhibited && isOpenMPDistributeDirective(CurrentRegion)) {
+ // OpenMP 4.5 [2.17 Nesting of Regions]
+ // The region associated with the distribute construct must be strictly
+ // nested inside a teams region
+ NestingProhibited = !isOpenMPTeamsDirective(ParentRegion);
+ Recommend = ShouldBeInTeamsRegion;
+ }
if (NestingProhibited) {
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
<< CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend
@@ -2233,9 +2607,8 @@
Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc);
break;
case OMPD_critical:
- assert(ClausesWithImplicit.empty() &&
- "No clauses are allowed for 'omp critical' directive");
- Res = ActOnOpenMPCriticalDirective(DirName, AStmt, StartLoc, EndLoc);
+ Res = ActOnOpenMPCriticalDirective(DirName, ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
break;
case OMPD_parallel_for:
Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc,
@@ -2324,6 +2697,20 @@
EndLoc);
AllowedNameModifiers.push_back(OMPD_target_data);
break;
+ case OMPD_taskloop:
+ Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_taskloop_simd:
+ Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_distribute:
+ Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ break;
case OMPD_threadprivate:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
@@ -3051,14 +3438,13 @@
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
assert(getLangOpts().OpenMP && "OpenMP is not active.");
assert(Init && "Expected loop in canonical form.");
- unsigned CollapseIteration = DSAStack->getCollapseNumber();
- if (CollapseIteration > 0 &&
+ unsigned AssociatedLoops = DSAStack->getAssociatedLoops();
+ if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
OpenMPIterationSpaceChecker ISC(*this, ForLoc);
- if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) {
+ if (!ISC.CheckInit(Init, /*EmitDiags=*/false))
DSAStack->addLoopControlVariable(ISC.GetLoopVar());
- }
- DSAStack->setCollapseNumber(CollapseIteration - 1);
+ DSAStack->setAssociatedLoops(AssociatedLoops - 1);
}
}
@@ -3151,12 +3537,12 @@
? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
: OMPC_private;
if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_threadprivate && DVar.CKind != PredeterminedCKind) ||
- (isOpenMPWorksharingDirective(DKind) && !isOpenMPSimdDirective(DKind) &&
- DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private &&
- DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_threadprivate)) &&
- ((DVar.CKind != OMPC_private && DVar.CKind != OMPC_threadprivate) ||
- DVar.RefExpr != nullptr)) {
+ DVar.CKind != PredeterminedCKind) ||
+ ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
+ isOpenMPDistributeDirective(DKind)) &&
+ !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(PredeterminedCKind);
@@ -3189,7 +3575,9 @@
// Build the loop's iteration space representation.
ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond());
ResultIterSpace.NumIterations = ISC.BuildNumIterations(
- DSA.getCurScope(), /* LimitedType */ isOpenMPWorksharingDirective(DKind));
+ DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)));
ResultIterSpace.CounterVar = ISC.BuildCounterVar();
ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar();
ResultIterSpace.CounterInit = ISC.BuildCounterInit();
@@ -3326,13 +3714,22 @@
// Found 'collapse' clause - calculate collapse number.
llvm::APSInt Result;
if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
- NestedLoopCount += Result.getLimitedValue() - 1;
+ NestedLoopCount = Result.getLimitedValue();
}
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
llvm::APSInt Result;
- if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
- NestedLoopCount += Result.getLimitedValue() - 1;
+ if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) {
+ if (Result.getLimitedValue() < NestedLoopCount) {
+ SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
+ diag::err_omp_wrong_ordered_loop_count)
+ << OrderedLoopCountExpr->getSourceRange();
+ SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(),
+ diag::note_collapse_loop_count)
+ << CollapseLoopCountExpr->getSourceRange();
+ }
+ NestedLoopCount = Result.getLimitedValue();
+ }
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
@@ -3488,7 +3885,8 @@
QualType VType = LastIteration.get()->getType();
// Build variables passed into runtime, nesessary for worksharing directives.
ExprResult LB, UB, IL, ST, EUB;
- if (isOpenMPWorksharingDirective(DKind)) {
+ if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)) {
// Lower bound variable, initialized with zero.
VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb");
LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc);
@@ -3536,7 +3934,9 @@
{
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv");
IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc);
- Expr *RHS = isOpenMPWorksharingDirective(DKind)
+ Expr *RHS = (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind))
? LB.get()
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
@@ -3546,7 +3946,8 @@
// Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
SourceLocation CondLoc;
ExprResult Cond =
- isOpenMPWorksharingDirective(DKind)
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))
? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
@@ -3566,7 +3967,8 @@
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
// Used for directives with static scheduling.
ExprResult NextLB, NextUB;
- if (isOpenMPWorksharingDirective(DKind)) {
+ if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)) {
// LB + ST
NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get());
if (!NextLB.isUsable())
@@ -3981,19 +4383,62 @@
return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt);
}
-StmtResult
-Sema::ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName,
- Stmt *AStmt, SourceLocation StartLoc,
- SourceLocation EndLoc) {
+StmtResult Sema::ActOnOpenMPCriticalDirective(
+ const DeclarationNameInfo &DirName, ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ bool ErrorFound = false;
+ llvm::APSInt Hint;
+ SourceLocation HintLoc;
+ bool DependentHint = false;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_hint) {
+ if (!DirName.getName()) {
+ Diag(C->getLocStart(), diag::err_omp_hint_clause_no_name);
+ ErrorFound = true;
+ }
+ Expr *E = cast<OMPHintClause>(C)->getHint();
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ E->isInstantiationDependent())
+ DependentHint = true;
+ else {
+ Hint = E->EvaluateKnownConstInt(Context);
+ HintLoc = C->getLocStart();
+ }
+ }
+ }
+ if (ErrorFound)
+ return StmtError();
+ auto Pair = DSAStack->getCriticalWithHint(DirName);
+ if (Pair.first && DirName.getName() && !DependentHint) {
+ if (llvm::APSInt::compareValues(Hint, Pair.second) != 0) {
+ Diag(StartLoc, diag::err_omp_critical_with_hint);
+ if (HintLoc.isValid()) {
+ Diag(HintLoc, diag::note_omp_critical_hint_here)
+ << 0 << Hint.toString(/*Radix=*/10, /*Signed=*/false);
+ } else
+ Diag(StartLoc, diag::note_omp_critical_no_hint) << 0;
+ if (auto *C = Pair.first->getSingleClause<OMPHintClause>()) {
+ Diag(C->getLocStart(), diag::note_omp_critical_hint_here)
+ << 1
+ << C->getHint()->EvaluateKnownConstInt(Context).toString(
+ /*Radix=*/10, /*Signed=*/false);
+ } else
+ Diag(Pair.first->getLocStart(), diag::note_omp_critical_no_hint) << 1;
+ }
+ }
+
getCurFunction()->setHasBranchProtectedScope();
- return OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc,
- AStmt);
+ auto *Dir = OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc,
+ Clauses, AStmt);
+ if (!Pair.first && DirName.getName() && !DependentHint)
+ DSAStack->addCriticalWithHint(Dir, Hint);
+ return Dir;
}
StmtResult Sema::ActOnOpenMPParallelForDirective(
@@ -4196,36 +4641,72 @@
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- if (!AStmt)
- return StmtError();
-
- assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
-
- getCurFunction()->setHasBranchProtectedScope();
-
+ OMPClause *DependFound = nullptr;
+ OMPClause *DependSourceClause = nullptr;
+ OMPClause *DependSinkClause = nullptr;
+ bool ErrorFound = false;
OMPThreadsClause *TC = nullptr;
OMPSIMDClause *SC = nullptr;
- for (auto *C: Clauses) {
- if (C->getClauseKind() == OMPC_threads)
+ for (auto *C : Clauses) {
+ if (auto *DC = dyn_cast<OMPDependClause>(C)) {
+ DependFound = C;
+ if (DC->getDependencyKind() == OMPC_DEPEND_source) {
+ if (DependSourceClause) {
+ Diag(C->getLocStart(), diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(OMPD_ordered)
+ << getOpenMPClauseName(OMPC_depend) << 2;
+ ErrorFound = true;
+ } else
+ DependSourceClause = C;
+ if (DependSinkClause) {
+ Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed)
+ << 0;
+ ErrorFound = true;
+ }
+ } else if (DC->getDependencyKind() == OMPC_DEPEND_sink) {
+ if (DependSourceClause) {
+ Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed)
+ << 1;
+ ErrorFound = true;
+ }
+ DependSinkClause = C;
+ }
+ } else if (C->getClauseKind() == OMPC_threads)
TC = cast<OMPThreadsClause>(C);
else if (C->getClauseKind() == OMPC_simd)
SC = cast<OMPSIMDClause>(C);
}
-
- // TODO: this must happen only if 'threads' clause specified or if no clauses
- // is specified.
- if (auto *Param = DSAStack->getParentOrderedRegionParam()) {
- SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc;
- Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr);
- Diag(Param->getLocStart(), diag::note_omp_ordered_param);
- return StmtError();
- }
- if (!SC && isOpenMPSimdDirective(DSAStack->getParentDirective())) {
+ if (!ErrorFound && !SC &&
+ isOpenMPSimdDirective(DSAStack->getParentDirective())) {
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
Diag(StartLoc, diag::err_omp_prohibited_region_simd);
+ ErrorFound = true;
+ } else if (DependFound && (TC || SC)) {
+ Diag(DependFound->getLocStart(), diag::err_omp_depend_clause_thread_simd)
+ << getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind());
+ ErrorFound = true;
+ } else if (DependFound && !DSAStack->getParentOrderedRegionParam()) {
+ Diag(DependFound->getLocStart(),
+ diag::err_omp_ordered_directive_without_param);
+ ErrorFound = true;
+ } else if (TC || Clauses.empty()) {
+ if (auto *Param = DSAStack->getParentOrderedRegionParam()) {
+ SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc;
+ Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
+ << (TC != nullptr);
+ Diag(Param->getLocStart(), diag::note_omp_ordered_param);
+ ErrorFound = true;
+ }
+ }
+ if ((!AStmt && !DependFound) || ErrorFound)
return StmtError();
+
+ if (AStmt) {
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
}
return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
@@ -4909,7 +5390,13 @@
if (!AStmt)
return StmtError();
- assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
@@ -5025,6 +5512,120 @@
CancelRegion);
}
+static bool checkGrainsizeNumTasksClauses(Sema &S,
+ ArrayRef<OMPClause *> Clauses) {
+ OMPClause *PrevClause = nullptr;
+ bool ErrorFound = false;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_grainsize ||
+ C->getClauseKind() == OMPC_num_tasks) {
+ if (!PrevClause)
+ PrevClause = C;
+ else if (PrevClause->getClauseKind() != C->getClauseKind()) {
+ S.Diag(C->getLocStart(),
+ diag::err_omp_grainsize_num_tasks_mutually_exclusive)
+ << getOpenMPClauseName(C->getClauseKind())
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ S.Diag(PrevClause->getLocStart(),
+ diag::note_omp_previous_grainsize_num_tasks)
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ ErrorFound = true;
+ }
+ }
+ }
+ return ErrorFound;
+}
+
+StmtResult Sema::ActOnOpenMPTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPDistributeDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses),
+ nullptr /*ordered not a clause on distribute*/, AStmt,
+ *this, *DSAStack, VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPDistributeDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -5052,6 +5653,24 @@
case OMPC_device:
Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_num_teams:
+ Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_thread_limit:
+ Res = ActOnOpenMPThreadLimitClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_priority:
+ Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_grainsize:
+ Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_num_tasks:
+ Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_hint:
+ Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_default:
case OMPC_proc_bind:
@@ -5078,6 +5697,9 @@
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_map:
+ case OMPC_nogroup:
+ case OMPC_dist_schedule:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -5168,38 +5790,52 @@
return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
}
+static bool IsNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
+ OpenMPClauseKind CKind,
+ bool StrictlyPositive) {
+ if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
+ !ValExpr->isInstantiationDependent()) {
+ SourceLocation Loc = ValExpr->getExprLoc();
+ ExprResult Value =
+ SemaRef.PerformOpenMPImplicitIntegerConversion(Loc, ValExpr);
+ if (Value.isInvalid())
+ return false;
+
+ ValExpr = Value.get();
+ // The expression must evaluate to a non-negative integer value.
+ llvm::APSInt Result;
+ if (ValExpr->isIntegerConstantExpr(Result, SemaRef.Context) &&
+ Result.isSigned() &&
+ !((!StrictlyPositive && Result.isNonNegative()) ||
+ (StrictlyPositive && Result.isStrictlyPositive()))) {
+ SemaRef.Diag(Loc, diag::err_omp_negative_expression_in_clause)
+ << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0)
+ << ValExpr->getSourceRange();
+ return false;
+ }
+ }
+ return true;
+}
+
OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumThreads;
- if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() &&
- !NumThreads->containsUnexpandedParameterPack()) {
- SourceLocation NumThreadsLoc = NumThreads->getLocStart();
- ExprResult Val =
- PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads);
- if (Val.isInvalid())
- return nullptr;
- ValExpr = Val.get();
-
- // OpenMP [2.5, Restrictions]
- // The num_threads expression must evaluate to a positive integer value.
- llvm::APSInt Result;
- if (ValExpr->isIntegerConstantExpr(Result, Context) && Result.isSigned() &&
- !Result.isStrictlyPositive()) {
- Diag(NumThreadsLoc, diag::err_omp_negative_expression_in_clause)
- << "num_threads" << NumThreads->getSourceRange();
- return nullptr;
- }
- }
+ // OpenMP [2.5, Restrictions]
+ // The num_threads expression must evaluate to a positive integer value.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads,
+ /*StrictlyPositive=*/true))
+ return nullptr;
return new (Context)
OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
- OpenMPClauseKind CKind) {
+ OpenMPClauseKind CKind,
+ bool StrictlyPositive) {
if (!E)
return ExprError();
if (E->isValueDependent() || E->isTypeDependent() ||
@@ -5209,9 +5845,11 @@
ExprResult ICE = VerifyIntegerConstantExpression(E, &Result);
if (ICE.isInvalid())
return ExprError();
- if (!Result.isStrictlyPositive()) {
+ if ((StrictlyPositive && !Result.isStrictlyPositive()) ||
+ (!StrictlyPositive && !Result.isNonNegative())) {
Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause)
- << getOpenMPClauseName(CKind) << E->getSourceRange();
+ << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0)
+ << E->getSourceRange();
return ExprError();
}
if (CKind == OMPC_aligned && !Result.isPowerOf2()) {
@@ -5219,13 +5857,10 @@
<< E->getSourceRange();
return ExprError();
}
- if (CKind == OMPC_collapse) {
- DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
- Result.getExtValue());
- } else if (CKind == OMPC_ordered) {
- DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
- Result.getExtValue());
- }
+ if (CKind == OMPC_collapse && DSAStack->getAssociatedLoops() == 1)
+ DSAStack->setAssociatedLoops(Result.getExtValue());
+ else if (CKind == OMPC_ordered)
+ DSAStack->setAssociatedLoops(Result.getExtValue());
return ICE;
}
@@ -5340,39 +5975,56 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_map:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_dist_schedule:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
+static std::string
+getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
+ ArrayRef<unsigned> Exclude = llvm::None) {
+ std::string Values;
+ unsigned Bound = Last >= 2 ? Last - 2 : 0;
+ unsigned Skipped = Exclude.size();
+ auto S = Exclude.begin(), E = Exclude.end();
+ for (unsigned i = First; i < Last; ++i) {
+ if (std::find(S, E, i) != E) {
+ --Skipped;
+ continue;
+ }
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(K, i);
+ Values += "'";
+ if (i == Bound - Skipped)
+ Values += " or ";
+ else if (i != Bound + 1 - Skipped)
+ Values += ", ";
+ }
+ return Values;
+}
+
OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_DEFAULT_unknown) {
- std::string Values;
static_assert(OMPC_DEFAULT_unknown > 0,
"OMPC_DEFAULT_unknown not greater than 0");
- std::string Sep(", ");
- for (unsigned i = 0; i < OMPC_DEFAULT_unknown; ++i) {
- Values += "'";
- Values += getOpenMPSimpleClauseTypeName(OMPC_default, i);
- Values += "'";
- switch (i) {
- case OMPC_DEFAULT_unknown - 2:
- Values += " or ";
- break;
- case OMPC_DEFAULT_unknown - 1:
- break;
- default:
- Values += Sep;
- break;
- }
- }
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << Values << getOpenMPClauseName(OMPC_default);
+ << getListOfPossibleValues(OMPC_default, /*First=*/0,
+ /*Last=*/OMPC_DEFAULT_unknown)
+ << getOpenMPClauseName(OMPC_default);
return nullptr;
}
switch (Kind) {
@@ -5396,25 +6048,10 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_PROC_BIND_unknown) {
- std::string Values;
- std::string Sep(", ");
- for (unsigned i = 0; i < OMPC_PROC_BIND_unknown; ++i) {
- Values += "'";
- Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i);
- Values += "'";
- switch (i) {
- case OMPC_PROC_BIND_unknown - 2:
- Values += " or ";
- break;
- case OMPC_PROC_BIND_unknown - 1:
- break;
- default:
- Values += Sep;
- break;
- }
- }
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << Values << getOpenMPClauseName(OMPC_proc_bind);
+ << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0,
+ /*Last=*/OMPC_PROC_BIND_unknown)
+ << getOpenMPClauseName(OMPC_proc_bind);
return nullptr;
}
return new (Context)
@@ -5422,21 +6059,33 @@
}
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
- OpenMPClauseKind Kind, unsigned Argument, Expr *Expr,
+ OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ArgumentLoc, SourceLocation DelimLoc,
+ ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc,
SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_schedule:
+ enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };
+ assert(Argument.size() == NumberOfElements &&
+ ArgumentLoc.size() == NumberOfElements);
Res = ActOnOpenMPScheduleClause(
- static_cast<OpenMPScheduleClauseKind>(Argument), Expr, StartLoc,
- LParenLoc, ArgumentLoc, DelimLoc, EndLoc);
+ static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier1]),
+ static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier2]),
+ static_cast<OpenMPScheduleClauseKind>(Argument[ScheduleKind]), Expr,
+ StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2],
+ ArgumentLoc[ScheduleKind], DelimLoc, EndLoc);
break;
case OMPC_if:
- Res =
- ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument), Expr,
- StartLoc, LParenLoc, ArgumentLoc, DelimLoc, EndLoc);
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
+ Res = ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument.back()),
+ Expr, StartLoc, LParenLoc, ArgumentLoc.back(),
+ DelimLoc, EndLoc);
+ break;
+ case OMPC_dist_schedule:
+ Res = ActOnOpenMPDistScheduleClause(
+ static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc);
break;
case OMPC_final:
case OMPC_num_threads:
@@ -5469,38 +6118,88 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_map:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
+static bool checkScheduleModifiers(Sema &S, OpenMPScheduleClauseModifier M1,
+ OpenMPScheduleClauseModifier M2,
+ SourceLocation M1Loc, SourceLocation M2Loc) {
+ if (M1 == OMPC_SCHEDULE_MODIFIER_unknown && M1Loc.isValid()) {
+ SmallVector<unsigned, 2> Excluded;
+ if (M2 != OMPC_SCHEDULE_MODIFIER_unknown)
+ Excluded.push_back(M2);
+ if (M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic)
+ Excluded.push_back(OMPC_SCHEDULE_MODIFIER_monotonic);
+ if (M2 == OMPC_SCHEDULE_MODIFIER_monotonic)
+ Excluded.push_back(OMPC_SCHEDULE_MODIFIER_nonmonotonic);
+ S.Diag(M1Loc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_schedule,
+ /*First=*/OMPC_SCHEDULE_MODIFIER_unknown + 1,
+ /*Last=*/OMPC_SCHEDULE_MODIFIER_last,
+ Excluded)
+ << getOpenMPClauseName(OMPC_schedule);
+ return true;
+ }
+ return false;
+}
+
OMPClause *Sema::ActOnOpenMPScheduleClause(
+ OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
- SourceLocation EndLoc) {
+ SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc,
+ SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) {
+ if (checkScheduleModifiers(*this, M1, M2, M1Loc, M2Loc) ||
+ checkScheduleModifiers(*this, M2, M1, M2Loc, M1Loc))
+ return nullptr;
+ // OpenMP, 2.7.1, Loop Construct, Restrictions
+ // Either the monotonic modifier or the nonmonotonic modifier can be specified
+ // but not both.
+ if ((M1 == M2 && M1 != OMPC_SCHEDULE_MODIFIER_unknown) ||
+ (M1 == OMPC_SCHEDULE_MODIFIER_monotonic &&
+ M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) ||
+ (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic &&
+ M2 == OMPC_SCHEDULE_MODIFIER_monotonic)) {
+ Diag(M2Loc, diag::err_omp_unexpected_schedule_modifier)
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule, M2)
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule, M1);
+ return nullptr;
+ }
if (Kind == OMPC_SCHEDULE_unknown) {
std::string Values;
- std::string Sep(", ");
- for (unsigned i = 0; i < OMPC_SCHEDULE_unknown; ++i) {
- Values += "'";
- Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i);
- Values += "'";
- switch (i) {
- case OMPC_SCHEDULE_unknown - 2:
- Values += " or ";
- break;
- case OMPC_SCHEDULE_unknown - 1:
- break;
- default:
- Values += Sep;
- break;
- }
+ if (M1Loc.isInvalid() && M2Loc.isInvalid()) {
+ unsigned Exclude[] = {OMPC_SCHEDULE_unknown};
+ Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0,
+ /*Last=*/OMPC_SCHEDULE_MODIFIER_last,
+ Exclude);
+ } else {
+ Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0,
+ /*Last=*/OMPC_SCHEDULE_unknown);
}
Diag(KindLoc, diag::err_omp_unexpected_clause_value)
<< Values << getOpenMPClauseName(OMPC_schedule);
return nullptr;
}
+ // OpenMP, 2.7.1, Loop Construct, Restrictions
+ // The nonmonotonic modifier can only be specified with schedule(dynamic) or
+ // schedule(guided).
+ if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
+ M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
+ Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) {
+ Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc,
+ diag::err_omp_schedule_nonmonotonic_static);
+ return nullptr;
+ }
Expr *ValExpr = ChunkSize;
Expr *HelperValExpr = nullptr;
if (ChunkSize) {
@@ -5522,7 +6221,7 @@
if (ValExpr->isIntegerConstantExpr(Result, Context)) {
if (Result.isSigned() && !Result.isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
- << "schedule" << ChunkSize->getSourceRange();
+ << "schedule" << 1 << ChunkSize->getSourceRange();
return nullptr;
}
} else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
@@ -5536,8 +6235,9 @@
}
}
- return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc,
- EndLoc, Kind, ValExpr, HelperValExpr);
+ return new (Context)
+ OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind,
+ ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc);
}
OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
@@ -5578,6 +6278,9 @@
case OMPC_simd:
Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc);
break;
+ case OMPC_nogroup:
+ Res = ActOnOpenMPNogroupClause(StartLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -5600,6 +6303,14 @@
case OMPC_flush:
case OMPC_depend:
case OMPC_device:
+ case OMPC_map:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_dist_schedule:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -5657,12 +6368,18 @@
return new (Context) OMPSIMDClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPNogroupClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPNogroupClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
- OpenMPLinearClauseKind LinKind, SourceLocation DepLinLoc) {
+ OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
@@ -5683,7 +6400,7 @@
break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
- LinKind, DepLinLoc, ColonLoc, EndLoc);
+ LinKind, DepLinMapLoc, ColonLoc, EndLoc);
break;
case OMPC_aligned:
Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
@@ -5699,8 +6416,12 @@
Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_depend:
- Res = ActOnOpenMPDependClause(DepKind, DepLinLoc, ColonLoc, VarList, StartLoc,
- LParenLoc, EndLoc);
+ Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList,
+ StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_map:
+ Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc,
+ VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
@@ -5724,6 +6445,14 @@
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_dist_schedule:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@@ -6002,6 +6731,49 @@
continue;
}
}
+
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that is private within a teams region must not appear in a
+ // firstprivate clause on a distribute construct if any of the distribute
+ // regions arising from the distribute construct ever bind to any of the
+ // teams regions arising from the teams construct.
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that appears in a reduction clause of a teams construct
+ // must not appear in a firstprivate clause on a distribute construct if
+ // any of the distribute regions arising from the distribute construct
+ // ever bind to any of the teams regions arising from the teams construct.
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
+ if (CurrDir == OMPD_distribute) {
+ DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_private),
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPTeamsDirective(K);
+ },
+ false);
+ if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) {
+ Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPTeamsDirective(K);
+ },
+ false);
+ if (DVar.CKind == OMPC_reduction &&
+ isOpenMPTeamsDirective(DVar.DKind)) {
+ Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind == OMPC_lastprivate) {
+ Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
}
// Variably modified types are not supported for tasks.
@@ -6198,6 +6970,18 @@
if (AssignmentOp.isInvalid())
continue;
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
+ if (CurrDir == OMPD_distribute) {
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind == OMPC_firstprivate) {
+ Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
+
if (TopDVar.CKind != OMPC_firstprivate)
DSAStack->addDSA(VD, DE, OMPC_lastprivate);
Vars.push_back(DE);
@@ -7340,60 +8124,144 @@
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
- if (DepKind == OMPC_DEPEND_unknown) {
- std::string Values;
- std::string Sep(", ");
- for (unsigned i = 0; i < OMPC_DEPEND_unknown; ++i) {
- Values += "'";
- Values += getOpenMPSimpleClauseTypeName(OMPC_depend, i);
- Values += "'";
- switch (i) {
- case OMPC_DEPEND_unknown - 2:
- Values += " or ";
- break;
- case OMPC_DEPEND_unknown - 1:
- break;
- default:
- Values += Sep;
- break;
- }
- }
+ if (DSAStack->getCurrentDirective() == OMPD_ordered &&
+ DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) {
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
- << Values << getOpenMPClauseName(OMPC_depend);
+ << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend);
+ return nullptr;
+ }
+ if (DSAStack->getCurrentDirective() != OMPD_ordered &&
+ (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source ||
+ DepKind == OMPC_DEPEND_sink)) {
+ unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink};
+ Diag(DepLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_depend, /*First=*/0,
+ /*Last=*/OMPC_DEPEND_unknown, Except)
+ << getOpenMPClauseName(OMPC_depend);
return nullptr;
}
SmallVector<Expr *, 8> Vars;
- for (auto &RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP shared clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- continue;
+ llvm::APSInt DepCounter(/*BitWidth=*/32);
+ llvm::APSInt TotalDepCount(/*BitWidth=*/32);
+ if (DepKind == OMPC_DEPEND_sink) {
+ if (auto *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) {
+ TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context);
+ TotalDepCount.setIsUnsigned(/*Val=*/true);
}
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.11.1.1, Restrictions, p.3]
- // A variable that is part of another variable (such as a field of a
- // structure) but is not an array element or an array section cannot appear
- // in a depend clause.
- auto *SimpleExpr = RefExpr->IgnoreParenCasts();
- auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
- auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
- if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
- (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
- (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
- !ASE->getBase()->getType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
- << RefExpr->getSourceRange();
- continue;
- }
-
- Vars.push_back(RefExpr->IgnoreParenImpCasts());
}
+ if ((DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) ||
+ DSAStack->getParentOrderedRegionParam()) {
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr) ||
+ (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
- if (Vars.empty())
- return nullptr;
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ auto *SimpleExpr = RefExpr->IgnoreParenCasts();
+ if (DepKind == OMPC_DEPEND_sink) {
+ if (DepCounter >= TotalDepCount) {
+ Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr);
+ continue;
+ }
+ ++DepCounter;
+ // OpenMP [2.13.9, Summary]
+ // depend(dependence-type : vec), where dependence-type is:
+ // 'sink' and where vec is the iteration vector, which has the form:
+ // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn]
+ // where n is the value specified by the ordered clause in the loop
+ // directive, xi denotes the loop iteration variable of the i-th nested
+ // loop associated with the loop directive, and di is a constant
+ // non-negative integer.
+ SimpleExpr = SimpleExpr->IgnoreImplicit();
+ auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
+ if (!DE) {
+ OverloadedOperatorKind OOK = OO_None;
+ SourceLocation OOLoc;
+ Expr *LHS, *RHS;
+ if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
+ OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
+ OOLoc = BO->getOperatorLoc();
+ LHS = BO->getLHS()->IgnoreParenImpCasts();
+ RHS = BO->getRHS()->IgnoreParenImpCasts();
+ } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
+ OOK = OCE->getOperator();
+ OOLoc = OCE->getOperatorLoc();
+ LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
+ } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
+ OOK = MCE->getMethodDecl()
+ ->getNameInfo()
+ .getName()
+ .getCXXOverloadedOperator();
+ OOLoc = MCE->getCallee()->getExprLoc();
+ LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
+ RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ } else {
+ Diag(ELoc, diag::err_omp_depend_sink_wrong_expr);
+ continue;
+ }
+ DE = dyn_cast<DeclRefExpr>(LHS);
+ if (!DE) {
+ Diag(LHS->getExprLoc(),
+ diag::err_omp_depend_sink_expected_loop_iteration)
+ << DSAStack->getParentLoopControlVariable(
+ DepCounter.getZExtValue());
+ continue;
+ }
+ if (OOK != OO_Plus && OOK != OO_Minus) {
+ Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
+ continue;
+ }
+ ExprResult Res = VerifyPositiveIntegerConstantInClause(
+ RHS, OMPC_depend, /*StrictlyPositive=*/false);
+ if (Res.isInvalid())
+ continue;
+ }
+ auto *VD = dyn_cast<VarDecl>(DE->getDecl());
+ if (!CurContext->isDependentContext() &&
+ DSAStack->getParentOrderedRegionParam() &&
+ (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) {
+ Diag(DE->getExprLoc(),
+ diag::err_omp_depend_sink_expected_loop_iteration)
+ << DSAStack->getParentLoopControlVariable(
+ DepCounter.getZExtValue());
+ continue;
+ }
+ } else {
+ // OpenMP [2.11.1.1, Restrictions, p.3]
+ // A variable that is part of another variable (such as a field of a
+ // structure) but is not an array element or an array section cannot
+ // appear in a depend clause.
+ auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
+ (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
+ (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
+ !ASE->getBase()->getType()->isArrayType())) {
+ Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
+ << RefExpr->getSourceRange();
+ continue;
+ }
+ }
+
+ Vars.push_back(RefExpr->IgnoreParenImpCasts());
+ }
+
+ if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink &&
+ TotalDepCount > VarList.size() &&
+ DSAStack->getParentOrderedRegionParam()) {
+ Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
+ << DSAStack->getParentLoopControlVariable(VarList.size() + 1);
+ }
+ if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
+ Vars.empty())
+ return nullptr;
+ }
return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind,
DepLoc, ColonLoc, Vars);
@@ -7403,22 +8271,335 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Device;
- if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
- !ValExpr->isInstantiationDependent()) {
- SourceLocation Loc = ValExpr->getExprLoc();
- ExprResult Value = PerformOpenMPImplicitIntegerConversion(Loc, ValExpr);
- if (Value.isInvalid())
- return nullptr;
- // OpenMP [2.9.1, Restrictions]
- // The device expression must evaluate to a non-negative integer value.
- llvm::APSInt Result;
- if (Value.get()->isIntegerConstantExpr(Result, Context) &&
- Result.isSigned() && !Result.isStrictlyPositive()) {
- Diag(Loc, diag::err_omp_negative_expression_in_clause)
- << "device" << ValExpr->getSourceRange();
- return nullptr;
+ // OpenMP [2.9.1, Restrictions]
+ // The device expression must evaluate to a non-negative integer value.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
+ /*StrictlyPositive=*/false))
+ return nullptr;
+
+ return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc,
+ DSAStackTy *Stack, CXXRecordDecl *RD) {
+ if (!RD || RD->isInvalidDecl())
+ return true;
+
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ if (auto *CTD = CTSD->getSpecializedTemplate())
+ RD = CTD->getTemplatedDecl();
+ auto QTy = SemaRef.Context.getRecordType(RD);
+ if (RD->isDynamicClass()) {
+ SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
+ SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target);
+ return false;
+ }
+ auto *DC = RD;
+ bool IsCorrect = true;
+ for (auto *I : DC->decls()) {
+ if (I) {
+ if (auto *MD = dyn_cast<CXXMethodDecl>(I)) {
+ if (MD->isStatic()) {
+ SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
+ SemaRef.Diag(MD->getLocation(),
+ diag::note_omp_static_member_in_target);
+ IsCorrect = false;
+ }
+ } else if (auto *VD = dyn_cast<VarDecl>(I)) {
+ if (VD->isStaticDataMember()) {
+ SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
+ SemaRef.Diag(VD->getLocation(),
+ diag::note_omp_static_member_in_target);
+ IsCorrect = false;
+ }
+ }
}
}
- return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+
+ for (auto &I : RD->bases()) {
+ if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack,
+ I.getType()->getAsCXXRecordDecl()))
+ IsCorrect = false;
+ }
+ return IsCorrect;
+}
+
+static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
+ DSAStackTy *Stack, QualType QTy) {
+ NamedDecl *ND;
+ if (QTy->isIncompleteType(&ND)) {
+ SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR;
+ return false;
+ } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) {
+ if (!RD->isInvalidDecl() &&
+ !IsCXXRecordForMappable(SemaRef, SL, Stack, RD))
+ return false;
+ }
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPMapClause(
+ OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType,
+ SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
+ SmallVector<Expr *, 4> Vars;
+
+ for (auto &RE : VarList) {
+ assert(RE && "Null expr in omp map");
+ if (isa<DependentScopeDeclRefExpr>(RE)) {
+ // It will be analyzed later.
+ Vars.push_back(RE);
+ continue;
+ }
+ SourceLocation ELoc = RE->getExprLoc();
+
+ // OpenMP [2.14.5, Restrictions]
+ // A variable that is part of another variable (such as field of a
+ // structure) but is not an array element or an array section cannot appear
+ // in a map clause.
+ auto *VE = RE->IgnoreParenLValueCasts();
+
+ if (VE->isValueDependent() || VE->isTypeDependent() ||
+ VE->isInstantiationDependent() ||
+ VE->containsUnexpandedParameterPack()) {
+ // It will be analyzed later.
+ Vars.push_back(RE);
+ continue;
+ }
+
+ auto *SimpleExpr = RE->IgnoreParenCasts();
+ auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+
+ if (!RE->IgnoreParenImpCasts()->isLValue() ||
+ (!OASE && !ASE && !DE) ||
+ (DE && !isa<VarDecl>(DE->getDecl())) ||
+ (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
+ !ASE->getBase()->getType()->isArrayType())) {
+ Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
+ << RE->getSourceRange();
+ continue;
+ }
+
+ Decl *D = nullptr;
+ if (DE) {
+ D = DE->getDecl();
+ } else if (ASE) {
+ auto *B = ASE->getBase()->IgnoreParenCasts();
+ D = dyn_cast<DeclRefExpr>(B)->getDecl();
+ } else if (OASE) {
+ auto *B = OASE->getBase();
+ D = dyn_cast<DeclRefExpr>(B)->getDecl();
+ }
+ assert(D && "Null decl on map clause.");
+ auto *VD = cast<VarDecl>(D);
+
+ // OpenMP [2.14.5, Restrictions, p.8]
+ // threadprivate variables cannot appear in a map clause.
+ if (DSAStack->isThreadPrivate(VD)) {
+ auto DVar = DSAStack->getTopDSA(VD, false);
+ Diag(ELoc, diag::err_omp_threadprivate_in_map);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+
+ // OpenMP [2.14.5, Restrictions, p.2]
+ // At most one list item can be an array item derived from a given variable
+ // in map clauses of the same construct.
+ // OpenMP [2.14.5, Restrictions, p.3]
+ // List items of map clauses in the same construct must not share original
+ // storage.
+ // OpenMP [2.14.5, Restrictions, C/C++, p.2]
+ // A variable for which the type is pointer, reference to array, or
+ // reference to pointer and an array section derived from that variable
+ // must not appear as list items of map clauses of the same construct.
+ DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD);
+ if (MI.RefExpr) {
+ Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc;
+ Diag(MI.RefExpr->getExprLoc(), diag::note_used_here)
+ << MI.RefExpr->getSourceRange();
+ continue;
+ }
+
+ // OpenMP [2.14.5, Restrictions, C/C++, p.3,4]
+ // A variable for which the type is pointer, reference to array, or
+ // reference to pointer must not appear as a list item if the enclosing
+ // device data environment already contains an array section derived from
+ // that variable.
+ // An array section derived from a variable for which the type is pointer,
+ // reference to array, or reference to pointer must not appear as a list
+ // item if the enclosing device data environment already contains that
+ // variable.
+ QualType Type = VD->getType();
+ MI = DSAStack->getMapInfoForVar(VD);
+ if (MI.RefExpr && (isa<DeclRefExpr>(MI.RefExpr->IgnoreParenLValueCasts()) !=
+ isa<DeclRefExpr>(VE)) &&
+ (Type->isPointerType() || Type->isReferenceType())) {
+ Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc;
+ Diag(MI.RefExpr->getExprLoc(), diag::note_used_here)
+ << MI.RefExpr->getSourceRange();
+ continue;
+ }
+
+ // OpenMP [2.14.5, Restrictions, C/C++, p.7]
+ // A list item must have a mappable type.
+ if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this,
+ DSAStack, Type))
+ continue;
+
+ Vars.push_back(RE);
+ MI.RefExpr = RE;
+ DSAStack->addMapInfoForVar(VD, MI);
+ }
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
+ MapTypeModifier, MapType, MapLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = NumTeams;
+
+ // OpenMP [teams Constrcut, Restrictions]
+ // The num_teams expression must evaluate to a positive integer value.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams,
+ /*StrictlyPositive=*/true))
+ return nullptr;
+
+ return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = ThreadLimit;
+
+ // OpenMP [teams Constrcut, Restrictions]
+ // The thread_limit expression must evaluate to a positive integer value.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit,
+ /*StrictlyPositive=*/true))
+ return nullptr;
+
+ return new (Context) OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc,
+ EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Priority;
+
+ // OpenMP [2.9.1, task Constrcut]
+ // The priority-value is a non-negative numerical scalar expression.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_priority,
+ /*StrictlyPositive=*/false))
+ return nullptr;
+
+ return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Grainsize;
+
+ // OpenMP [2.9.2, taskloop Constrcut]
+ // The parameter of the grainsize clause must be a positive integer
+ // expression.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true))
+ return nullptr;
+
+ return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = NumTasks;
+
+ // OpenMP [2.9.2, taskloop Constrcut]
+ // The parameter of the num_tasks clause must be a positive integer
+ // expression.
+ if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks,
+ /*StrictlyPositive=*/true))
+ return nullptr;
+
+ return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.13.2, critical construct, Description]
+ // ... where hint-expression is an integer constant expression that evaluates
+ // to a valid lock hint.
+ ExprResult HintExpr = VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint);
+ if (HintExpr.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPDistScheduleClause(
+ OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_DIST_SCHEDULE_unknown) {
+ std::string Values;
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0);
+ Values += "'";
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_dist_schedule);
+ return nullptr;
+ }
+ Expr *ValExpr = ChunkSize;
+ Expr *HelperValExpr = nullptr;
+ if (ChunkSize) {
+ if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
+ !ChunkSize->isInstantiationDependent() &&
+ !ChunkSize->containsUnexpandedParameterPack()) {
+ SourceLocation ChunkSizeLoc = ChunkSize->getLocStart();
+ ExprResult Val =
+ PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+
+ // OpenMP [2.7.1, Restrictions]
+ // chunk_size must be a loop invariant integer expression with a positive
+ // value.
+ llvm::APSInt Result;
+ if (ValExpr->isIntegerConstantExpr(Result, Context)) {
+ if (Result.isSigned() && !Result.isStrictlyPositive()) {
+ Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
+ << "dist_schedule" << ChunkSize->getSourceRange();
+ return nullptr;
+ }
+ } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
+ auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(),
+ ChunkSize->getType(), ".chunk.");
+ auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(),
+ ChunkSize->getExprLoc(),
+ /*RefersToCapture=*/true);
+ HelperValExpr = ImpVarRef;
+ }
+ }
+ }
+
+ return new (Context)
+ OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc,
+ Kind, ValExpr, HelperValExpr);
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 8ce3c21..c9293fa 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -38,6 +38,11 @@
using namespace clang;
using namespace sema;
+static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
+ return std::any_of(FD->param_begin(), FD->param_end(),
+ std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
+}
+
/// A convenience routine for creating a decayed reference to a function.
static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
@@ -60,12 +65,8 @@
DRE->setHadMultipleCandidates(true);
S.MarkDeclRefReferenced(DRE);
-
- ExprResult E = DRE;
- E = S.DefaultFunctionArrayConversion(E.get());
- if (E.isInvalid())
- return ExprError();
- return E;
+ return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
+ CK_FunctionToPointerDecay);
}
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
@@ -88,7 +89,7 @@
static ImplicitConversionSequence::CompareKind
-CompareStandardConversionSequences(Sema &S,
+CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
@@ -98,7 +99,7 @@
const StandardConversionSequence& SCS2);
static ImplicitConversionSequence::CompareKind
-CompareDerivedToBaseConversions(Sema &S,
+CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
@@ -257,6 +258,7 @@
case CK_IntegralCast:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
+ case CK_BooleanToSignedIntegral:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
@@ -542,6 +544,12 @@
struct DFIParamWithArguments : DFIArguments {
TemplateParameter Param;
};
+ // Structure used by DeductionFailureInfo to store template argument
+ // information and the index of the problematic call argument.
+ struct DFIDeducedMismatchArgs : DFIArguments {
+ TemplateArgumentList *TemplateArgs;
+ unsigned CallArgIndex;
+ };
}
/// \brief Convert from Sema's representation of template deduction information
@@ -553,13 +561,14 @@
DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
- Result.Data = nullptr;
switch (TDK) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
+ case Sema::TDK_MiscellaneousDeductionFailure:
+ Result.Data = nullptr;
break;
case Sema::TDK_Incomplete:
@@ -567,6 +576,17 @@
Result.Data = Info.Param.getOpaqueValue();
break;
+ case Sema::TDK_DeducedMismatch: {
+ // FIXME: Should allocate from normal heap so that we can free this later.
+ auto *Saved = new (Context) DFIDeducedMismatchArgs;
+ Saved->FirstArg = Info.FirstArg;
+ Saved->SecondArg = Info.SecondArg;
+ Saved->TemplateArgs = Info.take();
+ Saved->CallArgIndex = Info.CallArgIndex;
+ Result.Data = Saved;
+ break;
+ }
+
case Sema::TDK_NonDeducedMismatch: {
// FIXME: Should allocate from normal heap so that we can free this later.
DFIArguments *Saved = new (Context) DFIArguments;
@@ -600,9 +620,6 @@
case Sema::TDK_FailedOverloadResolution:
Result.Data = Info.Expression;
break;
-
- case Sema::TDK_MiscellaneousDeductionFailure:
- break;
}
return Result;
@@ -622,6 +639,7 @@
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
+ case Sema::TDK_DeducedMismatch:
case Sema::TDK_NonDeducedMismatch:
// FIXME: Destroy the data?
Data = nullptr;
@@ -656,6 +674,7 @@
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_DeducedMismatch:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
return TemplateParameter();
@@ -691,6 +710,9 @@
case Sema::TDK_FailedOverloadResolution:
return nullptr;
+ case Sema::TDK_DeducedMismatch:
+ return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs;
+
case Sema::TDK_SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
@@ -717,6 +739,7 @@
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
+ case Sema::TDK_DeducedMismatch:
case Sema::TDK_NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->FirstArg;
@@ -743,6 +766,7 @@
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
+ case Sema::TDK_DeducedMismatch:
case Sema::TDK_NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->SecondArg;
@@ -762,6 +786,14 @@
return nullptr;
}
+llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
+ if (static_cast<Sema::TemplateDeductionResult>(Result) ==
+ Sema::TDK_DeducedMismatch)
+ return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
+
+ return llvm::None;
+}
+
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
@@ -1062,6 +1094,14 @@
return true;
}
+ // Though pass_object_size is placed on parameters and takes an argument, we
+ // consider it to be a function-level modifier for the sake of function
+ // identity. Either the function has one or more parameters with
+ // pass_object_size or it doesn't.
+ if (functionHasPassObjectSizeParams(New) !=
+ functionHasPassObjectSizeParams(Old))
+ return true;
+
// enable_if attributes are an order-sensitive part of the signature.
for (specific_attr_iterator<EnableIfAttr>
NewI = New->specific_attr_begin<EnableIfAttr>(),
@@ -1155,7 +1195,8 @@
QualType ToCanon
= S.Context.getCanonicalType(ToType).getUnqualifiedType();
if (Constructor->isCopyConstructor() &&
- (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
+ (FromCanon == ToCanon ||
+ S.IsDerivedFrom(From->getLocStart(), FromCanon, ToCanon))) {
// Turn this into a "standard" conversion sequence, so that it
// gets ranked with standard conversion sequences.
ICS.setStandard();
@@ -1245,7 +1286,7 @@
QualType FromType = From->getType();
if (ToType->getAs<RecordType>() && FromType->getAs<RecordType>() &&
(S.Context.hasSameUnqualifiedType(FromType, ToType) ||
- S.IsDerivedFrom(FromType, ToType))) {
+ S.IsDerivedFrom(From->getLocStart(), FromType, ToType))) {
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
@@ -1548,6 +1589,11 @@
// Function-to-pointer conversion (C++ 4.3).
SCS.First = ICK_Function_To_Pointer;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(From->IgnoreParenCasts()))
+ if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
+ if (!S.checkAddressOfFunctionIsAvailable(FD))
+ return false;
+
// An lvalue of function type T can be converted to an rvalue of
// type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1).
@@ -1807,7 +1853,7 @@
// We have already pre-calculated the promotion type, so this is trivial.
if (ToType->isIntegerType() &&
- !RequireCompleteType(From->getLocStart(), FromType, 0))
+ isCompleteType(From->getLocStart(), FromType))
return Context.hasSameUnqualifiedType(
ToType, FromEnumType->getDecl()->getPromotionType());
}
@@ -2138,8 +2184,7 @@
if (getLangOpts().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) &&
- !RequireCompleteType(From->getLocStart(), FromPointeeType, 0) &&
- IsDerivedFrom(FromPointeeType, ToPointeeType)) {
+ IsDerivedFrom(From->getLocStart(), FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
@@ -2508,10 +2553,21 @@
ft_parameter_arity,
ft_parameter_mismatch,
ft_return_type,
- ft_qualifer_mismatch,
- ft_addr_enable_if
+ ft_qualifer_mismatch
};
+/// Attempts to get the FunctionProtoType from a Type. Handles
+/// MemberFunctionPointers properly.
+static const FunctionProtoType *tryGetFunctionProtoType(QualType FromType) {
+ if (auto *FPT = FromType->getAs<FunctionProtoType>())
+ return FPT;
+
+ if (auto *MPT = FromType->getAs<MemberPointerType>())
+ return MPT->getPointeeType()->getAs<FunctionProtoType>();
+
+ return nullptr;
+}
+
/// HandleFunctionTypeMismatch - Gives diagnostic information for differeing
/// function types. Catches different number of parameter, mismatch in
/// parameter types, and different return types.
@@ -2558,8 +2614,8 @@
return;
}
- const FunctionProtoType *FromFunction = FromType->getAs<FunctionProtoType>(),
- *ToFunction = ToType->getAs<FunctionProtoType>();
+ const FunctionProtoType *FromFunction = tryGetFunctionProtoType(FromType),
+ *ToFunction = tryGetFunctionProtoType(ToType);
// Both types need to be function types.
if (!FromFunction || !ToFunction) {
@@ -2631,15 +2687,16 @@
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
- bool IgnoreBaseAccess) {
+ bool IgnoreBaseAccess,
+ bool Diagnose) {
QualType FromType = From->getType();
bool IsCStyleOrFunctionalCast = IgnoreBaseAccess;
Kind = CK_BitCast;
- if (!IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
+ if (Diagnose && !IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) ==
- Expr::NPCK_ZeroExpression) {
+ Expr::NPCK_ZeroExpression) {
if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy))
DiagRuntimeBehavior(From->getExprLoc(), From,
PDiag(diag::warn_impcast_bool_to_null_pointer)
@@ -2657,18 +2714,24 @@
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) {
// We must have a derived-to-base conversion. Check an
// ambiguous or inaccessible conversion.
- if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
- From->getExprLoc(),
- From->getSourceRange(), &BasePath,
- IgnoreBaseAccess))
+ unsigned InaccessibleID = 0;
+ unsigned AmbigiousID = 0;
+ if (Diagnose) {
+ InaccessibleID = diag::err_upcast_to_inaccessible_base;
+ AmbigiousID = diag::err_ambiguous_derived_to_base_conv;
+ }
+ if (CheckDerivedToBaseConversion(
+ FromPointeeType, ToPointeeType, InaccessibleID, AmbigiousID,
+ From->getExprLoc(), From->getSourceRange(), DeclarationName(),
+ &BasePath, IgnoreBaseAccess))
return true;
// The conversion was successful.
Kind = CK_DerivedToBase;
}
- if (!IsCStyleOrFunctionalCast && FromPointeeType->isFunctionType() &&
- ToPointeeType->isVoidType()) {
+ if (Diagnose && !IsCStyleOrFunctionalCast &&
+ FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) {
assert(getLangOpts().MSVCCompat &&
"this should only be possible with MSVCCompat!");
Diag(From->getExprLoc(), diag::ext_ms_impcast_fn_obj)
@@ -2734,8 +2797,7 @@
QualType ToClass(ToTypePtr->getClass(), 0);
if (!Context.hasSameUnqualifiedType(FromClass, ToClass) &&
- !RequireCompleteType(From->getLocStart(), ToClass, 0) &&
- IsDerivedFrom(ToClass, FromClass)) {
+ IsDerivedFrom(From->getLocStart(), ToClass, FromClass)) {
ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(),
ToClass.getTypePtr());
return true;
@@ -2778,7 +2840,8 @@
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
- bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
+ bool DerivationOkay =
+ IsDerivedFrom(From->getLocStart(), ToClass, FromClass, Paths);
assert(DerivationOkay &&
"Should not have been called if derivation isn't OK.");
(void)DerivationOkay;
@@ -3057,14 +3120,10 @@
// the parentheses of the initializer.
if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) ||
(From->getType()->getAs<RecordType>() &&
- S.IsDerivedFrom(From->getType(), ToType)))
+ S.IsDerivedFrom(From->getLocStart(), From->getType(), ToType)))
ConstructorsOnly = true;
- S.RequireCompleteType(From->getExprLoc(), ToType, 0);
- // RequireCompleteType may have returned true due to some invalid decl
- // during template instantiation, but ToType may be complete enough now
- // to try to recover.
- if (ToType->isIncompleteType()) {
+ if (!S.isCompleteType(From->getExprLoc(), ToType)) {
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
@@ -3138,7 +3197,7 @@
// Enumerate conversion functions, if we're allowed to.
if (ConstructorsOnly || isa<InitListExpr>(From)) {
- } else if (S.RequireCompleteType(From->getLocStart(), From->getType(), 0)) {
+ } else if (!S.isCompleteType(From->getLocStart(), From->getType())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType
= From->getType()->getAs<RecordType>()) {
@@ -3317,7 +3376,7 @@
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2).
static ImplicitConversionSequence::CompareKind
-CompareImplicitConversionSequences(Sema &S,
+CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2)
{
@@ -3397,7 +3456,7 @@
if (ICS1.isStandard())
// Standard conversion sequence S1 is a better conversion sequence than
// standard conversion sequence S2 if [...]
- Result = CompareStandardConversionSequences(S,
+ Result = CompareStandardConversionSequences(S, Loc,
ICS1.Standard, ICS2.Standard);
else if (ICS1.isUserDefined()) {
// User-defined conversion sequence U1 is a better conversion
@@ -3408,7 +3467,7 @@
// U2 (C++ 13.3.3.2p3).
if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
- Result = CompareStandardConversionSequences(S,
+ Result = CompareStandardConversionSequences(S, Loc,
ICS1.UserDefined.After,
ICS2.UserDefined.After);
else
@@ -3506,7 +3565,7 @@
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
static ImplicitConversionSequence::CompareKind
-CompareStandardConversionSequences(Sema &S,
+CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2)
{
@@ -3562,7 +3621,7 @@
// Neither conversion sequence converts to a void pointer; compare
// their derived-to-base conversions.
if (ImplicitConversionSequence::CompareKind DerivedCK
- = CompareDerivedToBaseConversions(S, SCS1, SCS2))
+ = CompareDerivedToBaseConversions(S, Loc, SCS1, SCS2))
return DerivedCK;
} else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid &&
!S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) {
@@ -3582,9 +3641,9 @@
QualType FromPointee1 = FromType1->getPointeeType().getUnqualifiedType();
QualType FromPointee2 = FromType2->getPointeeType().getUnqualifiedType();
- if (S.IsDerivedFrom(FromPointee2, FromPointee1))
+ if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(FromPointee1, FromPointee2))
+ else if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
// Objective-C++: If one interface is more specific than the
@@ -3792,7 +3851,7 @@
/// [over.ics.rank]p4b3). As part of these checks, we also look at
/// conversions between Objective-C interface types.
static ImplicitConversionSequence::CompareKind
-CompareDerivedToBaseConversions(Sema &S,
+CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
QualType FromType1 = SCS1.getFromType();
@@ -3835,17 +3894,17 @@
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
- if (S.IsDerivedFrom(ToPointee1, ToPointee2))
+ if (S.IsDerivedFrom(Loc, ToPointee1, ToPointee2))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(ToPointee2, ToPointee1))
+ else if (S.IsDerivedFrom(Loc, ToPointee2, ToPointee1))
return ImplicitConversionSequence::Worse;
}
// -- conversion of B* to A* is better than conversion of C* to A*,
if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) {
- if (S.IsDerivedFrom(FromPointee2, FromPointee1))
+ if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(FromPointee1, FromPointee2))
+ else if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
}
} else if (SCS1.Second == ICK_Pointer_Conversion &&
@@ -3942,16 +4001,16 @@
QualType ToPointee2 = QualType(ToPointeeType2, 0).getUnqualifiedType();
// conversion of A::* to B::* is better than conversion of A::* to C::*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
- if (S.IsDerivedFrom(ToPointee1, ToPointee2))
+ if (S.IsDerivedFrom(Loc, ToPointee1, ToPointee2))
return ImplicitConversionSequence::Worse;
- else if (S.IsDerivedFrom(ToPointee2, ToPointee1))
+ else if (S.IsDerivedFrom(Loc, ToPointee2, ToPointee1))
return ImplicitConversionSequence::Better;
}
// conversion of B::* to C::* is better than conversion of A::* to C::*
if (ToPointee1 == ToPointee2 && FromPointee1 != FromPointee2) {
- if (S.IsDerivedFrom(FromPointee1, FromPointee2))
+ if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(FromPointee2, FromPointee1))
+ else if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Worse;
}
}
@@ -3963,9 +4022,9 @@
// reference of type A&,
if (S.Context.hasSameUnqualifiedType(FromType1, FromType2) &&
!S.Context.hasSameUnqualifiedType(ToType1, ToType2)) {
- if (S.IsDerivedFrom(ToType1, ToType2))
+ if (S.IsDerivedFrom(Loc, ToType1, ToType2))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(ToType2, ToType1))
+ else if (S.IsDerivedFrom(Loc, ToType2, ToType1))
return ImplicitConversionSequence::Worse;
}
@@ -3975,9 +4034,9 @@
// reference of type A&,
if (!S.Context.hasSameUnqualifiedType(FromType1, FromType2) &&
S.Context.hasSameUnqualifiedType(ToType1, ToType2)) {
- if (S.IsDerivedFrom(FromType2, FromType1))
+ if (S.IsDerivedFrom(Loc, FromType2, FromType1))
return ImplicitConversionSequence::Better;
- else if (S.IsDerivedFrom(FromType1, FromType2))
+ else if (S.IsDerivedFrom(Loc, FromType1, FromType2))
return ImplicitConversionSequence::Worse;
}
}
@@ -4026,9 +4085,9 @@
ObjCLifetimeConversion = false;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
- } else if (!RequireCompleteType(Loc, OrigT2, 0) &&
+ } else if (isCompleteType(Loc, OrigT2) &&
isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
+ IsDerivedFrom(Loc, UnqualT2, UnqualT1))
DerivedToBase = true;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
@@ -4293,7 +4352,7 @@
// conversion functions (13.3.1.6) and choosing the best
// one through overload resolution (13.3)),
if (!SuppressUserConversions && T2->isRecordType() &&
- !S.RequireCompleteType(DeclLoc, T2, 0) &&
+ S.isCompleteType(DeclLoc, T2) &&
RefRelationship == Sema::Ref_Incompatible) {
if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
Init, T2, /*AllowRvalues=*/false,
@@ -4356,7 +4415,7 @@
// in the second case (or, in either case, to an appropriate base
// class subobject).
if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
- T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) &&
+ T2->isRecordType() && S.isCompleteType(DeclLoc, T2) &&
FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
Init, T2, /*AllowRvalues=*/true,
AllowExplicit)) {
@@ -4494,7 +4553,7 @@
// We need a complete type for what follows. Incomplete types can never be
// initialized from init lists.
- if (S.RequireCompleteType(From->getLocStart(), ToType, 0))
+ if (!S.isCompleteType(From->getLocStart(), ToType))
return Result;
// Per DR1467:
@@ -4511,7 +4570,7 @@
if (ToType->isRecordType()) {
QualType InitType = From->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, ToType) ||
- S.IsDerivedFrom(InitType, ToType))
+ S.IsDerivedFrom(From->getLocStart(), InitType, ToType))
return TryCopyInitialization(S, From->getInit(0), ToType,
SuppressUserConversions,
InOverloadResolution,
@@ -4568,7 +4627,8 @@
}
// Otherwise, look for the worst conversion.
if (Result.isBad() ||
- CompareImplicitConversionSequences(S, ICS, Result) ==
+ CompareImplicitConversionSequences(S, From->getLocStart(), ICS,
+ Result) ==
ImplicitConversionSequence::Worse)
Result = ICS;
}
@@ -4775,7 +4835,7 @@
/// parameter of the given member function (@c Method) from the
/// expression @p From.
static ImplicitConversionSequence
-TryObjectArgumentInitialization(Sema &S, QualType FromType,
+TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType,
Expr::Classification FromClassification,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
@@ -4835,7 +4895,7 @@
ImplicitConversionKind SecondKind;
if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
SecondKind = ICK_Identity;
- } else if (S.IsDerivedFrom(FromType, ClassType))
+ } else if (S.IsDerivedFrom(Loc, FromType, ClassType))
SecondKind = ICK_Derived_To_Base;
else {
ICS.setBad(BadConversionSequence::unrelated_class,
@@ -4910,7 +4970,8 @@
// Note that we always use the true parent context when performing
// the actual argument initialization.
ImplicitConversionSequence ICS = TryObjectArgumentInitialization(
- *this, From->getType(), FromClassification, Method, Method->getParent());
+ *this, From->getLocStart(), From->getType(), FromClassification, Method,
+ Method->getParent());
if (ICS.isBad()) {
if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) {
Qualifiers FromQs = FromRecordType.getQualifiers();
@@ -5426,14 +5487,15 @@
Expr *From;
TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From)
- : TypeDiagnoser(Converter.Suppress), Converter(Converter), From(From) {}
+ : Converter(Converter), From(From) {}
void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
Converter.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
}
} IncompleteDiagnoser(Converter, From);
- if (RequireCompleteType(Loc, T, IncompleteDiagnoser))
+ if (Converter.Suppress ? !isCompleteType(Loc, T)
+ : RequireCompleteType(Loc, T, IncompleteDiagnoser))
return From;
// Look for a conversion to an integral or enumeration type.
@@ -5691,10 +5753,10 @@
// A member function template is never instantiated to perform the copy
// of a class object to an object of its class type.
QualType ClassType = Context.getTypeDeclType(Constructor->getParent());
- if (Args.size() == 1 &&
- Constructor->isSpecializationCopyingObject() &&
+ if (Args.size() == 1 && Constructor->isSpecializationCopyingObject() &&
(Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
- IsDerivedFrom(Args[0]->getType(), ClassType))) {
+ IsDerivedFrom(Args[0]->getLocStart(), Args[0]->getType(),
+ ClassType))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_illegal_constructor;
return;
@@ -6111,9 +6173,9 @@
else {
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[0]
- = TryObjectArgumentInitialization(*this, ObjectType, ObjectClassification,
- Method, ActingContext);
+ Candidate.Conversions[0] = TryObjectArgumentInitialization(
+ *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
+ Method, ActingContext);
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -6370,10 +6432,9 @@
CXXRecordDecl *ConversionContext
= cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl());
- Candidate.Conversions[0]
- = TryObjectArgumentInitialization(*this, From->getType(),
- From->Classify(Context),
- Conversion, ConversionContext);
+ Candidate.Conversions[0] = TryObjectArgumentInitialization(
+ *this, CandidateSet.getLocation(), From->getType(),
+ From->Classify(Context), Conversion, ConversionContext);
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
@@ -6387,7 +6448,8 @@
QualType FromCanon
= Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
- if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
+ if (FromCanon == ToCanon ||
+ IsDerivedFrom(CandidateSet.getLocation(), FromCanon, ToCanon)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_trivial_conversion;
return;
@@ -6409,7 +6471,7 @@
&ConversionRef, VK_RValue);
QualType ConversionType = Conversion->getConversionType();
- if (RequireCompleteType(From->getLocStart(), ConversionType, 0)) {
+ if (!isCompleteType(From->getLocStart(), ConversionType)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
@@ -6547,10 +6609,9 @@
// Determine the implicit conversion sequence for the implicit
// object parameter.
- ImplicitConversionSequence ObjectInit
- = TryObjectArgumentInitialization(*this, Object->getType(),
- Object->Classify(Context),
- Conversion, ActingContext);
+ ImplicitConversionSequence ObjectInit = TryObjectArgumentInitialization(
+ *this, CandidateSet.getLocation(), Object->getType(),
+ Object->Classify(Context), Conversion, ActingContext);
if (ObjectInit.isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -6659,7 +6720,8 @@
// the set of member candidates is empty.
if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
// Complete the type if it can be completed.
- RequireCompleteType(OpLoc, T1, 0);
+ if (!isCompleteType(OpLoc, T1) && !T1Rec->isBeingDefined())
+ return;
// If the type is neither complete nor being defined, bail out now.
if (!T1Rec->getDecl()->getDefinition())
return;
@@ -7008,7 +7070,7 @@
HasNullPtrType = true;
} else if (AllowUserConversions && TyRec) {
// No conversion functions in incomplete types.
- if (SemaRef.RequireCompleteType(Loc, Ty, 0))
+ if (!SemaRef.isCompleteType(Loc, Ty))
return;
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
@@ -8097,7 +8159,7 @@
const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr);
QualType C2 = QualType(mptr->getClass(), 0);
C2 = C2.getUnqualifiedType();
- if (C1 != C2 && !S.IsDerivedFrom(C1, C2))
+ if (C1 != C2 && !S.IsDerivedFrom(CandidateSet.getLocation(), C1, C2))
break;
QualType ParamTypes[2] = { *Ptr, *MemPtr };
// build CV12 T&
@@ -8483,7 +8545,7 @@
assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
- switch (CompareImplicitConversionSequences(S,
+ switch (CompareImplicitConversionSequences(S, Loc,
Cand1.Conversions[ArgIdx],
Cand2.Conversions[ArgIdx])) {
case ImplicitConversionSequence::Better:
@@ -8522,7 +8584,7 @@
ImplicitConversionSequence::CompareKind Result =
compareConversionFunctions(S, Cand1.Function, Cand2.Function);
if (Result == ImplicitConversionSequence::Indistinguishable)
- Result = CompareStandardConversionSequences(S,
+ Result = CompareStandardConversionSequences(S, Loc,
Cand1.FinalConversion,
Cand2.FinalConversion);
@@ -8572,26 +8634,63 @@
S.IdentifyCUDAPreference(Caller, Cand2.Function);
}
- return false;
+ bool HasPS1 = Cand1.Function != nullptr &&
+ functionHasPassObjectSizeParams(Cand1.Function);
+ bool HasPS2 = Cand2.Function != nullptr &&
+ functionHasPassObjectSizeParams(Cand2.Function);
+ return HasPS1 != HasPS2 && HasPS1;
}
/// Determine whether two declarations are "equivalent" for the purposes of
-/// name lookup and overload resolution. This applies when the same internal
-/// linkage variable or function is defined by two modules (textually including
+/// name lookup and overload resolution. This applies when the same internal/no
+/// linkage entity is defined by two modules (probably by textually including
/// the same header). In such a case, we don't consider the declarations to
/// declare the same entity, but we also don't want lookups with both
/// declarations visible to be ambiguous in some cases (this happens when using
/// a modularized libstdc++).
bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A,
const NamedDecl *B) {
- return A && B && isa<ValueDecl>(A) && isa<ValueDecl>(B) &&
- A->getDeclContext()->getRedeclContext()->Equals(
- B->getDeclContext()->getRedeclContext()) &&
- getOwningModule(const_cast<NamedDecl *>(A)) !=
- getOwningModule(const_cast<NamedDecl *>(B)) &&
- !A->isExternallyVisible() && !B->isExternallyVisible() &&
- Context.hasSameType(cast<ValueDecl>(A)->getType(),
- cast<ValueDecl>(B)->getType());
+ auto *VA = dyn_cast_or_null<ValueDecl>(A);
+ auto *VB = dyn_cast_or_null<ValueDecl>(B);
+ if (!VA || !VB)
+ return false;
+
+ // The declarations must be declaring the same name as an internal linkage
+ // entity in different modules.
+ if (!VA->getDeclContext()->getRedeclContext()->Equals(
+ VB->getDeclContext()->getRedeclContext()) ||
+ getOwningModule(const_cast<ValueDecl *>(VA)) ==
+ getOwningModule(const_cast<ValueDecl *>(VB)) ||
+ VA->isExternallyVisible() || VB->isExternallyVisible())
+ return false;
+
+ // Check that the declarations appear to be equivalent.
+ //
+ // FIXME: Checking the type isn't really enough to resolve the ambiguity.
+ // For constants and functions, we should check the initializer or body is
+ // the same. For non-constant variables, we shouldn't allow it at all.
+ if (Context.hasSameType(VA->getType(), VB->getType()))
+ return true;
+
+ // Enum constants within unnamed enumerations will have different types, but
+ // may still be similar enough to be interchangeable for our purposes.
+ if (auto *EA = dyn_cast<EnumConstantDecl>(VA)) {
+ if (auto *EB = dyn_cast<EnumConstantDecl>(VB)) {
+ // Only handle anonymous enums. If the enumerations were named and
+ // equivalent, they would have been merged to the same type.
+ auto *EnumA = cast<EnumDecl>(EA->getDeclContext());
+ auto *EnumB = cast<EnumDecl>(EB->getDeclContext());
+ if (EnumA->hasNameForLinkage() || EnumB->hasNameForLinkage() ||
+ !Context.hasSameType(EnumA->getIntegerType(),
+ EnumB->getIntegerType()))
+ return false;
+ // Allow this only if the value is the same for both enumerators.
+ return llvm::APSInt::isSameValue(EA->getInitVal(), EB->getInitVal());
+ }
+ }
+
+ // Nothing else is sufficiently similar.
+ return false;
}
void Sema::diagnoseEquivalentInternalLinkageDeclarations(
@@ -8609,9 +8708,6 @@
}
}
-static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
- unsigned NumArgs);
-
/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
@@ -8761,17 +8857,74 @@
return true;
}
+/// \brief Returns true if we can take the address of the function.
+///
+/// \param Complain - If true, we'll emit a diagnostic
+/// \param InOverloadResolution - For the purposes of emitting a diagnostic, are
+/// we in overload resolution?
+/// \param Loc - The location of the statement we're complaining about. Ignored
+/// if we're not complaining, or if we're in overload resolution.
+static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
+ bool Complain,
+ bool InOverloadResolution,
+ SourceLocation Loc) {
+ if (!isFunctionAlwaysEnabled(S.Context, FD)) {
+ if (Complain) {
+ if (InOverloadResolution)
+ S.Diag(FD->getLocStart(),
+ diag::note_addrof_ovl_candidate_disabled_by_enable_if_attr);
+ else
+ S.Diag(Loc, diag::err_addrof_function_disabled_by_enable_if_attr) << FD;
+ }
+ return false;
+ }
+
+ auto I = std::find_if(FD->param_begin(), FD->param_end(),
+ std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
+ if (I == FD->param_end())
+ return true;
+
+ if (Complain) {
+ // Add one to ParamNo because it's user-facing
+ unsigned ParamNo = std::distance(FD->param_begin(), I) + 1;
+ if (InOverloadResolution)
+ S.Diag(FD->getLocation(),
+ diag::note_ovl_candidate_has_pass_object_size_params)
+ << ParamNo;
+ else
+ S.Diag(Loc, diag::err_address_of_function_with_pass_object_size_params)
+ << FD << ParamNo;
+ }
+ return false;
+}
+
+static bool checkAddressOfCandidateIsAvailable(Sema &S,
+ const FunctionDecl *FD) {
+ return checkAddressOfFunctionIsAvailable(S, FD, /*Complain=*/true,
+ /*InOverloadResolution=*/true,
+ /*Loc=*/SourceLocation());
+}
+
+bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
+ bool Complain,
+ SourceLocation Loc) {
+ return ::checkAddressOfFunctionIsAvailable(*this, Function, Complain,
+ /*InOverloadResolution=*/false,
+ Loc);
+}
+
// Notes the location of an overload candidate.
void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType,
bool TakingAddress) {
+ if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
+ return;
+
std::string FnDesc;
OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
<< (unsigned) K << FnDesc;
- if (TakingAddress && !isFunctionAlwaysEnabled(Context, Fn))
- PD << ft_addr_enable_if;
- else
- HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
+
+ HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
Diag(Fn->getLocation(), PD);
MaybeEmitInheritedConstructorNote(*this, Fn);
}
@@ -8825,7 +8978,7 @@
}
static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
- unsigned I) {
+ unsigned I, bool TakingCandidateAddress) {
const ImplicitConversionSequence &Conv = Cand->Conversions[I];
assert(Conv.isBad());
assert(Cand->Function && "for now, candidate must be a function");
@@ -8967,7 +9120,7 @@
FromPtrTy->getPointeeType()) &&
!FromPtrTy->getPointeeType()->isIncompleteType() &&
!ToPtrTy->getPointeeType()->isIncompleteType() &&
- S.IsDerivedFrom(ToPtrTy->getPointeeType(),
+ S.IsDerivedFrom(SourceLocation(), ToPtrTy->getPointeeType(),
FromPtrTy->getPointeeType()))
BaseToDerivedConversion = 1;
}
@@ -8985,7 +9138,7 @@
if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) &&
!FromTy->isIncompleteType() &&
!ToRefTy->getPointeeType()->isIncompleteType() &&
- S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) {
+ S.IsDerivedFrom(SourceLocation(), ToRefTy->getPointeeType(), FromTy)) {
BaseToDerivedConversion = 3;
} else if (ToTy->isLValueReferenceType() && !FromExpr->isLValue() &&
ToTy.getNonReferenceType().getCanonicalType() ==
@@ -9023,7 +9176,11 @@
return;
}
}
-
+
+ if (TakingCandidateAddress &&
+ !checkAddressOfCandidateIsAvailable(S, Cand->Function))
+ return;
+
// Emit the generic diagnostic and, optionally, add the hints to it.
PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv);
FDiag << (unsigned) FnKind << FnDesc
@@ -9134,7 +9291,8 @@
/// Diagnose a failed template-argument deduction.
static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
DeductionFailureInfo &DeductionFailure,
- unsigned NumArgs) {
+ unsigned NumArgs,
+ bool TakingCandidateAddress) {
TemplateParameter Param = DeductionFailure.getTemplateParameter();
NamedDecl *ParamD;
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
@@ -9277,6 +9435,23 @@
return;
}
+ case Sema::TDK_DeducedMismatch: {
+ // Format the template argument list into the argument string.
+ SmallString<128> TemplateArgString;
+ if (TemplateArgumentList *Args =
+ DeductionFailure.getTemplateArgumentList()) {
+ TemplateArgString = " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ }
+
+ S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
+ << (*DeductionFailure.getCallArgIndex() + 1)
+ << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg()
+ << TemplateArgString;
+ break;
+ }
+
case Sema::TDK_NonDeducedMismatch: {
// FIXME: Provide a source location to indicate what we couldn't match.
TemplateArgument FirstTA = *DeductionFailure.getFirstArg();
@@ -9302,6 +9477,11 @@
}
}
}
+
+ if (TakingCandidateAddress && isa<FunctionDecl>(Templated) &&
+ !checkAddressOfCandidateIsAvailable(S, cast<FunctionDecl>(Templated)))
+ return;
+
// FIXME: For generic lambda parameters, check if the function is a lambda
// call operator, and if so, emit a prettier and more informative
// diagnostic that mentions 'auto' and lambda in addition to
@@ -9322,14 +9502,15 @@
/// Diagnose a failed template-argument deduction, for function calls.
static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
- unsigned NumArgs) {
+ unsigned NumArgs,
+ bool TakingCandidateAddress) {
unsigned TDK = Cand->DeductionFailure.Result;
if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) {
if (CheckArityMismatch(S, Cand, NumArgs))
return;
}
DiagnoseBadDeduction(S, Cand->Function, // pattern
- Cand->DeductionFailure, NumArgs);
+ Cand->DeductionFailure, NumArgs, TakingCandidateAddress);
}
/// CUDA: diagnose an invalid call across targets.
@@ -9410,7 +9591,8 @@
/// more richly for those diagnostic clients that cared, but we'd
/// still have to be just as careful with the default diagnostics.
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
- unsigned NumArgs) {
+ unsigned NumArgs,
+ bool TakingCandidateAddress) {
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
@@ -9438,7 +9620,7 @@
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
- return DiagnoseBadDeduction(S, Cand, NumArgs);
+ return DiagnoseBadDeduction(S, Cand, NumArgs, TakingCandidateAddress);
case ovl_fail_illegal_constructor: {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
@@ -9456,7 +9638,7 @@
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
for (unsigned N = Cand->NumConversions; I != N; ++I)
if (Cand->Conversions[I].isBad())
- return DiagnoseBadConversion(S, Cand, I);
+ return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
@@ -9469,6 +9651,13 @@
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
+
+ case ovl_fail_addr_not_available: {
+ bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
+ (void)Available;
+ assert(!Available);
+ break;
+ }
}
}
@@ -9559,6 +9748,7 @@
return 2;
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_DeducedMismatch:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_MiscellaneousDeductionFailure:
return 3;
@@ -9580,9 +9770,10 @@
namespace {
struct CompareOverloadCandidatesForDisplay {
Sema &S;
+ SourceLocation Loc;
size_t NumArgs;
- CompareOverloadCandidatesForDisplay(Sema &S, size_t nArgs)
+ CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs)
: S(S), NumArgs(nArgs) {}
bool operator()(const OverloadCandidate *L,
@@ -9653,7 +9844,7 @@
int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
for (unsigned E = L->NumConversions; I != E; ++I) {
- switch (CompareImplicitConversionSequences(S,
+ switch (CompareImplicitConversionSequences(S, Loc,
L->Conversions[I],
R->Conversions[I])) {
case ImplicitConversionSequence::Better:
@@ -9808,7 +9999,7 @@
}
std::sort(Cands.begin(), Cands.end(),
- CompareOverloadCandidatesForDisplay(S, Args.size()));
+ CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size()));
bool ReportedAmbiguousConversions = false;
@@ -9827,7 +10018,8 @@
++CandsShown;
if (Cand->Function)
- NoteFunctionCandidate(S, Cand, Args.size());
+ NoteFunctionCandidate(S, Cand, Args.size(),
+ /*TakingCandidateAddress=*/false);
else if (Cand->IsSurrogate)
NoteSurrogateCandidate(S, Cand);
else {
@@ -9895,9 +10087,10 @@
/// Diagnose a template argument deduction failure.
/// We are treating these failures as overload failures due to bad
/// deductions.
-void TemplateSpecCandidate::NoteDeductionFailure(Sema &S) {
+void TemplateSpecCandidate::NoteDeductionFailure(Sema &S,
+ bool ForTakingAddress) {
DiagnoseBadDeduction(S, Specialization, // pattern
- DeductionFailure, /*NumArgs=*/0);
+ DeductionFailure, /*NumArgs=*/0, ForTakingAddress);
}
void TemplateSpecCandidateSet::destroyCandidates() {
@@ -9950,7 +10143,7 @@
assert(Cand->Specialization &&
"Non-matching built-in candidates are not added to Cands.");
- Cand->NoteDeductionFailure(S);
+ Cand->NoteDeductionFailure(S, ForTakingAddress);
}
if (I != E)
@@ -10015,7 +10208,7 @@
HasComplained(false),
OvlExprInfo(OverloadExpr::find(SourceExpr)),
OvlExpr(OvlExprInfo.Expression),
- FailedCandidates(OvlExpr->getNameLoc()) {
+ FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) {
ExtractUnqualifiedFunctionTypeFromTargetType();
if (TargetFunctionType->isFunctionType()) {
@@ -10046,7 +10239,7 @@
}
if (OvlExpr->hasExplicitTemplateArgs())
- OvlExpr->getExplicitTemplateArgs().copyInto(OvlExplicitTemplateArgs);
+ OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
if (FindAllFunctionsThatMatchTargetTypeExactly()) {
// C++ [over.over]p4:
@@ -10149,10 +10342,9 @@
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
assert(S.isSameOrCompatibleFunctionType(
Context.getCanonicalType(Specialization->getType()),
- Context.getCanonicalType(TargetFunctionType)) ||
- (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType()));
+ Context.getCanonicalType(TargetFunctionType)));
- if (!isFunctionAlwaysEnabled(S.Context, Specialization))
+ if (!S.checkAddressOfFunctionIsAvailable(Specialization))
return false;
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
@@ -10185,7 +10377,7 @@
return false;
}
- if (!isFunctionAlwaysEnabled(S.Context, FunDecl))
+ if (!S.checkAddressOfFunctionIsAvailable(FunDecl))
return false;
QualType ResultTy;
@@ -10308,8 +10500,9 @@
I != IEnd; ++I)
if (FunctionDecl *Fun =
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
- S.NoteOverloadCandidate(Fun, TargetFunctionType,
- /*TakingAddress=*/true);
+ if (!functionHasPassObjectSizeParams(Fun))
+ S.NoteOverloadCandidate(Fun, TargetFunctionType,
+ /*TakingAddress=*/true);
FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart());
}
}
@@ -10446,7 +10639,7 @@
return nullptr;
TemplateArgumentListInfo ExplicitTemplateArgs;
- ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
+ ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc());
// Look through all of the overloaded functions, searching for one
@@ -11019,9 +11212,23 @@
if (!Recovery.isInvalid())
return Recovery;
- SemaRef.Diag(Fn->getLocStart(),
- diag::err_ovl_no_viable_function_in_call)
- << ULE->getName() << Fn->getSourceRange();
+ // If the user passes in a function that we can't take the address of, we
+ // generally end up emitting really bad error messages. Here, we attempt to
+ // emit better ones.
+ for (const Expr *Arg : Args) {
+ if (!Arg->getType()->isFunctionType())
+ continue;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts())) {
+ auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
+ if (FD &&
+ !SemaRef.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ Arg->getExprLoc()))
+ return ExprError();
+ }
+ }
+
+ SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_no_viable_function_in_call)
+ << ULE->getName() << Fn->getSourceRange();
CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
break;
}
@@ -11053,6 +11260,17 @@
return ExprError();
}
+static void markUnaddressableCandidatesUnviable(Sema &S,
+ OverloadCandidateSet &CS) {
+ for (auto I = CS.begin(), E = CS.end(); I != E; ++I) {
+ if (I->Viable &&
+ !S.checkAddressOfFunctionIsAvailable(I->Function, /*Complain=*/false)) {
+ I->Viable = false;
+ I->FailureKind = ovl_fail_addr_not_available;
+ }
+ }
+}
+
/// BuildOverloadedCallExpr - Given the call expression that calls Fn
/// (which eventually refers to the declaration Func) and the call
/// arguments Args/NumArgs, attempt to resolve the function call down
@@ -11065,7 +11283,8 @@
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
- bool AllowTypoCorrection) {
+ bool AllowTypoCorrection,
+ bool CalleesAddressIsTaken) {
OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
ExprResult result;
@@ -11074,6 +11293,11 @@
&result))
return result;
+ // If the user handed us something like `(&Foo)(Bar)`, we need to ensure that
+ // functions that aren't addressible are considered unviable.
+ if (CalleesAddressIsTaken)
+ markUnaddressableCandidatesUnviable(*this, CandidateSet);
+
OverloadCandidateSet::iterator Best;
OverloadingResult OverloadResult =
CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best);
@@ -11094,8 +11318,7 @@
///
/// \param OpLoc The location of the operator itself (e.g., '*').
///
-/// \param OpcIn The UnaryOperator::Opcode that describes this
-/// operator.
+/// \param Opc The UnaryOperatorKind that describes this operator.
///
/// \param Fns The set of non-member functions that will be
/// considered by overload resolution. The caller needs to build this
@@ -11106,11 +11329,9 @@
///
/// \param Input The input argument.
ExprResult
-Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
+Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *Input) {
- UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
-
OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -11281,8 +11502,7 @@
///
/// \param OpLoc The location of the operator itself (e.g., '+').
///
-/// \param OpcIn The BinaryOperator::Opcode that describes this
-/// operator.
+/// \param Opc The BinaryOperatorKind that describes this operator.
///
/// \param Fns The set of non-member functions that will be
/// considered by overload resolution. The caller needs to build this
@@ -11295,13 +11515,12 @@
/// \param RHS Right-hand argument.
ExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
- BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -12017,6 +12236,17 @@
<< MD->getDeclName();
}
}
+
+ if (CXXDestructorDecl *DD =
+ dyn_cast<CXXDestructorDecl>(TheCall->getMethodDecl())) {
+ // a->A::f() doesn't go through the vtable, except in AppleKext mode.
+ bool CallCanBeVirtual = !cast<MemberExpr>(NakedMemExpr)->hasQualifier() ||
+ getLangOpts().AppleKext;
+ CheckVirtualDtorCall(DD, MemExpr->getLocStart(), /*IsDelete=*/false,
+ CallCanBeVirtual, /*WarnOnNonAbstractTypes=*/true,
+ MemExpr->getMemberLoc());
+ }
+
return MaybeBindToTemporary(TheCall);
}
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 8998a7e..62c823b 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -44,17 +44,76 @@
namespace {
// Basically just a very focused copy of TreeTransform.
- template <class T> struct Rebuilder {
+ struct Rebuilder {
Sema &S;
- Rebuilder(Sema &S) : S(S) {}
+ unsigned MSPropertySubscriptCount;
+ typedef llvm::function_ref<Expr *(Expr *, unsigned)> SpecificRebuilderRefTy;
+ const SpecificRebuilderRefTy &SpecificCallback;
+ Rebuilder(Sema &S, const SpecificRebuilderRefTy &SpecificCallback)
+ : S(S), MSPropertySubscriptCount(0),
+ SpecificCallback(SpecificCallback) {}
- T &getDerived() { return static_cast<T&>(*this); }
+ Expr *rebuildObjCPropertyRefExpr(ObjCPropertyRefExpr *refExpr) {
+ // Fortunately, the constraint that we're rebuilding something
+ // with a base limits the number of cases here.
+ if (refExpr->isClassReceiver() || refExpr->isSuperReceiver())
+ return refExpr;
+
+ if (refExpr->isExplicitProperty()) {
+ return new (S.Context) ObjCPropertyRefExpr(
+ refExpr->getExplicitProperty(), refExpr->getType(),
+ refExpr->getValueKind(), refExpr->getObjectKind(),
+ refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0));
+ }
+ return new (S.Context) ObjCPropertyRefExpr(
+ refExpr->getImplicitPropertyGetter(),
+ refExpr->getImplicitPropertySetter(), refExpr->getType(),
+ refExpr->getValueKind(), refExpr->getObjectKind(),
+ refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0));
+ }
+ Expr *rebuildObjCSubscriptRefExpr(ObjCSubscriptRefExpr *refExpr) {
+ assert(refExpr->getBaseExpr());
+ assert(refExpr->getKeyExpr());
+
+ return new (S.Context) ObjCSubscriptRefExpr(
+ SpecificCallback(refExpr->getBaseExpr(), 0),
+ SpecificCallback(refExpr->getKeyExpr(), 1), refExpr->getType(),
+ refExpr->getValueKind(), refExpr->getObjectKind(),
+ refExpr->getAtIndexMethodDecl(), refExpr->setAtIndexMethodDecl(),
+ refExpr->getRBracket());
+ }
+ Expr *rebuildMSPropertyRefExpr(MSPropertyRefExpr *refExpr) {
+ assert(refExpr->getBaseExpr());
+
+ return new (S.Context) MSPropertyRefExpr(
+ SpecificCallback(refExpr->getBaseExpr(), 0),
+ refExpr->getPropertyDecl(), refExpr->isArrow(), refExpr->getType(),
+ refExpr->getValueKind(), refExpr->getQualifierLoc(),
+ refExpr->getMemberLoc());
+ }
+ Expr *rebuildMSPropertySubscriptExpr(MSPropertySubscriptExpr *refExpr) {
+ assert(refExpr->getBase());
+ assert(refExpr->getIdx());
+
+ auto *NewBase = rebuild(refExpr->getBase());
+ ++MSPropertySubscriptCount;
+ return new (S.Context) MSPropertySubscriptExpr(
+ NewBase,
+ SpecificCallback(refExpr->getIdx(), MSPropertySubscriptCount),
+ refExpr->getType(), refExpr->getValueKind(), refExpr->getObjectKind(),
+ refExpr->getRBracketLoc());
+ }
Expr *rebuild(Expr *e) {
// Fast path: nothing to look through.
- if (typename T::specific_type *specific
- = dyn_cast<typename T::specific_type>(e))
- return getDerived().rebuildSpecific(specific);
+ if (auto *PRE = dyn_cast<ObjCPropertyRefExpr>(e))
+ return rebuildObjCPropertyRefExpr(PRE);
+ if (auto *SRE = dyn_cast<ObjCSubscriptRefExpr>(e))
+ return rebuildObjCSubscriptRefExpr(SRE);
+ if (auto *MSPRE = dyn_cast<MSPropertyRefExpr>(e))
+ return rebuildMSPropertyRefExpr(MSPRE);
+ if (auto *MSPSE = dyn_cast<MSPropertySubscriptExpr>(e))
+ return rebuildMSPropertySubscriptExpr(MSPSE);
// Otherwise, we should look through and rebuild anything that
// IgnoreParens would.
@@ -125,72 +184,6 @@
}
};
- struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> {
- Expr *NewBase;
- ObjCPropertyRefRebuilder(Sema &S, Expr *newBase)
- : Rebuilder<ObjCPropertyRefRebuilder>(S), NewBase(newBase) {}
-
- typedef ObjCPropertyRefExpr specific_type;
- Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {
- // Fortunately, the constraint that we're rebuilding something
- // with a base limits the number of cases here.
- assert(refExpr->isObjectReceiver());
-
- if (refExpr->isExplicitProperty()) {
- return new (S.Context)
- ObjCPropertyRefExpr(refExpr->getExplicitProperty(),
- refExpr->getType(), refExpr->getValueKind(),
- refExpr->getObjectKind(), refExpr->getLocation(),
- NewBase);
- }
- return new (S.Context)
- ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(),
- refExpr->getImplicitPropertySetter(),
- refExpr->getType(), refExpr->getValueKind(),
- refExpr->getObjectKind(),refExpr->getLocation(),
- NewBase);
- }
- };
-
- struct ObjCSubscriptRefRebuilder : Rebuilder<ObjCSubscriptRefRebuilder> {
- Expr *NewBase;
- Expr *NewKeyExpr;
- ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr)
- : Rebuilder<ObjCSubscriptRefRebuilder>(S),
- NewBase(newBase), NewKeyExpr(newKeyExpr) {}
-
- typedef ObjCSubscriptRefExpr specific_type;
- Expr *rebuildSpecific(ObjCSubscriptRefExpr *refExpr) {
- assert(refExpr->getBaseExpr());
- assert(refExpr->getKeyExpr());
-
- return new (S.Context)
- ObjCSubscriptRefExpr(NewBase,
- NewKeyExpr,
- refExpr->getType(), refExpr->getValueKind(),
- refExpr->getObjectKind(),refExpr->getAtIndexMethodDecl(),
- refExpr->setAtIndexMethodDecl(),
- refExpr->getRBracket());
- }
- };
-
- struct MSPropertyRefRebuilder : Rebuilder<MSPropertyRefRebuilder> {
- Expr *NewBase;
- MSPropertyRefRebuilder(Sema &S, Expr *newBase)
- : Rebuilder<MSPropertyRefRebuilder>(S), NewBase(newBase) {}
-
- typedef MSPropertyRefExpr specific_type;
- Expr *rebuildSpecific(MSPropertyRefExpr *refExpr) {
- assert(refExpr->getBaseExpr());
-
- return new (S.Context)
- MSPropertyRefExpr(NewBase, refExpr->getPropertyDecl(),
- refExpr->isArrow(), refExpr->getType(),
- refExpr->getValueKind(), refExpr->getQualifierLoc(),
- refExpr->getMemberLoc());
- }
- };
-
class PseudoOpBuilder {
public:
Sema &S;
@@ -236,7 +229,7 @@
}
/// Return true if assignments have a non-void result.
- bool CanCaptureValue(Expr *exp) {
+ static bool CanCaptureValue(Expr *exp) {
if (exp->isGLValue())
return true;
QualType ty = exp->getType();
@@ -252,6 +245,20 @@
virtual ExprResult buildGet() = 0;
virtual ExprResult buildSet(Expr *, SourceLocation,
bool captureSetValueAsResult) = 0;
+ /// \brief Should the result of an assignment be the formal result of the
+ /// setter call or the value that was passed to the setter?
+ ///
+ /// Different pseudo-object language features use different language rules
+ /// for this.
+ /// The default is to use the set value. Currently, this affects the
+ /// behavior of simple assignments, compound assignments, and prefix
+ /// increment and decrement.
+ /// Postfix increment and decrement always use the getter result as the
+ /// expression result.
+ ///
+ /// If this method returns true, and the set value isn't capturable for
+ /// some reason, the result of the expression will be void.
+ virtual bool captureSetValueAsResult() const { return true; }
};
/// A PseudoOpBuilder for Objective-C \@properties.
@@ -329,15 +336,24 @@
class MSPropertyOpBuilder : public PseudoOpBuilder {
MSPropertyRefExpr *RefExpr;
OpaqueValueExpr *InstanceBase;
+ SmallVector<Expr *, 4> CallArgs;
+
+ MSPropertyRefExpr *getBaseMSProperty(MSPropertySubscriptExpr *E);
public:
MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) :
PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()),
RefExpr(refExpr), InstanceBase(nullptr) {}
+ MSPropertyOpBuilder(Sema &S, MSPropertySubscriptExpr *refExpr)
+ : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()),
+ InstanceBase(nullptr) {
+ RefExpr = getBaseMSProperty(refExpr);
+ }
Expr *rebuildAndCaptureObject(Expr *) override;
ExprResult buildGet() override;
ExprResult buildSet(Expr *op, SourceLocation, bool) override;
+ bool captureSetValueAsResult() const override { return false; }
};
}
@@ -454,9 +470,12 @@
// The result of the assignment, if not void, is the value set into
// the l-value.
- result = buildSet(result.get(), opcLoc, /*captureSetValueAsResult*/ true);
+ result = buildSet(result.get(), opcLoc, captureSetValueAsResult());
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.get());
+ if (!captureSetValueAsResult() && !result.get()->getType()->isVoidType() &&
+ (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
+ setResultToLastSemantic();
return complete(syntactic);
}
@@ -498,9 +517,14 @@
// Store that back into the result. The value stored is the result
// of a prefix operation.
- result = buildSet(result.get(), opcLoc, UnaryOperator::isPrefix(opcode));
+ result = buildSet(result.get(), opcLoc, UnaryOperator::isPrefix(opcode) &&
+ captureSetValueAsResult());
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.get());
+ if (UnaryOperator::isPrefix(opcode) && !captureSetValueAsResult() &&
+ !result.get()->getType()->isVoidType() &&
+ (result.get()->isTypeDependent() || CanCaptureValue(result.get())))
+ setResultToLastSemantic();
UnaryOperator *syntactic =
new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,
@@ -634,7 +658,8 @@
SmallString<100> PropertyName = thisPropertyName;
PropertyName[0] = front;
IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName);
- if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember))
+ if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(
+ AltMember, prop->getQueryKind()))
if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) {
S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use)
<< prop << prop1 << setter->getSelector();
@@ -674,9 +699,9 @@
// form to use the OVE as its base.
if (RefExpr->isObjectReceiver()) {
InstanceReceiver = capture(RefExpr->getBase());
-
- syntacticBase =
- ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase);
+ syntacticBase = Rebuilder(S, [=](Expr *, unsigned) -> Expr * {
+ return InstanceReceiver;
+ }).rebuild(syntacticBase);
}
if (ObjCPropertyRefExpr *
@@ -994,11 +1019,19 @@
// form to use the OVE as its base expression.
InstanceBase = capture(RefExpr->getBaseExpr());
InstanceKey = capture(RefExpr->getKeyExpr());
-
+
syntacticBase =
- ObjCSubscriptRefRebuilder(S, InstanceBase,
- InstanceKey).rebuild(syntacticBase);
-
+ Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * {
+ switch (Idx) {
+ case 0:
+ return InstanceBase;
+ case 1:
+ return InstanceKey;
+ default:
+ llvm_unreachable("Unexpected index for ObjCSubscriptExpr");
+ }
+ }).rebuild(syntacticBase);
+
return syntacticBase;
}
@@ -1400,11 +1433,30 @@
// MSVC __declspec(property) references
//===----------------------------------------------------------------------===//
+MSPropertyRefExpr *
+MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) {
+ CallArgs.insert(CallArgs.begin(), E->getIdx());
+ Expr *Base = E->getBase()->IgnoreParens();
+ while (auto *MSPropSubscript = dyn_cast<MSPropertySubscriptExpr>(Base)) {
+ CallArgs.insert(CallArgs.begin(), MSPropSubscript->getIdx());
+ Base = MSPropSubscript->getBase()->IgnoreParens();
+ }
+ return cast<MSPropertyRefExpr>(Base);
+}
+
Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
InstanceBase = capture(RefExpr->getBaseExpr());
-
- syntacticBase =
- MSPropertyRefRebuilder(S, InstanceBase).rebuild(syntacticBase);
+ std::for_each(CallArgs.begin(), CallArgs.end(),
+ [this](Expr *&Arg) { Arg = capture(Arg); });
+ syntacticBase = Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * {
+ switch (Idx) {
+ case 0:
+ return InstanceBase;
+ default:
+ assert(Idx <= CallArgs.size());
+ return CallArgs[Idx - 1];
+ }
+ }).rebuild(syntacticBase);
return syntacticBase;
}
@@ -1432,9 +1484,8 @@
return ExprError();
}
- MultiExprArg ArgExprs;
return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(),
- RefExpr->getSourceRange().getBegin(), ArgExprs,
+ RefExpr->getSourceRange().getBegin(), CallArgs,
RefExpr->getSourceRange().getEnd());
}
@@ -1462,7 +1513,8 @@
return ExprError();
}
- SmallVector<Expr*, 1> ArgExprs;
+ SmallVector<Expr*, 4> ArgExprs;
+ ArgExprs.append(CallArgs.begin(), CallArgs.end());
ArgExprs.push_back(op);
return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(),
RefExpr->getSourceRange().getBegin(), ArgExprs,
@@ -1488,6 +1540,10 @@
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
MSPropertyOpBuilder builder(*this, refExpr);
return builder.buildRValueOperation(E);
+ } else if (MSPropertySubscriptExpr *RefExpr =
+ dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
+ MSPropertyOpBuilder Builder(*this, RefExpr);
+ return Builder.buildRValueOperation(E);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
@@ -1514,6 +1570,10 @@
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
MSPropertyOpBuilder builder(*this, refExpr);
return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
+ } else if (MSPropertySubscriptExpr *RefExpr
+ = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
+ MSPropertyOpBuilder Builder(*this, RefExpr);
+ return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
@@ -1545,8 +1605,12 @@
return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else if (MSPropertyRefExpr *refExpr
= dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
- MSPropertyOpBuilder builder(*this, refExpr);
- return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
+ MSPropertyOpBuilder builder(*this, refExpr);
+ return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
+ } else if (MSPropertySubscriptExpr *RefExpr
+ = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
+ MSPropertyOpBuilder Builder(*this, RefExpr);
+ return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
} else {
llvm_unreachable("unknown pseudo-object kind!");
}
@@ -1556,29 +1620,11 @@
/// values. Basically, undo the behavior of rebuildAndCaptureObject.
/// This should never operate in-place.
static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) {
- Expr *opaqueRef = E->IgnoreParens();
- if (ObjCPropertyRefExpr *refExpr
- = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
- // Class and super property references don't have opaque values in them.
- if (refExpr->isClassReceiver() || refExpr->isSuperReceiver())
- return E;
-
- assert(refExpr->isObjectReceiver() && "Unknown receiver kind?");
- OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase());
- return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E);
- } else if (ObjCSubscriptRefExpr *refExpr
- = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
- OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr());
- OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr());
- return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(),
- keyOVE->getSourceExpr()).rebuild(E);
- } else if (MSPropertyRefExpr *refExpr
- = dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
- OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr());
- return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E);
- } else {
- llvm_unreachable("unknown pseudo-object kind!");
- }
+ return Rebuilder(S,
+ [=](Expr *E, unsigned) -> Expr * {
+ return cast<OpaqueValueExpr>(E)->getSourceExpr();
+ })
+ .rebuild(E);
}
/// Given a pseudo-object expression, recreate what it looks like
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 869ea1d..e1b1a47 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1706,11 +1706,10 @@
// If we have a forward-declared type, we can't do this check.
// Under ARC, it is an error not to have a forward-declared class.
if (iface &&
- RequireCompleteType(forLoc, QualType(objectType, 0),
- getLangOpts().ObjCAutoRefCount
- ? diag::err_arc_collection_forward
- : 0,
- collection)) {
+ (getLangOpts().ObjCAutoRefCount
+ ? RequireCompleteType(forLoc, QualType(objectType, 0),
+ diag::err_arc_collection_forward, collection)
+ : !isCompleteType(forLoc, QualType(objectType, 0)))) {
// Otherwise, if we have any useful type information, check that
// the type declares the appropriate method.
} else if (iface || !objectType->qual_empty()) {
@@ -3216,7 +3215,7 @@
}
// return (some void expression); is legal in C++.
else if (D != diag::ext_return_has_void_expr ||
- !getLangOpts().CPlusPlus) {
+ !getLangOpts().CPlusPlus) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
int FunctionKind = 0;
@@ -3803,11 +3802,10 @@
continue;
}
- assert(Cap->isReferenceCapture() &&
- "non-reference capture not yet implemented");
-
Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
- CapturedStmt::VCK_ByRef,
+ Cap->isReferenceCapture()
+ ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
Cap->getVariable()));
CaptureInits.push_back(Cap->getInitExpr());
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index bb6657b..11a4f8b 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -589,10 +589,8 @@
QualType T = Result.get()->getType();
- // For now, reject dependent types.
if (T->isDependentType()) {
- Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T;
- return ExprError();
+ return Result;
}
// Any sort of function type is fine.
@@ -617,56 +615,80 @@
bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset, SourceLocation AsmLoc) {
Offset = 0;
+ SmallVector<StringRef, 2> Members;
+ Member.split(Members, ".");
+
LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
LookupOrdinaryName);
if (!LookupName(BaseResult, getCurScope()))
return true;
- if (!BaseResult.isSingleResult())
- return true;
+ LookupResult CurrBaseResult(BaseResult);
- const RecordType *RT = nullptr;
- NamedDecl *FoundDecl = BaseResult.getFoundDecl();
- if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
- RT = VD->getType()->getAs<RecordType>();
- else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
- MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
- RT = TD->getUnderlyingType()->getAs<RecordType>();
- } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
- RT = TD->getTypeForDecl()->getAs<RecordType>();
- if (!RT)
- return true;
+ for (StringRef NextMember : Members) {
- if (RequireCompleteType(AsmLoc, QualType(RT, 0), 0))
- return true;
+ if (!CurrBaseResult.isSingleResult())
+ return true;
- LookupResult FieldResult(*this, &Context.Idents.get(Member), SourceLocation(),
- LookupMemberName);
+ const RecordType *RT = nullptr;
+ NamedDecl *FoundDecl = CurrBaseResult.getFoundDecl();
+ if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
+ RT = VD->getType()->getAs<RecordType>();
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
+ MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
+ RT = TD->getUnderlyingType()->getAs<RecordType>();
+ } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
+ RT = TD->getTypeForDecl()->getAs<RecordType>();
+ else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
+ RT = TD->getType()->getAs<RecordType>();
+ if (!RT)
+ return true;
- if (!LookupQualifiedName(FieldResult, RT->getDecl()))
- return true;
+ if (RequireCompleteType(AsmLoc, QualType(RT, 0),
+ diag::err_asm_incomplete_type))
+ return true;
- // FIXME: Handle IndirectFieldDecl?
- FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
- if (!FD)
- return true;
+ LookupResult FieldResult(*this, &Context.Idents.get(NextMember),
+ SourceLocation(), LookupMemberName);
- const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
- unsigned i = FD->getFieldIndex();
- CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
- Offset = (unsigned)Result.getQuantity();
+ if (!LookupQualifiedName(FieldResult, RT->getDecl()))
+ return true;
+
+ // FIXME: Handle IndirectFieldDecl?
+ FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
+ if (!FD)
+ return true;
+
+ CurrBaseResult = FieldResult;
+
+ const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
+ unsigned i = FD->getFieldIndex();
+ CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
+ Offset += (unsigned)Result.getQuantity();
+ }
return false;
}
ExprResult
-Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, unsigned &Offset,
+Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc) {
Info.clear();
- const RecordType *RT = E->getType()->getAs<RecordType>();
+ QualType T = E->getType();
+ if (T->isDependentType()) {
+ DeclarationNameInfo NameInfo;
+ NameInfo.setLoc(AsmLoc);
+ NameInfo.setName(&Context.Idents.get(Member));
+ return CXXDependentScopeMemberExpr::Create(
+ Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
+ SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
+ }
+
+ const RecordType *RT = T->getAs<RecordType>();
// FIXME: Diagnose this as field access into a scalar type.
if (!RT)
return ExprResult();
@@ -684,9 +706,6 @@
if (!FD)
return ExprResult();
- Offset = (unsigned)Context.toCharUnitsFromBits(Context.getFieldOffset(FD))
- .getQuantity();
-
// Make an Expr to thread through OpDecl.
ExprResult Result = BuildMemberReferenceExpr(
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
@@ -737,7 +756,15 @@
// Create an internal name for the label. The name should not be a valid mangled
// name, and should be unique. We use a dot to make the name an invalid mangled
// name.
- OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName;
+ OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__";
+ for (auto it = ExternalLabelName.begin(); it != ExternalLabelName.end();
+ ++it) {
+ OS << *it;
+ if (*it == '$') {
+ // We escape '$' in asm strings by replacing it with "$$"
+ OS << '$';
+ }
+ }
Label->setMSAsmLabel(OS.str());
}
if (AlwaysCreate) {
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 02d5628..984bd07 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -150,9 +150,8 @@
if (!LH)
continue;
- int Option = LH->getOption();
- int Category;
- enum { Vectorize, Interleave, Unroll };
+ LoopHintAttr::OptionType Option = LH->getOption();
+ enum { Vectorize, Interleave, Unroll } Category;
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ce1aa4c..9077049 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -329,8 +329,8 @@
Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
- if (Corrected.getCorrectionDecl())
- Found.addDecl(Corrected.getCorrectionDecl());
+ if (auto *ND = Corrected.getFoundDecl())
+ Found.addDecl(ND);
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
if (LookupCtx) {
@@ -583,7 +583,7 @@
// template-parameter that is not a template parameter pack.
if (DefaultArg && IsParameterPack) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- DefaultArg = ParsedType();
+ DefaultArg = nullptr;
}
// Handle the default argument, if provided.
@@ -814,14 +814,15 @@
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ ArrayRef<Decl *> Params,
SourceLocation RAngleLoc) {
if (ExportLoc.isValid())
Diag(ExportLoc, diag::warn_template_export_unsupported);
- return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- (NamedDecl**)Params, NumParams,
- RAngleLoc);
+ return TemplateParameterList::Create(
+ Context, TemplateLoc, LAngleLoc,
+ llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()),
+ RAngleLoc);
}
static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
@@ -1939,7 +1940,7 @@
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), nullptr, 0,
+ SourceLocation(), None,
SourceLocation());
}
@@ -2749,7 +2750,8 @@
typedef PartialSpecMatchResult MatchResult;
SmallVector<MatchResult, 4> Matched;
SourceLocation PointOfInstantiation = TemplateNameLoc;
- TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
+ TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation,
+ /*ForTakingAddress=*/false);
// 1. Attempt to find the closest partial specialization that this
// specializes, if any.
@@ -3280,8 +3282,8 @@
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
- Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
+ Sema::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
}
@@ -4182,6 +4184,10 @@
return Visit(T->getValueType());
}
+bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
@@ -4281,7 +4287,7 @@
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
- if (S.RequireCompleteType(Arg->getExprLoc(), ParamType, 0))
+ if (!S.isCompleteType(Arg->getExprLoc(), ParamType))
llvm_unreachable(
"Incomplete parameter type in isNullPointerValueTemplateArgument!");
@@ -5501,6 +5507,8 @@
Expr *E;
if (T->isAnyCharacterType()) {
+ // This does not need to handle u8 character literals because those are
+ // of type char, and so can also be covered by an ASCII character literal.
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
Kind = CharacterLiteral::Wide;
@@ -6409,7 +6417,17 @@
if (!PrevDecl)
ClassTemplate->AddSpecialization(Specialization, InsertPos);
- CanonType = Context.getTypeDeclType(Specialization);
+ if (CurContext->isDependentContext()) {
+ // -fms-extensions permits specialization of nested classes without
+ // fully specializing the outer class(es).
+ assert(getLangOpts().MicrosoftExt &&
+ "Only possible with -fms-extensions!");
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ CanonType = Context.getTemplateSpecializationType(
+ CanonTemplate, Converted.data(), Converted.size());
+ } else {
+ CanonType = Context.getTypeDeclType(Specialization);
+ }
}
// C++ [temp.expl.spec]p6:
@@ -6813,7 +6831,8 @@
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
- TemplateSpecCandidateSet FailedCandidates(FD->getLocation());
+ TemplateSpecCandidateSet FailedCandidates(FD->getLocation(),
+ /*ForTakingAddress=*/false);
llvm::SmallDenseMap<FunctionDecl *, TemplateArgumentListInfo, 8>
ConvertedTemplateArgs;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 8b2e7db..71faafc 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1440,7 +1440,7 @@
// We cannot inspect base classes as part of deduction when the type
// is incomplete, so either instantiate any templates necessary to
// complete the type, or skip over it if it cannot be completed.
- if (S.RequireCompleteType(Info.getLocation(), Arg, 0))
+ if (!S.isCompleteType(Info.getLocation(), Arg))
return Result;
// Use data recursion to crawl through the list of base classes.
@@ -1517,10 +1517,19 @@
if (!MemPtrArg)
return Sema::TDK_NonDeducedMismatch;
+ QualType ParamPointeeType = MemPtrParam->getPointeeType();
+ if (ParamPointeeType->isFunctionType())
+ S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true,
+ /*IsCtorOrDtor=*/false, Info.getLocation());
+ QualType ArgPointeeType = MemPtrArg->getPointeeType();
+ if (ArgPointeeType->isFunctionType())
+ S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true,
+ /*IsCtorOrDtor=*/false, Info.getLocation());
+
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- MemPtrParam->getPointeeType(),
- MemPtrArg->getPointeeType(),
+ ParamPointeeType,
+ ArgPointeeType,
Info, Deduced,
TDF & TDF_IgnoreQualifiers))
return Result;
@@ -1643,6 +1652,7 @@
case Type::Auto:
case Type::DependentTemplateSpecialization:
case Type::PackExpansion:
+ case Type::Pipe:
// No template argument deduction for these types
return Sema::TDK_Success;
}
@@ -2729,7 +2739,7 @@
return false;
if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
- S.IsDerivedFrom(A, DeducedA))
+ S.IsDerivedFrom(SourceLocation(), A, DeducedA))
return false;
return true;
@@ -2945,8 +2955,12 @@
continue;
QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA))
- return Sema::TDK_SubstitutionFailure;
+ if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+ Info.FirstArg = TemplateArgument(DeducedA);
+ Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
+ Info.CallArgIndex = OriginalArg.ArgIdx;
+ return TDK_DeducedMismatch;
+ }
}
}
@@ -3028,7 +3042,7 @@
// Gather the explicit template arguments, if any.
TemplateArgumentListInfo ExplicitTemplateArgs;
if (Ovl->hasExplicitTemplateArgs())
- Ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
+ Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
QualType Match;
for (UnresolvedSetIterator I = Ovl->decls_begin(),
E = Ovl->decls_end(); I != E; ++I) {
@@ -3123,8 +3137,10 @@
if (ParamRefType) {
// If the argument has incomplete array type, try to complete its type.
- if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
+ if (ArgType->isIncompleteArrayType()) {
+ S.completeExprArrayBound(Arg);
ArgType = Arg->getType();
+ }
// C++0x [temp.deduct.call]p3:
// If P is an rvalue reference to a cv-unqualified template
@@ -3203,24 +3219,63 @@
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF, Sema::TemplateDeductionResult &Result) {
- // If the argument is an initializer list then the parameter is an undeduced
- // context, unless the parameter type is (reference to cv)
- // std::initializer_list<P'>, in which case deduction is done for each element
- // of the initializer list as-if it were an argument in a function call, and
- // the result is the deduced type if it's the same for all elements.
- QualType X;
- if (!S.isStdInitializerList(AdjustedParamType, &X))
+
+ // [temp.deduct.call] p1 (post CWG-1591)
+ // If removing references and cv-qualifiers from P gives
+ // std::initializer_list<P0> or P0[N] for some P0 and N and the argument is a
+ // non-empty initializer list (8.5.4), then deduction is performed instead for
+ // each element of the initializer list, taking P0 as a function template
+ // parameter type and the initializer element as its argument, and in the
+ // P0[N] case, if N is a non-type template parameter, N is deduced from the
+ // length of the initializer list. Otherwise, an initializer list argument
+ // causes the parameter to be considered a non-deduced context
+
+ const bool IsConstSizedArray = AdjustedParamType->isConstantArrayType();
+
+ const bool IsDependentSizedArray =
+ !IsConstSizedArray && AdjustedParamType->isDependentSizedArrayType();
+
+ QualType ElTy; // The element type of the std::initializer_list or the array.
+
+ const bool IsSTDList = !IsConstSizedArray && !IsDependentSizedArray &&
+ S.isStdInitializerList(AdjustedParamType, &ElTy);
+
+ if (!IsConstSizedArray && !IsDependentSizedArray && !IsSTDList)
return false;
Result = Sema::TDK_Success;
-
- // Recurse down into the init list.
- for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
- if ((Result = DeduceTemplateArgumentByListElement(
- S, TemplateParams, X, ILE->getInit(i), Info, Deduced, TDF)))
- return true;
+ // If we are not deducing against the 'T' in a std::initializer_list<T> then
+ // deduce against the 'T' in T[N].
+ if (ElTy.isNull()) {
+ assert(!IsSTDList);
+ ElTy = S.Context.getAsArrayType(AdjustedParamType)->getElementType();
}
+ // Deduction only needs to be done for dependent types.
+ if (ElTy->isDependentType()) {
+ for (Expr *E : ILE->inits()) {
+ if ((Result = DeduceTemplateArgumentByListElement(S, TemplateParams, ElTy,
+ E, Info, Deduced, TDF)))
+ return true;
+ }
+ }
+ if (IsDependentSizedArray) {
+ const DependentSizedArrayType *ArrTy =
+ S.Context.getAsDependentSizedArrayType(AdjustedParamType);
+ // Determine the array bound is something we can deduce.
+ if (NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(ArrTy->getSizeExpr())) {
+ // We can perform template argument deduction for the given non-type
+ // template parameter.
+ assert(NTTP->getDepth() == 0 &&
+ "Cannot deduce non-type template argument at depth > 0");
+ llvm::APInt Size(S.Context.getIntWidth(NTTP->getType()),
+ ILE->getNumInits());
+ Result = DeduceNonTypeTemplateArgument(
+ S, NTTP, llvm::APSInt(Size), NTTP->getType(),
+ /*ArrayBound=*/true, Info, Deduced);
+ }
+ }
return true;
}
@@ -3908,7 +3963,7 @@
!Replacement.isNull() && Replacement->isDependentType();
QualType Result =
SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement,
- TL.getTypePtr()->isDecltypeAuto(),
+ TL.getTypePtr()->getKeyword(),
Dependent);
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -3976,6 +4031,11 @@
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
+ } else if (!getLangOpts().CPlusPlus) {
+ if (isa<InitListExpr>(Init)) {
+ Diag(Init->getLocStart(), diag::err_auto_init_list_from_c);
+ return DAR_FailedAlreadyDiagnosed;
+ }
}
}
@@ -3990,7 +4050,7 @@
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterListStorage<1> TemplateParamsSt(
- Loc, Loc, &TemplParamPtr, Loc);
+ Loc, Loc, TemplParamPtr, Loc);
QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type);
assert(!FuncParam.isNull() &&
@@ -4013,6 +4073,11 @@
return DAR_Failed;
}
} else {
+ if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
+ Diag(Loc, diag::err_auto_bitfield);
+ return DAR_FailedAlreadyDiagnosed;
+ }
+
if (AdjustFunctionParmAndArgTypesForDeduction(
*this, TemplateParamsSt.get(), FuncParam, InitType, Init, TDF))
return DAR_Failed;
@@ -4827,19 +4892,23 @@
break;
case Type::DependentTemplateSpecialization: {
+ // C++14 [temp.deduct.type]p5:
+ // The non-deduced contexts are:
+ // -- The nested-name-specifier of a type that was specified using a
+ // qualified-id
+ //
+ // C++14 [temp.deduct.type]p6:
+ // When a type name is specified in a way that includes a non-deduced
+ // context, all of the types that comprise that type name are also
+ // non-deduced.
+ if (OnlyDeduced)
+ break;
+
const DependentTemplateSpecializationType *Spec
= cast<DependentTemplateSpecializationType>(T);
- if (!OnlyDeduced)
- MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
- OnlyDeduced, Depth, Used);
- // C++0x [temp.deduct.type]p9:
- // If the template argument list of P contains a pack expansion that is not
- // the last template argument, the entire template argument list is a
- // non-deduced context.
- if (OnlyDeduced &&
- hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs()))
- break;
+ MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
+ OnlyDeduced, Depth, Used);
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
@@ -4896,6 +4965,7 @@
case Type::ObjCObject:
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
+ case Type::Pipe:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3a3f632..fb7fc10 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1680,8 +1680,11 @@
Sema::ContextRAII SavedContext(*this, OwningFunc);
LocalInstantiationScope Local(*this);
ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
- if (NewArg.isUsable())
- NewParm->setDefaultArg(NewArg.get());
+ if (NewArg.isUsable()) {
+ // It would be nice if we still had this.
+ SourceLocation EqualLoc = NewArg.get()->getLocStart();
+ SetParamDefaultArgument(NewParm, NewArg.get(), EqualLoc);
+ }
} else {
// FIXME: if we non-lazily instantiated non-dependent default args for
// non-dependent parameter types we could remove a bunch of duplicate
@@ -1834,9 +1837,7 @@
Invalid = true;
}
- if (!Invalid &&
- AttachBaseSpecifiers(Instantiation, InstantiatedBases.data(),
- InstantiatedBases.size()))
+ if (!Invalid && AttachBaseSpecifiers(Instantiation, InstantiatedBases))
Invalid = true;
return Invalid;
@@ -2663,16 +2664,17 @@
return Instantiator.TransformInitializer(Init, CXXDirectInit);
}
-bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
+bool Sema::SubstExprs(ArrayRef<Expr *> Exprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<Expr *> &Outputs) {
- if (NumExprs == 0)
+ if (Exprs.empty())
return false;
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
DeclarationName());
- return Instantiator.TransformExprs(Exprs, NumExprs, IsCall, Outputs);
+ return Instantiator.TransformExprs(Exprs.data(), Exprs.size(),
+ IsCall, Outputs);
}
NestedNameSpecifierLoc
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f5f03d0..7a452af 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2767,7 +2767,7 @@
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
- L->getLAngleLoc(), &Params.front(), N,
+ L->getLAngleLoc(), Params,
L->getRAngleLoc());
return InstL;
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index a7fef8a..cb67d71 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -737,6 +737,7 @@
case TST_interface:
case TST_class:
case TST_auto:
+ case TST_auto_type:
case TST_decltype_auto:
case TST_unknown_anytype:
case TST_error:
@@ -749,6 +750,7 @@
case DeclaratorChunk::Pointer:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pipe:
case DeclaratorChunk::BlockPointer:
// These declarator chunks cannot contain any parameter packs.
break;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 81c8b7f..844be54 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -26,7 +26,6 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
@@ -336,6 +335,7 @@
case DeclaratorChunk::Array:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return result;
// If we do find a function declarator, scan inwards from that,
@@ -348,6 +348,7 @@
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::MemberPointer:
@@ -428,6 +429,7 @@
// Don't walk through these.
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
goto error;
}
}
@@ -460,6 +462,7 @@
case DeclaratorChunk::MemberPointer:
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
+ case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::Function:
@@ -521,6 +524,7 @@
case DeclaratorChunk::Array:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
continue;
}
}
@@ -1273,6 +1277,10 @@
// value being declared, poison it as invalid so we don't get chains of
// errors.
declarator.setInvalidType(true);
+ } else if (S.getLangOpts().OpenCLVersion >= 200 && DS.isTypeSpecPipe()){
+ S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
+ << DS.getSourceRange();
+ declarator.setInvalidType(true);
} else {
S.Diag(DeclLoc, diag::ext_missing_type_specifier)
<< DS.getSourceRange();
@@ -1504,14 +1512,17 @@
// template type parameter.
Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
} else {
- Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false);
+ Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
}
break;
+ case DeclSpec::TST_auto_type:
+ Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false);
+ break;
+
case DeclSpec::TST_decltype_auto:
- Result = Context.getAutoType(QualType(),
- /*decltype(auto)*/true,
- /*IsDependent*/ false);
+ Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,
+ /*IsDependent*/ false);
break;
case DeclSpec::TST_unknown_anytype:
@@ -1562,8 +1573,9 @@
// Apply any type attributes from the decl spec. This may cause the
// list of type attributes to be temporarily saved while the type
// attributes are pushed around.
- if (AttributeList *attrs = DS.getAttributes().getList())
- processTypeAttrs(state, Result, TAL_DeclSpec, attrs);
+ // pipe attributes will be handled later ( at GetFullTypeForDeclarator )
+ if (!DS.isTypeSpecPipe())
+ processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList());
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -1923,6 +1935,21 @@
return Context.getRValueReferenceType(T);
}
+/// \brief Build a Pipe type.
+///
+/// \param T The type to which we'll be building a Pipe.
+///
+/// \param Loc We do not use it for now.
+///
+/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a
+/// NULL type.
+QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) {
+ assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
+
+ // Build the pipe type.
+ return Context.getPipeType(T);
+}
+
/// Check whether the specified array size makes the array type a VLA. If so,
/// return true, if not, return the size of the array in SizeVal.
static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
@@ -1997,7 +2024,7 @@
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
if (!MPTy->getClass()->isDependentType())
- RequireCompleteType(Loc, T, 0);
+ (void)isCompleteType(Loc, T);
} else {
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
@@ -2125,12 +2152,9 @@
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
QualType BaseT = Context.getBaseElementType(T);
- if (!T->isDependentType() &&
- !RequireCompleteType(Loc, BaseT, 0) &&
- !BaseT.isPODType(Context) &&
- !BaseT->isObjCLifetimeType()) {
- Diag(Loc, diag::err_vla_non_pod)
- << BaseT;
+ if (!T->isDependentType() && isCompleteType(Loc, BaseT) &&
+ !BaseT.isPODType(Context) && !BaseT->isObjCLifetimeType()) {
+ Diag(Loc, diag::err_vla_non_pod) << BaseT;
return QualType();
}
// Prohibit the use of VLAs during template argument deduction.
@@ -2144,7 +2168,7 @@
} else if (ASM != ArrayType::Normal || Quals != 0)
Diag(Loc,
getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx
- : diag::ext_c99_array_usage) << ASM;
+ : diag::ext_c99_array_usage) << ASM;
}
if (T->isVariableArrayType()) {
@@ -2395,6 +2419,7 @@
case DeclaratorChunk::Array: // suppress if written (id[])?
case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return;
}
}
@@ -2457,14 +2482,14 @@
return;
struct Qual {
- unsigned Mask;
const char *Name;
+ unsigned Mask;
SourceLocation Loc;
} const QualKinds[4] = {
- { DeclSpec::TQ_const, "const", ConstQualLoc },
- { DeclSpec::TQ_volatile, "volatile", VolatileQualLoc },
- { DeclSpec::TQ_restrict, "restrict", RestrictQualLoc },
- { DeclSpec::TQ_atomic, "_Atomic", AtomicQualLoc }
+ { "const", DeclSpec::TQ_const, ConstQualLoc },
+ { "volatile", DeclSpec::TQ_volatile, VolatileQualLoc },
+ { "restrict", DeclSpec::TQ_restrict, RestrictQualLoc },
+ { "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc }
};
SmallString<32> QualStr;
@@ -2534,6 +2559,7 @@
case DeclaratorChunk::Reference:
case DeclaratorChunk::Array:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
// FIXME: We can't currently provide an accurate source location and a
// fix-it hint for these.
unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0;
@@ -2573,8 +2599,6 @@
// The TagDecl owned by the DeclSpec.
TagDecl *OwnedTagDecl = nullptr;
- bool ContainsPlaceholderType = false;
-
switch (D.getName().getKind()) {
case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_OperatorFunctionId:
@@ -2582,7 +2606,6 @@
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(state);
- ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType();
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
@@ -2597,8 +2620,8 @@
// Constructors and destructors don't have return types. Use
// "void" instead.
T = SemaRef.Context.VoidTy;
- if (AttributeList *attrs = D.getDeclSpec().getAttributes().getList())
- processTypeAttrs(state, T, TAL_DeclSpec, attrs);
+ processTypeAttrs(state, T, TAL_DeclSpec,
+ D.getDeclSpec().getAttributes().getList());
break;
case UnqualifiedId::IK_ConversionFunctionId:
@@ -2606,7 +2629,6 @@
// converts to.
T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
&ReturnTypeInfo);
- ContainsPlaceholderType = T->getContainedAutoType();
break;
}
@@ -2614,17 +2636,10 @@
distributeTypeAttrsFromDeclarator(state, T);
// C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
- // In C++11, a function declarator using 'auto' must have a trailing return
- // type (this is checked later) and we can skip this. In other languages
- // using auto, we need to check regardless.
- // C++14 In generic lambdas allow 'auto' in their parameters.
- if (ContainsPlaceholderType &&
- (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
+ if (D.getDeclSpec().containsPlaceholderType()) {
int Error = -1;
switch (D.getContext()) {
- case Declarator::KNRTypeListContext:
- llvm_unreachable("K&R type lists aren't allowed in C++");
case Declarator::LambdaExprContext:
llvm_unreachable("Can't specify a type specifier in lambda grammar");
case Declarator::ObjCParameterContext:
@@ -2633,69 +2648,88 @@
Error = 0;
break;
case Declarator::LambdaExprParameterContext:
+ // In C++14, generic lambdas allow 'auto' in their parameters.
if (!(SemaRef.getLangOpts().CPlusPlus14
&& D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
- Error = 14;
+ Error = 16;
break;
- case Declarator::MemberContext:
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+ case Declarator::MemberContext: {
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+ D.isFunctionDeclarator())
break;
+ bool Cxx = SemaRef.getLangOpts().CPlusPlus;
switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
case TTK_Enum: llvm_unreachable("unhandled tag kind");
- case TTK_Struct: Error = 1; /* Struct member */ break;
- case TTK_Union: Error = 2; /* Union member */ break;
- case TTK_Class: Error = 3; /* Class member */ break;
- case TTK_Interface: Error = 4; /* Interface member */ break;
+ case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break;
+ case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break;
+ case TTK_Class: Error = 5; /* Class member */ break;
+ case TTK_Interface: Error = 6; /* Interface member */ break;
}
break;
+ }
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
- Error = 5; // Exception declaration
+ Error = 7; // Exception declaration
break;
case Declarator::TemplateParamContext:
- Error = 6; // Template parameter
+ Error = 8; // Template parameter
break;
case Declarator::BlockLiteralContext:
- Error = 7; // Block literal
+ Error = 9; // Block literal
break;
case Declarator::TemplateTypeArgContext:
- Error = 8; // Template type argument
+ Error = 10; // Template type argument
break;
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
- Error = 10; // Type alias
+ Error = 12; // Type alias
break;
case Declarator::TrailingReturnContext:
- if (!SemaRef.getLangOpts().CPlusPlus14)
- Error = 11; // Function return type
+ if (!SemaRef.getLangOpts().CPlusPlus14 ||
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ Error = 13; // Function return type
break;
case Declarator::ConversionIdContext:
- if (!SemaRef.getLangOpts().CPlusPlus14)
- Error = 12; // conversion-type-id
+ if (!SemaRef.getLangOpts().CPlusPlus14 ||
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ Error = 14; // conversion-type-id
break;
case Declarator::TypeNameContext:
- Error = 13; // Generic
+ Error = 15; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
case Declarator::ForContext:
case Declarator::ConditionContext:
+ break;
case Declarator::CXXNewContext:
+ if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ Error = 17; // 'new' type
+ break;
+ case Declarator::KNRTypeListContext:
+ Error = 18; // K&R function parameter
break;
}
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- Error = 9;
-
- // In Objective-C it is an error to use 'auto' on a function declarator.
- if (D.isFunctionDeclarator())
Error = 11;
+ // In Objective-C it is an error to use 'auto' on a function declarator
+ // (and everywhere for '__auto_type').
+ if (D.isFunctionDeclarator() &&
+ (!SemaRef.getLangOpts().CPlusPlus11 ||
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type))
+ Error = 13;
+
+ bool HaveTrailing = false;
+
// C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (SemaRef.getLangOpts().CPlusPlus11 && Error != -1) {
+ // We don't support '__auto_type' with trailing return types.
+ if (SemaRef.getLangOpts().CPlusPlus11 &&
+ D.getDeclSpec().getTypeSpecType() != DeclSpec::TST_auto_type) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -2703,6 +2737,7 @@
if (DeclType.Kind == DeclaratorChunk::Function) {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
if (FTI.hasTrailingReturnType()) {
+ HaveTrailing = true;
Error = -1;
break;
}
@@ -2715,22 +2750,31 @@
AutoRange = D.getName().getSourceRange();
if (Error != -1) {
- const bool IsDeclTypeAuto =
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto;
+ unsigned Keyword;
+ switch (D.getDeclSpec().getTypeSpecType()) {
+ case DeclSpec::TST_auto: Keyword = 0; break;
+ case DeclSpec::TST_decltype_auto: Keyword = 1; break;
+ case DeclSpec::TST_auto_type: Keyword = 2; break;
+ default: llvm_unreachable("unknown auto TypeSpecType");
+ }
SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
- << IsDeclTypeAuto << Error << AutoRange;
+ << Keyword << Error << AutoRange;
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
- } else
+ } else if (!HaveTrailing) {
+ // If there was a trailing return type, we already got
+ // warn_cxx98_compat_trailing_return_type in the parser.
SemaRef.Diag(AutoRange.getBegin(),
diag::warn_cxx98_compat_auto_type_specifier)
<< AutoRange;
+ }
}
if (SemaRef.getLangOpts().CPlusPlus &&
OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) {
// Check the contexts where C++ forbids the declaration of a new class
// or enumeration in a type-specifier-seq.
+ unsigned DiagID = 0;
switch (D.getContext()) {
case Declarator::TrailingReturnContext:
// Class and enumeration definitions are syntactically not allowed in
@@ -2750,10 +2794,7 @@
case Declarator::AliasDeclContext:
break;
case Declarator::AliasTemplateContext:
- SemaRef.Diag(OwnedTagDecl->getLocation(),
- diag::err_type_defined_in_alias_template)
- << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
- D.setInvalidType(true);
+ DiagID = diag::err_type_defined_in_alias_template;
break;
case Declarator::TypeNameContext:
case Declarator::ConversionIdContext:
@@ -2762,10 +2803,7 @@
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
case Declarator::TemplateTypeArgContext:
- SemaRef.Diag(OwnedTagDecl->getLocation(),
- diag::err_type_defined_in_type_specifier)
- << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
- D.setInvalidType(true);
+ DiagID = diag::err_type_defined_in_type_specifier;
break;
case Declarator::PrototypeContext:
case Declarator::LambdaExprParameterContext:
@@ -2774,20 +2812,21 @@
case Declarator::KNRTypeListContext:
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
- SemaRef.Diag(OwnedTagDecl->getLocation(),
- diag::err_type_defined_in_param_type)
- << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
- D.setInvalidType(true);
+ DiagID = diag::err_type_defined_in_param_type;
break;
case Declarator::ConditionContext:
// C++ 6.4p2:
// The type-specifier-seq shall not contain typedef and shall not declare
// a new class or enumeration.
- SemaRef.Diag(OwnedTagDecl->getLocation(),
- diag::err_type_defined_in_condition);
- D.setInvalidType(true);
+ DiagID = diag::err_type_defined_in_condition;
break;
}
+
+ if (DiagID != 0) {
+ SemaRef.Diag(OwnedTagDecl->getLocation(), DiagID)
+ << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
+ }
}
assert(!T.isNull() && "This function should not return a null type");
@@ -3046,6 +3085,7 @@
switch (chunk.Kind) {
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pipe:
break;
case DeclaratorChunk::BlockPointer:
@@ -3298,6 +3338,8 @@
case DeclaratorChunk::Array:
DiagKind = 2;
break;
+ case DeclaratorChunk::Pipe:
+ break;
}
S.Diag(DeclChunk.Loc, DiagId) << DiagKind;
@@ -3363,6 +3405,7 @@
switch (chunk.Kind) {
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pipe:
break;
case DeclaratorChunk::BlockPointer:
@@ -3682,6 +3725,7 @@
break;
case DeclaratorChunk::Function:
case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Pipe:
// These are invalid anyway, so just ignore.
break;
}
@@ -3733,7 +3777,7 @@
D.setInvalidType(true);
} else if (D.getContext() != Declarator::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
- cast<AutoType>(T)->isDecltypeAuto())) {
+ cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -4031,7 +4075,7 @@
break;
}
- case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::MemberPointer: {
// The scope spec must refer to a class, or be dependent.
CXXScopeSpec &SS = DeclType.Mem.Scope();
QualType ClsType;
@@ -4091,14 +4135,20 @@
break;
}
+ case DeclaratorChunk::Pipe: {
+ T = S.BuildPipeType(T, DeclType.Loc );
+ break;
+ }
+ }
+
if (T.isNull()) {
D.setInvalidType(true);
T = Context.IntTy;
}
// See if there are any attributes on this declarator chunk.
- if (AttributeList *attrs = const_cast<AttributeList*>(DeclType.getAttrs()))
- processTypeAttrs(state, T, TAL_DeclChunk, attrs);
+ processTypeAttrs(state, T, TAL_DeclChunk,
+ const_cast<AttributeList *>(DeclType.getAttrs()));
}
assert(!T.isNull() && "T must not be null after this point");
@@ -4191,8 +4241,7 @@
}
// Apply any undistributed attributes from the declarator.
- if (AttributeList *attrs = D.getAttributes())
- processTypeAttrs(state, T, TAL_DeclName, attrs);
+ processTypeAttrs(state, T, TAL_DeclName, D.getAttributes());
// Diagnose any ignored type attributes.
state.diagnoseIgnoredTypeAttrs(T);
@@ -4386,6 +4435,7 @@
case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return;
}
}
@@ -4437,6 +4487,7 @@
case AttributedType::attr_objc_gc:
return AttributeList::AT_ObjCGC;
case AttributedType::attr_objc_ownership:
+ case AttributedType::attr_objc_inert_unsafe_unretained:
return AttributeList::AT_ObjCOwnership;
case AttributedType::attr_noreturn:
return AttributeList::AT_NoReturn;
@@ -4675,6 +4726,14 @@
}
}
+ void VisitPipeTypeLoc(PipeTypeLoc TL) {
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ }
+
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(Context, DS.getTypeSpecTypeLoc());
@@ -4795,6 +4854,10 @@
TL.setLParenLoc(Chunk.Loc);
TL.setRParenLoc(Chunk.EndLoc);
}
+ void VisitPipeTypeLoc(PipeTypeLoc TL) {
+ assert(Chunk.Kind == DeclaratorChunk::Pipe);
+ TL.setKWLoc(Chunk.Loc);
+ }
void VisitTypeLoc(TypeLoc TL) {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
@@ -4808,6 +4871,7 @@
case DeclaratorChunk::Function:
case DeclaratorChunk::Array:
case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pipe:
llvm_unreachable("cannot be _Atomic qualified");
case DeclaratorChunk::Pointer:
@@ -5161,6 +5225,25 @@
<< TDS_ObjCObjOrBlock << type;
}
+ // Don't actually add the __unsafe_unretained qualifier in non-ARC files,
+ // because having both 'T' and '__unsafe_unretained T' exist in the type
+ // system causes unfortunate widespread consistency problems. (For example,
+ // they're not considered compatible types, and we mangle them identicially
+ // as template arguments.) These problems are all individually fixable,
+ // but it's easier to just not add the qualifier and instead sniff it out
+ // in specific places using isObjCInertUnsafeUnretainedType().
+ //
+ // Doing this does means we miss some trivial consistency checks that
+ // would've triggered in ARC, but that's better than trying to solve all
+ // the coexistence problems with __unsafe_unretained.
+ if (!S.getLangOpts().ObjCAutoRefCount &&
+ lifetime == Qualifiers::OCL_ExplicitNone) {
+ type = S.Context.getAttributedType(
+ AttributedType::attr_objc_inert_unsafe_unretained,
+ type, type);
+ return true;
+ }
+
QualType origType = type;
if (!NonObjCPointer)
type = S.Context.getQualifiedType(underlyingType);
@@ -5171,6 +5254,18 @@
type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
origType, type);
+ auto diagnoseOrDelay = [](Sema &S, SourceLocation loc,
+ unsigned diagnostic, QualType type) {
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(
+ S.getSourceManager().getExpansionLoc(loc),
+ diagnostic, type, /*ignored*/ 0));
+ } else {
+ S.Diag(loc, diagnostic);
+ }
+ };
+
// Sometimes, __weak isn't allowed.
if (lifetime == Qualifiers::OCL_Weak &&
!S.getLangOpts().ObjCWeak && !NonObjCPointer) {
@@ -5181,26 +5276,12 @@
: diag::err_arc_weak_no_runtime);
// In any case, delay the diagnostic until we know what we're parsing.
- if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
- S.DelayedDiagnostics.add(
- sema::DelayedDiagnostic::makeForbiddenType(
- S.getSourceManager().getExpansionLoc(AttrLoc),
- diagnostic, type, /*ignored*/ 0));
- } else {
- S.Diag(AttrLoc, diagnostic);
- }
+ diagnoseOrDelay(S, AttrLoc, diagnostic, type);
attr.setInvalid();
return true;
}
- // If we accepted __weak, we might still need to warn about it.
- if (lifetime == Qualifiers::OCL_Weak &&
- !S.getLangOpts().ObjCAutoRefCount &&
- S.getLangOpts().ObjCWeak) {
- S.Diag(AttrLoc, diag::warn_objc_weak_compat);
- }
-
// Forbid __weak for class objects marked as
// objc_arc_weak_reference_unavailable
if (lifetime == Qualifiers::OCL_Weak) {
@@ -5452,9 +5533,12 @@
// Pointer type qualifiers can only operate on pointer types, but not
// pointer-to-member types.
if (!isa<PointerType>(Desugared)) {
- S.Diag(Attr.getLoc(), Type->isMemberPointerType() ?
- diag::err_attribute_no_member_pointers :
- diag::err_attribute_pointers_only) << Attr.getName();
+ if (Type->isMemberPointerType())
+ S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers)
+ << Attr.getName();
+ else
+ S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
+ << Attr.getName() << 0;
return true;
}
@@ -5719,6 +5803,7 @@
// Don't walk through these.
case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pipe:
return false;
}
}
@@ -6151,10 +6236,11 @@
// type, but others can be present in the type specifiers even though they
// apply to the decl. Here we apply type attributes and ignore the rest.
- AttributeList *next;
- do {
+ bool hasOpenCLAddressSpace = false;
+ while (attrs) {
AttributeList &attr = *attrs;
- next = attr.getNext();
+ attrs = attr.getNext(); // reset to the next here due to early loop continue
+ // stmts
// Skip attributes that were marked to be invalid.
if (attr.isInvalid())
@@ -6213,6 +6299,7 @@
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
+ hasOpenCLAddressSpace = true;
break;
OBJC_POINTER_TYPE_ATTRS_CASELIST:
if (!handleObjCPointerTypeAttr(state, attr, type))
@@ -6308,7 +6395,83 @@
distributeFunctionTypeAttr(state, attr, type);
break;
}
- } while ((attrs = next));
+ }
+
+ // If address space is not set, OpenCL 2.0 defines non private default
+ // address spaces for some cases:
+ // OpenCL 2.0, section 6.5:
+ // The address space for a variable at program scope or a static variable
+ // inside a function can either be __global or __constant, but defaults to
+ // __global if not specified.
+ // (...)
+ // Pointers that are declared without pointing to a named address space point
+ // to the generic address space.
+ if (state.getSema().getLangOpts().OpenCLVersion >= 200 &&
+ !hasOpenCLAddressSpace && type.getAddressSpace() == 0 &&
+ (TAL == TAL_DeclSpec || TAL == TAL_DeclChunk)) {
+ Declarator &D = state.getDeclarator();
+ if (state.getCurrentChunkIndex() > 0 &&
+ D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
+ DeclaratorChunk::Pointer) {
+ type = state.getSema().Context.getAddrSpaceQualType(
+ type, LangAS::opencl_generic);
+ } else if (state.getCurrentChunkIndex() == 0 &&
+ D.getContext() == Declarator::FileContext &&
+ !D.isFunctionDeclarator() && !D.isFunctionDefinition() &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ !type->isSamplerT())
+ type = state.getSema().Context.getAddrSpaceQualType(
+ type, LangAS::opencl_global);
+ else if (state.getCurrentChunkIndex() == 0 &&
+ D.getContext() == Declarator::BlockContext &&
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+ type = state.getSema().Context.getAddrSpaceQualType(
+ type, LangAS::opencl_global);
+ }
+}
+
+void Sema::completeExprArrayBound(Expr *E) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
+ SourceLocation PointOfInstantiation = E->getExprLoc();
+
+ if (MemberSpecializationInfo *MSInfo =
+ Var->getMemberSpecializationInfo()) {
+ // If we don't already have a point of instantiation, this is it.
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ MSInfo->setPointOfInstantiation(PointOfInstantiation);
+
+ // This is a modification of an existing AST node. Notify
+ // listeners.
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
+ }
+ } else {
+ VarTemplateSpecializationDecl *VarSpec =
+ cast<VarTemplateSpecializationDecl>(Var);
+ if (VarSpec->getPointOfInstantiation().isInvalid())
+ VarSpec->setPointOfInstantiation(PointOfInstantiation);
+ }
+
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
+
+ // Update the type to the newly instantiated definition's type both
+ // here and within the expression.
+ if (VarDecl *Def = Var->getDefinition()) {
+ DRE->setDecl(Def);
+ QualType T = Def->getType();
+ DRE->setType(T);
+ // FIXME: Update the type on all intervening expressions.
+ E->setType(T);
+ }
+
+ // We still go on to try to complete the type independently, as it
+ // may also require instantiations or diagnostics if it remains
+ // incomplete.
+ }
+ }
+ }
}
/// \brief Ensure that the type of the given expression is complete.
@@ -6325,87 +6488,26 @@
///
/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
/// otherwise.
-bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser){
+bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
QualType T = E->getType();
- // Fast path the case where the type is already complete.
- if (!T->isIncompleteType())
- // FIXME: The definition might not be visible.
- return false;
-
// Incomplete array types may be completed by the initializer attached to
// their definitions. For static data members of class templates and for
// variable templates, we need to instantiate the definition to get this
// initializer and complete the type.
if (T->isIncompleteArrayType()) {
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
- SourceLocation PointOfInstantiation = E->getExprLoc();
-
- if (MemberSpecializationInfo *MSInfo =
- Var->getMemberSpecializationInfo()) {
- // If we don't already have a point of instantiation, this is it.
- if (MSInfo->getPointOfInstantiation().isInvalid()) {
- MSInfo->setPointOfInstantiation(PointOfInstantiation);
-
- // This is a modification of an existing AST node. Notify
- // listeners.
- if (ASTMutationListener *L = getASTMutationListener())
- L->StaticDataMemberInstantiated(Var);
- }
- } else {
- VarTemplateSpecializationDecl *VarSpec =
- cast<VarTemplateSpecializationDecl>(Var);
- if (VarSpec->getPointOfInstantiation().isInvalid())
- VarSpec->setPointOfInstantiation(PointOfInstantiation);
- }
-
- InstantiateVariableDefinition(PointOfInstantiation, Var);
-
- // Update the type to the newly instantiated definition's type both
- // here and within the expression.
- if (VarDecl *Def = Var->getDefinition()) {
- DRE->setDecl(Def);
- T = Def->getType();
- DRE->setType(T);
- E->setType(T);
- }
-
- // We still go on to try to complete the type independently, as it
- // may also require instantiations or diagnostics if it remains
- // incomplete.
- }
- }
- }
+ completeExprArrayBound(E);
+ T = E->getType();
}
// FIXME: Are there other cases which require instantiating something other
// than the type to complete the type of an expression?
- // Look through reference types and complete the referred type.
- if (const ReferenceType *Ref = T->getAs<ReferenceType>())
- T = Ref->getPointeeType();
-
return RequireCompleteType(E->getExprLoc(), T, Diagnoser);
}
-namespace {
- struct TypeDiagnoserDiag : Sema::TypeDiagnoser {
- unsigned DiagID;
-
- TypeDiagnoserDiag(unsigned DiagID)
- : Sema::TypeDiagnoser(DiagID == 0), DiagID(DiagID) {}
-
- void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
- if (Suppressed) return;
- S.Diag(Loc, DiagID) << T;
- }
- };
-}
-
bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
- TypeDiagnoserDiag Diagnoser(DiagID);
+ BoundTypeDiagnoser<> Diagnoser(DiagID);
return RequireCompleteExprType(E, Diagnoser);
}
@@ -6428,7 +6530,7 @@
/// @c false otherwise.
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser) {
- if (RequireCompleteTypeImpl(Loc, T, Diagnoser))
+ if (RequireCompleteTypeImpl(Loc, T, &Diagnoser))
return true;
if (const TagType *Tag = T->getAs<TagType>()) {
if (!Tag->getDecl()->isCompleteDefinitionRequired()) {
@@ -6532,7 +6634,7 @@
/// \brief The implementation of RequireCompleteType
bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
- TypeDiagnoser &Diagnoser) {
+ TypeDiagnoser *Diagnoser) {
// FIXME: Add this assertion to make sure we always get instantiation points.
// assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
// FIXME: Add this assertion to help us flush out problems with
@@ -6546,7 +6648,7 @@
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) {
if (!MPTy->getClass()->isDependentType()) {
- RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), 0);
+ (void)isCompleteType(Loc, QualType(MPTy->getClass(), 0));
assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl());
}
}
@@ -6557,9 +6659,16 @@
if (!T->isIncompleteType(&Def)) {
// If we know about the definition but it is not visible, complain.
NamedDecl *SuggestedDef = nullptr;
- if (!Diagnoser.Suppressed && Def &&
- !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true))
- diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true);
+ if (Def &&
+ !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) {
+ // If the user is going to see an error here, recover by making the
+ // definition visible.
+ bool TreatAsComplete = Diagnoser && !isSFINAEContext();
+ if (Diagnoser)
+ diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true,
+ /*Recover*/TreatAsComplete);
+ return !TreatAsComplete;
+ }
return false;
}
@@ -6575,6 +6684,9 @@
// chain for a declaration that can be accessed through a mechanism other
// than name lookup (eg, referenced in a template, or a variable whose type
// could be completed by the module)?
+ //
+ // FIXME: Should we map through to the base array element type before
+ // checking for a tag type?
if (Tag || IFace) {
NamedDecl *D =
Tag ? static_cast<NamedDecl *>(Tag->getDecl()) : IFace->getDecl();
@@ -6605,12 +6717,16 @@
= Context.getAsConstantArrayType(MaybeTemplate))
MaybeTemplate = Array->getElementType();
if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) {
+ bool Instantiated = false;
+ bool Diagnosed = false;
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
- if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared)
- return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec,
- TSK_ImplicitInstantiation,
- /*Complain=*/!Diagnoser.Suppressed);
+ if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
+ Diagnosed = InstantiateClassTemplateSpecialization(
+ Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ Instantiated = true;
+ }
} else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
@@ -6618,16 +6734,31 @@
MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo();
assert(MSI && "Missing member specialization information?");
// This record was instantiated from a class within a template.
- if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
- return InstantiateClass(Loc, Rec, Pattern,
- getTemplateInstantiationArgs(Rec),
- TSK_ImplicitInstantiation,
- /*Complain=*/!Diagnoser.Suppressed);
+ if (MSI->getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization) {
+ Diagnosed = InstantiateClass(Loc, Rec, Pattern,
+ getTemplateInstantiationArgs(Rec),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ Instantiated = true;
+ }
}
}
+
+ if (Instantiated) {
+ // Instantiate* might have already complained that the template is not
+ // defined, if we asked it to.
+ if (Diagnoser && Diagnosed)
+ return true;
+ // If we instantiated a definition, check that it's usable, even if
+ // instantiation produced an error, so that repeated calls to this
+ // function give consistent answers.
+ if (!T->isIncompleteType())
+ return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+ }
}
- if (Diagnoser.Suppressed)
+ if (!Diagnoser)
return true;
// We have an incomplete type. Produce a diagnostic.
@@ -6637,7 +6768,7 @@
return true;
}
- Diagnoser.diagnose(*this, Loc, T);
+ Diagnoser->diagnose(*this, Loc, T);
// If the type was a forward declaration of a class/struct/union
// type, produce a note.
@@ -6661,7 +6792,7 @@
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID) {
- TypeDiagnoserDiag Diagnoser(DiagID);
+ BoundTypeDiagnoser<> Diagnoser(DiagID);
return RequireCompleteType(Loc, T, Diagnoser);
}
@@ -6702,14 +6833,10 @@
assert(!T->isDependentType() && "type should not be dependent");
QualType ElemType = Context.getBaseElementType(T);
- RequireCompleteType(Loc, ElemType, 0);
-
- if (T->isLiteralType(Context))
+ if ((isCompleteType(Loc, ElemType) || ElemType->isVoidType()) &&
+ T->isLiteralType(Context))
return false;
- if (Diagnoser.Suppressed)
- return true;
-
Diagnoser.diagnose(*this, Loc, T);
if (T->isVariableArrayType())
@@ -6724,10 +6851,8 @@
// A partially-defined class type can't be a literal type, because a literal
// class type must have a trivial destructor (which can't be checked until
// the class definition is complete).
- if (!RD->isCompleteDefinition()) {
- RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T);
+ if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T))
return true;
- }
// If the class has virtual base classes, then it's not an aggregate, and
// cannot have any constexpr constructors or a trivial default constructor,
@@ -6779,7 +6904,7 @@
}
bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID) {
- TypeDiagnoserDiag Diagnoser(DiagID);
+ BoundTypeDiagnoser<> Diagnoser(DiagID);
return RequireLiteralType(Loc, T, Diagnoser);
}
@@ -6805,6 +6930,9 @@
if (ER.isInvalid()) return QualType();
E = ER.get();
+ if (!getLangOpts().CPlusPlus && E->refersToBitField())
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2;
+
if (!E->isTypeDependent()) {
QualType T = E->getType();
if (const TagType *TT = T->getAs<TagType>())
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 176e571..60c661c 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -391,7 +391,7 @@
/// due to transformation.
///
/// \returns true if an error occurred, false otherwise.
- bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall,
+ bool TransformExprs(Expr *const *Inputs, unsigned NumInputs, bool IsCall,
SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged = nullptr);
@@ -848,11 +848,11 @@
/// \brief Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
- QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) {
+ QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) {
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
- return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto,
+ return SemaRef.Context.getAutoType(Deduced, Keyword,
/*IsDependent*/ false);
}
@@ -1046,6 +1046,9 @@
/// Subclasses may override this routine to provide different behavior.
QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc);
+ /// \brief Build a new pipe type given its value type.
+ QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc);
+
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
@@ -1478,15 +1481,14 @@
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPScheduleClause(OpenMPScheduleClauseKind Kind,
- Expr *ChunkSize,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation KindLoc,
- SourceLocation CommaLoc,
- SourceLocation EndLoc) {
+ OMPClause *RebuildOMPScheduleClause(
+ OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
+ OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc,
+ SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) {
return getSema().ActOnOpenMPScheduleClause(
- Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
+ M1, M2, Kind, ChunkSize, StartLoc, LParenLoc, M1Loc, M2Loc, KindLoc,
+ CommaLoc, EndLoc);
}
/// \brief Build a new OpenMP 'ordered' clause.
@@ -1648,10 +1650,103 @@
OMPClause *RebuildOMPDeviceClause(Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, LParenLoc,
+ return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, LParenLoc,
EndLoc);
}
+ /// \brief Build a new OpenMP 'map' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPMapClause(
+ OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType,
+ SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPMapClause(MapTypeModifier, MapType, MapLoc,
+ ColonLoc, VarList,StartLoc,
+ LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'num_teams' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPNumTeamsClause(NumTeams, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'thread_limit' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPThreadLimitClause(Expr *ThreadLimit,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPThreadLimitClause(ThreadLimit, StartLoc,
+ LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'priority' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPPriorityClause(Expr *Priority, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPPriorityClause(Priority, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'grainsize' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPGrainsizeClause(Grainsize, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'num_tasks' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPNumTasksClause(NumTasks, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'hint' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPHintClause(Expr *Hint, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'dist_schedule' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *
+ RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind,
+ Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation KindLoc,
+ SourceLocation CommaLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDistScheduleClause(
+ Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
+ }
+
/// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -2685,9 +2780,8 @@
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCDictionaryLiteral(SourceRange Range,
- ObjCDictionaryElement *Elements,
- unsigned NumElements) {
- return getSema().BuildObjCDictionaryLiteral(Range, Elements, NumElements);
+ MutableArrayRef<ObjCDictionaryElement> Elements) {
+ return getSema().BuildObjCDictionaryLiteral(Range, Elements);
}
/// \brief Build a new Objective-C \@encode expression.
@@ -3121,7 +3215,7 @@
}
template<typename Derived>
-bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
+bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
unsigned NumInputs,
bool IsCall,
SmallVectorImpl<Expr *> &Outputs,
@@ -3502,7 +3596,7 @@
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
@@ -3888,7 +3982,7 @@
Qs.removeObjCLifetime();
Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
Qs);
- Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(),
+ Result = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
AutoTy->isDependentType());
TLB.TypeWasModifiedSafely(Result);
} else {
@@ -5091,7 +5185,7 @@
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
T->isDependentType()) {
- Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto());
+ Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword());
if (Result.isNull())
return QualType();
}
@@ -5246,6 +5340,26 @@
return Result;
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
+ PipeTypeLoc TL) {
+ QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc());
+ if (ValueType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) {
+ Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ PipeTypeLoc NewTL = TLB.push<PipeTypeLoc>(Result);
+ NewTL.setKWLoc(TL.getKWLoc());
+
+ return Result;
+}
+
/// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
@@ -6050,7 +6164,7 @@
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get(), S->getIfLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -6145,7 +6259,8 @@
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(
+ getSema().MakeFullExpr(Cond.get(), S->getWhileLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -6195,6 +6310,11 @@
if (Init.isInvalid())
return StmtError();
+ // In OpenMP loop region loop control variable must be captured and be
+ // private. Perform analysis of first part (if any).
+ if (getSema().getLangOpts().OpenMP && Init.isUsable())
+ getSema().ActOnOpenMPLoopInitialization(S->getForLoc(), Init.get());
+
// Transform the condition
ExprResult Cond;
VarDecl *ConditionVar = nullptr;
@@ -6224,7 +6344,8 @@
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(
+ getSema().MakeFullExpr(Cond.get(), S->getForLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -6894,6 +7015,25 @@
}
template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformMSPropertySubscriptExpr(
+ MSPropertySubscriptExpr *E) {
+ auto BaseRes = getDerived().TransformExpr(E->getBase());
+ if (BaseRes.isInvalid())
+ return ExprError();
+ auto IdxRes = getDerived().TransformExpr(E->getIdx());
+ if (IdxRes.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ BaseRes.get() == E->getBase() &&
+ IdxRes.get() == E->getIdx())
+ return E;
+
+ return getDerived().RebuildArraySubscriptExpr(
+ BaseRes.get(), SourceLocation(), IdxRes.get(), E->getRBracketLoc());
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock());
if (TryBlock.isInvalid())
@@ -6972,10 +7112,7 @@
}
}
StmtResult AssociatedStmt;
- if (D->hasAssociatedStmt()) {
- if (!D->getAssociatedStmt()) {
- return StmtError();
- }
+ if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
getDerived().getSema().ActOnOpenMPRegionStart(D->getDirectiveKind(),
/*CurScope=*/nullptr);
StmtResult Body;
@@ -7286,6 +7423,39 @@
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTaskLoopDirective(OMPTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_taskloop, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTaskLoopSimdDirective(
+ OMPTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_taskloop_simd, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
+ OMPDistributeDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clause transformation
//===----------------------------------------------------------------------===//
@@ -7371,7 +7541,9 @@
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPScheduleClause(
+ C->getFirstScheduleModifier(), C->getSecondScheduleModifier(),
C->getScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(),
+ C->getFirstScheduleModifierLoc(), C->getSecondScheduleModifierLoc(),
C->getScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd());
}
@@ -7457,6 +7629,13 @@
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPNogroupClause(OMPNogroupClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
@@ -7648,6 +7827,92 @@
E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPMapClause(
+ C->getMapTypeModifier(), C->getMapType(), C->getMapLoc(),
+ C->getColonLoc(), Vars, C->getLocStart(), C->getLParenLoc(),
+ C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNumTeamsClause(OMPNumTeamsClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getNumTeams());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPNumTeamsClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPThreadLimitClause(OMPThreadLimitClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getThreadLimit());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPThreadLimitClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPPriorityClause(OMPPriorityClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getPriority());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPPriorityClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPGrainsizeClause(OMPGrainsizeClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getGrainsize());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPGrainsizeClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNumTasksClause(OMPNumTasksClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getNumTasks());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPNumTasksClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPHintClause(OMPHintClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getHint());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPHintClause(E.get(), C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause(
+ OMPDistScheduleClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getChunkSize());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPDistScheduleClause(
+ C->getDistScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(),
+ C->getDistScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -7847,16 +8112,15 @@
// template code that we don't care.
bool ExprChanged = false;
typedef Sema::OffsetOfComponent Component;
- typedef OffsetOfExpr::OffsetOfNode Node;
SmallVector<Component, 4> Components;
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
- const Node &ON = E->getComponent(I);
+ const OffsetOfNode &ON = E->getComponent(I);
Component Comp;
Comp.isBrackets = true;
Comp.LocStart = ON.getSourceRange().getBegin();
Comp.LocEnd = ON.getSourceRange().getEnd();
switch (ON.getKind()) {
- case Node::Array: {
+ case OffsetOfNode::Array: {
Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex());
ExprResult Index = getDerived().TransformExpr(FromIndex);
if (Index.isInvalid())
@@ -7868,8 +8132,8 @@
break;
}
- case Node::Field:
- case Node::Identifier:
+ case OffsetOfNode::Field:
+ case OffsetOfNode::Identifier:
Comp.isBrackets = false;
Comp.U.IdentInfo = ON.getFieldName();
if (!Comp.U.IdentInfo)
@@ -7877,7 +8141,7 @@
break;
- case Node::Base:
+ case OffsetOfNode::Base:
// Will be recomputed during the rebuild.
continue;
}
@@ -9623,9 +9887,10 @@
VarDecl *OldVD = C->getCapturedVar();
QualType NewInitCaptureType =
- getSema().performLambdaInitCaptureInitialization(C->getLocation(),
- OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
- NewExprInit);
+ getSema().buildLambdaInitCaptureInitialization(
+ C->getLocation(), OldVD->getType()->isReferenceType(),
+ OldVD->getIdentifier(),
+ C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit);
NewExprInitResult = NewExprInit;
InitCaptureExprsAndTypes[C - E->capture_begin()] =
std::make_pair(NewExprInitResult, NewInitCaptureType);
@@ -9732,8 +9997,8 @@
}
VarDecl *OldVD = C->getCapturedVar();
VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
- OldVD->getLocation(), InitExprTypePair.second,
- OldVD->getIdentifier(), Init.get());
+ OldVD->getLocation(), InitExprTypePair.second, OldVD->getIdentifier(),
+ OldVD->getInitStyle(), Init.get());
if (!NewVD)
Invalid = true;
else {
@@ -10511,8 +10776,7 @@
return SemaRef.MaybeBindToTemporary(E);
return getDerived().RebuildObjCDictionaryLiteral(E->getSourceRange(),
- Elements.data(),
- Elements.size());
+ Elements);
}
template<typename Derived>
@@ -11133,6 +11397,12 @@
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
+ SourceLocation KWLoc) {
+ return SemaRef.BuildPipeType(ValueType, KWLoc);
+}
+
+template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index e59bc89..64f583c 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -29,6 +29,7 @@
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT,
UPD_CXX_RESOLVED_DTOR_DELETE,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 3265603..b61265b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1259,7 +1259,8 @@
= SourceMgr.getOrCreateContentCache(File,
/*isSystemFile=*/FileCharacter != SrcMgr::C_User);
if (OverriddenBuffer && !ContentCache->BufferOverridden &&
- ContentCache->ContentsEntry == ContentCache->OrigEntry) {
+ ContentCache->ContentsEntry == ContentCache->OrigEntry &&
+ !ContentCache->getRawBuffer()) {
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
@@ -1890,19 +1891,14 @@
"invalid record type for input file");
(void)Result;
- std::string Filename;
- off_t StoredSize;
- time_t StoredTime;
- bool Overridden;
-
assert(Record[0] == ID && "Bogus stored ID or offset");
- StoredSize = static_cast<off_t>(Record[1]);
- StoredTime = static_cast<time_t>(Record[2]);
- Overridden = static_cast<bool>(Record[3]);
- Filename = Blob;
- ResolveImportedPath(F, Filename);
-
- InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
+ InputFileInfo R;
+ R.StoredSize = static_cast<off_t>(Record[1]);
+ R.StoredTime = static_cast<time_t>(Record[2]);
+ R.Overridden = static_cast<bool>(Record[3]);
+ R.Transient = static_cast<bool>(Record[4]);
+ R.Filename = Blob;
+ ResolveImportedPath(F, R.Filename);
return R;
}
@@ -1927,11 +1923,10 @@
off_t StoredSize = FI.StoredSize;
time_t StoredTime = FI.StoredTime;
bool Overridden = FI.Overridden;
+ bool Transient = FI.Transient;
StringRef Filename = FI.Filename;
- const FileEntry *File
- = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
+ const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false);
// If we didn't find the file, resolve it relative to the
// original directory from which this AST file was created.
@@ -1946,9 +1941,8 @@
// For an overridden file, create a virtual file with the stored
// size/timestamp.
- if (Overridden && File == nullptr) {
+ if ((Overridden || Transient) && File == nullptr)
File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
- }
if (File == nullptr) {
if (Complain) {
@@ -1969,11 +1963,17 @@
// can lead to problems when lexing using the source locations from the
// PCH.
SourceManager &SM = getSourceManager();
- if (!Overridden && SM.isFileOverridden(File)) {
+ // FIXME: Reject if the overrides are different.
+ if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
if (Complain)
Error(diag::err_fe_pch_file_overridden, Filename);
// After emitting the diagnostic, recover by disabling the override so
// that the original file will be used.
+ //
+ // FIXME: This recovery is just as broken as the original state; there may
+ // be another precompiled module that's using the overridden contents, or
+ // we might be half way through parsing it. Instead, we should treat the
+ // overridden contents as belonging to a separate FileEntry.
SM.disableFileContentsOverride(File);
// The FileEntry is a virtual file entry with the size of the contents
// that would override the original contents. Set it to the original's
@@ -2024,8 +2024,10 @@
IsOutOfDate = true;
}
+ // FIXME: If the file is overridden and we've already opened it,
+ // issue an error (or split it into a separate FileEntry).
- InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+ InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate);
// Note that we've loaded this input file.
F.InputFilesLoaded[ID-1] = IF;
@@ -4697,6 +4699,13 @@
}
LangOpts.CommentOpts.ParseAllComments = Record[Idx++];
+ // OpenMP offloading options.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ LangOpts.OMPTargetTriples.push_back(llvm::Triple(ReadString(Record, Idx)));
+ }
+
+ LangOpts.OMPHostIRFile = ReadString(Record, Idx);
+
return Listener.ReadLanguageOptions(LangOpts, Complain,
AllowCompatibleDifferences);
}
@@ -5413,9 +5422,9 @@
case TYPE_AUTO: {
QualType Deduced = readType(*Loc.F, Record, Idx);
- bool IsDecltypeAuto = Record[Idx++];
+ AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++];
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
- return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
+ return Context.getAutoType(Deduced, Keyword, IsDependent);
}
case TYPE_RECORD: {
@@ -5631,6 +5640,17 @@
QualType ValueType = readType(*Loc.F, Record, Idx);
return Context.getAtomicType(ValueType);
}
+
+ case TYPE_PIPE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pipe type");
+ return QualType();
+ }
+
+ // Reading the pipe element type.
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ return Context.getPipeType(ElementType);
+ }
}
llvm_unreachable("Invalid TypeCode!");
}
@@ -5902,6 +5922,9 @@
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+}
TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
const RecordData &Record,
@@ -6421,6 +6444,12 @@
case PREDEF_DECL_MAKE_INTEGER_SEQ_ID:
return Context.getMakeIntegerSeqDecl();
+
+ case PREDEF_DECL_CF_CONSTANT_STRING_ID:
+ return Context.getCFConstantStringDecl();
+
+ case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID:
+ return Context.getCFConstantStringTagDecl();
}
llvm_unreachable("PredefinedDeclIDs unknown enum value");
}
@@ -7558,8 +7587,9 @@
// Chained PCH are not suported.
if (ModuleMgr.size() == 1) {
ModuleFile &MF = ModuleMgr.getPrimaryModule();
- return ASTReader::ASTSourceDescriptor(
- MF.OriginalSourceFileName, MF.OriginalDir, MF.FileName, MF.Signature);
+ StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName);
+ return ASTReader::ASTSourceDescriptor(ModuleName, MF.OriginalDir,
+ MF.FileName, MF.Signature);
}
return None;
}
@@ -7836,7 +7866,7 @@
TemplateParameterList* TemplateParams =
TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- Params.data(), Params.size(), RAngleLoc);
+ Params, RAngleLoc);
return TemplateParams;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 317846c..5bf95f8 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -412,9 +412,8 @@
template<typename DeclT>
llvm::iterator_range<MergedRedeclIterator<DeclT>> merged_redecls(DeclT *D) {
- return llvm::iterator_range<MergedRedeclIterator<DeclT>>(
- MergedRedeclIterator<DeclT>(D),
- MergedRedeclIterator<DeclT>());
+ return llvm::make_range(MergedRedeclIterator<DeclT>(D),
+ MergedRedeclIterator<DeclT>());
}
uint64_t ASTDeclReader::GetCurrentCursorOffset() {
@@ -477,6 +476,8 @@
// placeholder.
GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ if (!LexicalDCIDForTemplateParmDecl)
+ LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl;
Reader.addPendingDeclContextInfo(D,
SemaDCIDForTemplateParmDecl,
LexicalDCIDForTemplateParmDecl);
@@ -484,6 +485,8 @@
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ if (!LexicalDC)
+ LexicalDC = SemaDC;
DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
// Avoid calling setLexicalDeclContext() directly because it uses
// Decl::getASTContext() internally which is unsafe during derialization.
@@ -1728,7 +1731,7 @@
VisitDecl(D);
D->ImportedAndComplete.setPointer(readModule(Record, Idx));
D->ImportedAndComplete.setInt(Record[Idx++]);
- SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1);
+ SourceLocation *StoredLocs = D->getTrailingObjects<SourceLocation>();
for (unsigned I = 0, N = Record.back(); I != N; ++I)
StoredLocs[I] = ReadSourceLocation(Record, Idx);
++Idx; // The number of stored source locations.
@@ -1746,7 +1749,8 @@
else
D->Friend = GetTypeSourceInfo(Record, Idx);
for (unsigned i = 0; i != D->NumTPLists; ++i)
- D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->getTrailingObjects<TemplateParameterList *>()[i] =
+ Reader.ReadTemplateParameterList(F, Record, Idx);
D->NextFriend = ReadDeclID(Record, Idx);
D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
@@ -2095,10 +2099,11 @@
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
if (D->isExpandedParameterPack()) {
- void **Data = reinterpret_cast<void **>(D + 1);
+ auto TypesAndInfos =
+ D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
- Data[2*I] = Reader.readType(F, Record, Idx).getAsOpaquePtr();
- Data[2*I + 1] = GetTypeSourceInfo(Record, Idx);
+ new (&TypesAndInfos[I].first) QualType(Reader.readType(F, Record, Idx));
+ TypesAndInfos[I].second = GetTypeSourceInfo(Record, Idx);
}
} else {
// Rest of NonTypeTemplateParmDecl.
@@ -2114,7 +2119,8 @@
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
if (D->isExpandedParameterPack()) {
- void **Data = reinterpret_cast<void **>(D + 1);
+ TemplateParameterList **Data =
+ D->getTrailingObjects<TemplateParameterList *>();
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I)
Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
@@ -3620,6 +3626,21 @@
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
+ case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
+ auto Param = cast<ParmVarDecl>(D);
+
+ // We have to read the default argument regardless of whether we use it
+ // so that hypothetical further update records aren't messed up.
+ // TODO: Add a function to skip over the next expr record.
+ auto DefaultArg = Reader.ReadExpr(F);
+
+ // Only apply the update if the parameter still has an uninstantiated
+ // default argument.
+ if (Param->hasUninstantiatedDefaultArg())
+ Param->setDefaultArg(DefaultArg);
+ break;
+ }
+
case UPD_CXX_ADDED_FUNCTION_DEFINITION: {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (Reader.PendingBodies[FD]) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index ab82eee..3c2a98b 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -93,6 +93,7 @@
/// \brief Read and initialize a ExplicitTemplateArgumentList structure.
void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ TemplateArgumentLoc *ArgsLocArray,
unsigned NumTemplateArgs);
/// \brief Read and initialize a ExplicitTemplateArgumentList structure.
void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
@@ -105,9 +106,9 @@
};
}
-void ASTStmtReader::
-ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
- unsigned NumTemplateArgs) {
+void ASTStmtReader::ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ TemplateArgumentLoc *ArgsLocArray,
+ unsigned NumTemplateArgs) {
SourceLocation TemplateKWLoc = ReadSourceLocation(Record, Idx);
TemplateArgumentListInfo ArgInfo;
ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx));
@@ -115,7 +116,7 @@
for (unsigned i = 0; i != NumTemplateArgs; ++i)
ArgInfo.addArgument(
Reader.ReadTemplateArgumentLoc(F, Record, Idx));
- Args.initializeFrom(TemplateKWLoc, ArgInfo);
+ Args.initializeFrom(TemplateKWLoc, ArgInfo, ArgsLocArray);
}
void ASTStmtReader::VisitStmt(Stmt *S) {
@@ -134,7 +135,7 @@
unsigned NumStmts = Record[Idx++];
while (NumStmts--)
Stmts.push_back(Reader.ReadSubStmt());
- S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size());
+ S->setStmts(Reader.getContext(), Stmts);
S->LBraceLoc = ReadSourceLocation(Record, Idx);
S->RBraceLoc = ReadSourceLocation(Record, Idx);
}
@@ -459,15 +460,17 @@
NumTemplateArgs = Record[Idx++];
if (E->hasQualifier())
- E->getInternalQualifierLoc()
- = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ new (E->getTrailingObjects<NestedNameSpecifierLoc>())
+ NestedNameSpecifierLoc(
+ Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
if (E->hasFoundDecl())
- E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx);
+ *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(Record, Idx);
if (E->hasTemplateKWAndArgsInfo())
- ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
- NumTemplateArgs);
+ ReadTemplateKWAndArgsInfo(
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+ E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
@@ -547,7 +550,6 @@
}
void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
- typedef OffsetOfExpr::OffsetOfNode Node;
VisitExpr(E);
assert(E->getNumComponents() == Record[Idx]);
++Idx;
@@ -557,29 +559,29 @@
E->setRParenLoc(ReadSourceLocation(Record, Idx));
E->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
- Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+ OffsetOfNode::Kind Kind = static_cast<OffsetOfNode::Kind>(Record[Idx++]);
SourceLocation Start = ReadSourceLocation(Record, Idx);
SourceLocation End = ReadSourceLocation(Record, Idx);
switch (Kind) {
- case Node::Array:
- E->setComponent(I, Node(Start, Record[Idx++], End));
- break;
-
- case Node::Field:
- E->setComponent(I, Node(Start, ReadDeclAs<FieldDecl>(Record, Idx), End));
+ case OffsetOfNode::Array:
+ E->setComponent(I, OffsetOfNode(Start, Record[Idx++], End));
break;
- case Node::Identifier:
- E->setComponent(I,
- Node(Start,
- Reader.GetIdentifierInfo(F, Record, Idx),
- End));
+ case OffsetOfNode::Field:
+ E->setComponent(
+ I, OffsetOfNode(Start, ReadDeclAs<FieldDecl>(Record, Idx), End));
break;
-
- case Node::Base: {
+
+ case OffsetOfNode::Identifier:
+ E->setComponent(
+ I,
+ OffsetOfNode(Start, Reader.GetIdentifierInfo(F, Record, Idx), End));
+ break;
+
+ case OffsetOfNode::Base: {
CXXBaseSpecifier *Base = new (Reader.getContext()) CXXBaseSpecifier();
*Base = Reader.ReadCXXBaseSpecifier(F, Record, Idx);
- E->setComponent(I, Node(Base));
+ E->setComponent(I, OffsetOfNode(Base));
break;
}
}
@@ -985,8 +987,10 @@
assert(NumElements == E->getNumElements() && "Wrong number of elements");
bool HasPackExpansions = Record[Idx++];
assert(HasPackExpansions == E->HasPackExpansions &&"Pack expansion mismatch");
- ObjCDictionaryLiteral::KeyValuePair *KeyValues = E->getKeyValues();
- ObjCDictionaryLiteral::ExpansionData *Expansions = E->getExpansionData();
+ ObjCDictionaryLiteral::KeyValuePair *KeyValues =
+ E->getTrailingObjects<ObjCDictionaryLiteral::KeyValuePair>();
+ ObjCDictionaryLiteral::ExpansionData *Expansions =
+ E->getTrailingObjects<ObjCDictionaryLiteral::ExpansionData>();
for (unsigned I = 0; I != NumElements; ++I) {
KeyValues[I].Key = Reader.ReadSubExpr();
KeyValues[I].Value = Reader.ReadSubExpr();
@@ -1360,10 +1364,7 @@
void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
-
- assert((bool)Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
- ++Idx; // HasOtherExprStored and SubExpr was handled during creation.
- E->Param.setPointer(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ E->Param = ReadDeclAs<ParmVarDecl>(Record, Idx);
E->Loc = ReadSourceLocation(Record, Idx);
}
@@ -1443,7 +1444,8 @@
unsigned NumObjects = Record[Idx++];
assert(NumObjects == E->getNumObjects());
for (unsigned i = 0; i != NumObjects; ++i)
- E->getObjectsBuffer()[i] = ReadDeclAs<BlockDecl>(Record, Idx);
+ E->getTrailingObjects<BlockDecl *>()[i] =
+ ReadDeclAs<BlockDecl>(Record, Idx);
E->SubExpr = Reader.ReadSubExpr();
}
@@ -1453,8 +1455,10 @@
VisitExpr(E);
if (Record[Idx++]) // HasTemplateKWAndArgsInfo
- ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
- /*NumTemplateArgs=*/Record[Idx++]);
+ ReadTemplateKWAndArgsInfo(
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+ E->getTrailingObjects<TemplateArgumentLoc>(),
+ /*NumTemplateArgs=*/Record[Idx++]);
E->Base = Reader.ReadSubExpr();
E->BaseType = Reader.readType(F, Record, Idx);
@@ -1470,8 +1474,10 @@
VisitExpr(E);
if (Record[Idx++]) // HasTemplateKWAndArgsInfo
- ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
- /*NumTemplateArgs=*/Record[Idx++]);
+ ReadTemplateKWAndArgsInfo(
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+ E->getTrailingObjects<TemplateArgumentLoc>(),
+ /*NumTemplateArgs=*/Record[Idx++]);
E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
@@ -1493,7 +1499,8 @@
VisitExpr(E);
if (Record[Idx++]) // HasTemplateKWAndArgsInfo
- ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(),
+ E->getTrailingTemplateArgumentLoc(),
/*NumTemplateArgs=*/Record[Idx++]);
unsigned NumDecls = Record[Idx++];
@@ -1534,7 +1541,7 @@
E->Loc = Range.getBegin();
E->RParenLoc = Range.getEnd();
- TypeSourceInfo **Args = E->getTypeSourceInfos();
+ TypeSourceInfo **Args = E->getTrailingObjects<TypeSourceInfo *>();
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Args[I] = GetTypeSourceInfo(Record, Idx);
}
@@ -1582,7 +1589,7 @@
E->Pack = Reader.ReadDeclAs<NamedDecl>(F, Record, Idx);
if (E->isPartiallySubstituted()) {
assert(E->Length == NumPartialArgs);
- for (auto *I = reinterpret_cast<TemplateArgument *>(E + 1),
+ for (auto *I = E->getTrailingObjects<TemplateArgument>(),
*E = I + NumPartialArgs;
I != E; ++I)
new (I) TemplateArgument(Reader.ReadTemplateArgument(F, Record, Idx));
@@ -1617,7 +1624,7 @@
E->NumParameters = Record[Idx++];
E->ParamPack = ReadDeclAs<ParmVarDecl>(Record, Idx);
E->NameLoc = ReadSourceLocation(Record, Idx);
- ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1);
+ ParmVarDecl **Parms = E->getTrailingObjects<ParmVarDecl *>();
for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
Parms[i] = ReadDeclAs<ParmVarDecl>(Record, Idx);
}
@@ -1662,6 +1669,13 @@
E->TheDecl = ReadDeclAs<MSPropertyDecl>(Record, Idx);
}
+void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) {
+ VisitExpr(E);
+ E->setBase(Reader.ReadSubExpr());
+ E->setIdx(Reader.ReadSubExpr());
+ E->setRBracketLoc(ReadSourceLocation(Record, Idx));
+}
+
void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
VisitExpr(E);
E->setSourceRange(ReadSourceRange(Record, Idx));
@@ -1804,6 +1818,9 @@
case OMPC_simd:
C = new (Context) OMPSIMDClause();
break;
+ case OMPC_nogroup:
+ C = new (Context) OMPNogroupClause();
+ break;
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
@@ -1840,6 +1857,30 @@
case OMPC_device:
C = new (Context) OMPDeviceClause();
break;
+ case OMPC_map:
+ C = OMPMapClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_num_teams:
+ C = new (Context) OMPNumTeamsClause();
+ break;
+ case OMPC_thread_limit:
+ C = new (Context) OMPThreadLimitClause();
+ break;
+ case OMPC_priority:
+ C = new (Context) OMPPriorityClause();
+ break;
+ case OMPC_grainsize:
+ C = new (Context) OMPGrainsizeClause();
+ break;
+ case OMPC_num_tasks:
+ C = new (Context) OMPNumTasksClause();
+ break;
+ case OMPC_hint:
+ C = new (Context) OMPHintClause();
+ break;
+ case OMPC_dist_schedule:
+ C = new (Context) OMPDistScheduleClause();
+ break;
}
Visit(C);
C->setLocStart(Reader->ReadSourceLocation(Record, Idx));
@@ -1898,9 +1939,15 @@
void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
C->setScheduleKind(
static_cast<OpenMPScheduleClauseKind>(Record[Idx++]));
+ C->setFirstScheduleModifier(
+ static_cast<OpenMPScheduleClauseModifier>(Record[Idx++]));
+ C->setSecondScheduleModifier(
+ static_cast<OpenMPScheduleClauseModifier>(Record[Idx++]));
C->setChunkSize(Reader->Reader.ReadSubExpr());
C->setHelperChunkSize(Reader->Reader.ReadSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setFirstScheduleModifierLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setSecondScheduleModifierLoc(Reader->ReadSourceLocation(Record, Idx));
C->setScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx));
C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
}
@@ -1930,6 +1977,8 @@
void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {}
+void OMPClauseReader::VisitOMPNogroupClause(OMPNogroupClause *) {}
+
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
@@ -2147,6 +2196,63 @@
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
}
+void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setMapTypeModifier(
+ static_cast<OpenMPMapClauseKind>(Record[Idx++]));
+ C->setMapType(
+ static_cast<OpenMPMapClauseKind>(Record[Idx++]));
+ C->setMapLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ auto NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i) {
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ }
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
+ C->setNumTeams(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
+ C->setThreadLimit(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) {
+ C->setPriority(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
+ C->setGrainsize(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
+ C->setNumTasks(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPHintClause(OMPHintClause *C) {
+ C->setHint(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) {
+ C->setDistScheduleKind(
+ static_cast<OpenMPDistScheduleClauseKind>(Record[Idx++]));
+ C->setChunkSize(Reader->Reader.ReadSubExpr());
+ C->setHelperChunkSize(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setDistScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//
@@ -2256,6 +2362,8 @@
void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
VisitOMPExecutableDirective(D);
ReadDeclarationNameInfo(D->DirName, Record, Idx);
}
@@ -2369,6 +2477,18 @@
D->setCancelRegion(static_cast<OpenMPDirectiveKind>(Record[Idx++]));
}
+void ASTStmtReader::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
//===----------------------------------------------------------------------===//
// ASTReader Implementation
//===----------------------------------------------------------------------===//
@@ -2907,7 +3027,8 @@
break;
case STMT_OMP_CRITICAL_DIRECTIVE:
- S = OMPCriticalDirective::CreateEmpty(Context, Empty);
+ S = OMPCriticalDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
case STMT_OMP_PARALLEL_FOR_DIRECTIVE: {
@@ -2991,6 +3112,30 @@
Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
+ case STMT_OMP_TASKLOOP_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPTaskLoopDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
+ case STMT_OMP_TASKLOOP_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPTaskLoopSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_DISTRIBUTE_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPDistributeDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(Context, Empty);
break;
@@ -3058,6 +3203,9 @@
case EXPR_CXX_PROPERTY_REF_EXPR:
S = new (Context) MSPropertyRefExpr(Empty);
break;
+ case EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR:
+ S = new (Context) MSPropertySubscriptExpr(Empty);
+ break;
case EXPR_CXX_UUIDOF_TYPE:
S = new (Context) CXXUuidofExpr(Empty, false);
break;
@@ -3067,16 +3215,9 @@
case EXPR_CXX_THROW:
S = new (Context) CXXThrowExpr(Empty);
break;
- case EXPR_CXX_DEFAULT_ARG: {
- bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields];
- if (HasOtherExprStored) {
- Expr *SubExpr = ReadSubExpr();
- S = CXXDefaultArgExpr::Create(Context, SourceLocation(), nullptr,
- SubExpr);
- } else
- S = new (Context) CXXDefaultArgExpr(Empty);
+ case EXPR_CXX_DEFAULT_ARG:
+ S = new (Context) CXXDefaultArgExpr(Empty);
break;
- }
case EXPR_CXX_DEFAULT_INIT:
S = new (Context) CXXDefaultInitExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 9b0a9b1..0b28a7a 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1,4 +1,4 @@
-//===--- ASTWriter.cpp - AST File Writer ----------------------------------===//
+//===--- ASTWriter.cpp - AST File Writer ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -60,6 +60,7 @@
#include <cstdio>
#include <string.h>
#include <utility>
+
using namespace clang;
using namespace clang::serialization;
@@ -102,7 +103,7 @@
#define ABSTRACT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
};
-}
+} // end anonymous namespace
void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
llvm_unreachable("Built-in types are never serialized");
@@ -281,7 +282,7 @@
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Writer.AddTypeRef(T->getDeducedType(), Record);
- Record.push_back(T->isDecltypeAuto());
+ Record.push_back((unsigned)T->getKeyword());
if (T->getDeducedType().isNull())
Record.push_back(T->isDependentType());
Code = TYPE_AUTO;
@@ -333,9 +334,8 @@
Record.push_back(T->isDependentType());
Writer.AddTemplateName(T->getTemplateName(), Record);
Record.push_back(T->getNumArgs());
- for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
- ArgI != ArgE; ++ArgI)
- Writer.AddTemplateArgument(*ArgI, Record);
+ for (const auto &ArgI : *T)
+ Writer.AddTemplateArgument(ArgI, Record);
Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
@@ -385,9 +385,8 @@
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
Writer.AddIdentifierRef(T->getIdentifier(), Record);
Record.push_back(T->getNumArgs());
- for (DependentTemplateSpecializationType::iterator
- I = T->begin(), E = T->end(); I != E; ++I)
- Writer.AddTemplateArgument(*I, Record);
+ for (const auto &I : *T)
+ Writer.AddTemplateArgument(I, Record);
Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
}
@@ -447,6 +446,12 @@
Code = TYPE_ATOMIC;
}
+void
+ASTTypeWriter::VisitPipeType(const PipeType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Code = TYPE_PIPE;
+}
+
namespace {
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
@@ -466,7 +471,7 @@
void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
};
-}
+} // end anonymous namespace
void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
// nothing to do
@@ -673,6 +678,9 @@
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
+void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+}
void ASTWriter::WriteTypeAbbrevs() {
using namespace llvm;
@@ -1182,7 +1190,7 @@
RecordData Record;
// Metadata
- BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
+ auto *MetadataAbbrev = new BitCodeAbbrev();
MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
@@ -1215,7 +1223,7 @@
}
// Module name
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
@@ -1235,7 +1243,7 @@
.ModuleMapFileHomeIsCwd ||
WritingModule->Directory->getName() != StringRef(".")) {
// Module directory.
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
@@ -1319,14 +1327,18 @@
// Comment options.
Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
- for (CommentOptions::BlockCommandNamesTy::const_iterator
- I = LangOpts.CommentOpts.BlockCommandNames.begin(),
- IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
- I != IEnd; ++I) {
- AddString(*I, Record);
+ for (const auto &I : LangOpts.CommentOpts.BlockCommandNames) {
+ AddString(I, Record);
}
Record.push_back(LangOpts.CommentOpts.ParseAllComments);
+ // OpenMP offloading options.
+ Record.push_back(LangOpts.OMPTargetTriples.size());
+ for (auto &T : LangOpts.OMPTargetTriples)
+ AddString(T.getTriple(), Record);
+
+ AddString(LangOpts.OMPHostIRFile, Record);
+
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
// Target options.
@@ -1441,7 +1453,7 @@
// Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
+ auto *FileAbbrev = new BitCodeAbbrev();
FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
@@ -1459,7 +1471,7 @@
// Original PCH directory
if (!OutputFile.empty() && OutputFile != "-") {
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
@@ -1485,9 +1497,10 @@
struct InputFileEntry {
const FileEntry *File;
bool IsSystemFile;
+ bool IsTransient;
bool BufferOverridden;
};
-}
+} // end anonymous namespace
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
@@ -1496,12 +1509,13 @@
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
// Create input-file abbreviation.
- BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
+ auto *IFAbbrev = new BitCodeAbbrev();
IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
@@ -1523,6 +1537,7 @@
InputFileEntry Entry;
Entry.File = Cache->OrigEntry;
Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.IsTransient = Cache->IsTransient;
Entry.BufferOverridden = Cache->BufferOverridden;
if (Cache->IsSystemFile)
SortedFiles.push_back(Entry);
@@ -1533,10 +1548,7 @@
unsigned UserFilesNum = 0;
// Write out all of the input files.
std::vector<uint64_t> InputFileOffsets;
- for (std::deque<InputFileEntry>::iterator
- I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
- const InputFileEntry &Entry = *I;
-
+ for (const auto &Entry : SortedFiles) {
uint32_t &InputFileID = InputFileIDs[Entry.File];
if (InputFileID != 0)
continue; // already recorded this file.
@@ -1552,8 +1564,12 @@
// Emit size/modification time for this file.
// And whether this file was overridden.
RecordData::value_type Record[] = {
- INPUT_FILE, InputFileOffsets.size(), (uint64_t)Entry.File->getSize(),
- (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden};
+ INPUT_FILE,
+ InputFileOffsets.size(),
+ (uint64_t)Entry.File->getSize(),
+ (uint64_t)getTimestampForOutput(Entry.File),
+ Entry.BufferOverridden,
+ Entry.IsTransient};
EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
}
@@ -1561,7 +1577,7 @@
Stream.ExitBlock();
// Create input file offsets abbreviation.
- BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
+ auto *OffsetsAbbrev = new BitCodeAbbrev();
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
@@ -1583,7 +1599,8 @@
/// file.
static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
@@ -1601,7 +1618,8 @@
/// buffer.
static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
@@ -1615,7 +1633,8 @@
/// buffer's blob.
static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
return Stream.EmitAbbrev(Abbrev);
@@ -1625,7 +1644,8 @@
/// expansion.
static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
@@ -1804,7 +1824,8 @@
// Create a blob abbreviation
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
@@ -1902,7 +1923,7 @@
Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
- if (Content->BufferOverridden) {
+ if (Content->BufferOverridden || Content->IsTransient) {
RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB};
const llvm::MemoryBuffer *Buffer
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
@@ -1956,7 +1977,8 @@
// Write the source-location offsets table into the AST block. This
// table is used for lazily loading source-location information.
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size
@@ -1994,25 +2016,22 @@
Record.push_back(0);
// Emit the line entries
- for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
- L != LEnd; ++L) {
+ for (const auto &L : LineTable) {
// Only emit entries for local files.
- if (L->first.ID < 0)
+ if (L.first.ID < 0)
continue;
// Emit the file ID
- Record.push_back(L->first.ID);
+ Record.push_back(L.first.ID);
// Emit the line entries
- Record.push_back(L->second.size());
- for (std::vector<LineEntry>::iterator LE = L->second.begin(),
- LEEnd = L->second.end();
- LE != LEEnd; ++LE) {
- Record.push_back(LE->FileOffset);
- Record.push_back(LE->LineNo);
- Record.push_back(FilenameMap[LE->FilenameID]);
- Record.push_back((unsigned)LE->FileKind);
- Record.push_back(LE->IncludeOffset);
+ Record.push_back(L.second.size());
+ for (const auto &LE : L.second) {
+ Record.push_back(LE.FileOffset);
+ Record.push_back(LE.LineNo);
+ Record.push_back(FilenameMap[LE.FilenameID]);
+ Record.push_back((unsigned)LE.FileKind);
+ Record.push_back(LE.IncludeOffset);
}
}
@@ -2214,6 +2233,7 @@
// Write the offsets table for macro IDs.
using namespace llvm;
+
auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
@@ -2244,7 +2264,7 @@
// Set up the abbreviation for
unsigned InclusionAbbrev = 0;
{
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
@@ -2268,7 +2288,7 @@
PreprocessedEntityOffsets.push_back(
PPEntityOffset((*E)->getSourceRange(), Stream.GetCurrentBitNo()));
- if (MacroDefinitionRecord *MD = dyn_cast<MacroDefinitionRecord>(*E)) {
+ if (auto *MD = dyn_cast<MacroDefinitionRecord>(*E)) {
// Record this macro definition's ID.
MacroDefinitions[MD] = NextPreprocessorEntityID;
@@ -2277,7 +2297,7 @@
continue;
}
- if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
+ if (auto *ME = dyn_cast<MacroExpansion>(*E)) {
Record.push_back(ME->isBuiltinMacro());
if (ME->isBuiltinMacro())
AddIdentifierRef(ME->getName(), Record);
@@ -2287,7 +2307,7 @@
continue;
}
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+ if (auto *ID = dyn_cast<InclusionDirective>(*E)) {
Record.push_back(PPD_INCLUSION_DIRECTIVE);
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
@@ -2313,7 +2333,8 @@
// Write the offsets table for identifier IDs.
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -2355,8 +2376,7 @@
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
unsigned ChildModules = 0;
- for (Module::submodule_iterator Sub = Mod->submodule_begin(),
- SubEnd = Mod->submodule_end();
+ for (auto Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub)
ChildModules += getNumberOfModules(*Sub);
@@ -2369,7 +2389,8 @@
// Write the abbreviations needed for the submodules block.
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
@@ -2625,11 +2646,10 @@
if (DiagStateID == 0) {
DiagStateID = ++CurrID;
- for (DiagnosticsEngine::DiagState::const_iterator
- I = point.State->begin(), E = point.State->end(); I != E; ++I) {
- if (I->second.isPragma()) {
- Record.push_back(I->first);
- Record.push_back((unsigned)I->second.getSeverity());
+ for (const auto &I : *(point.State)) {
+ if (I.second.isPragma()) {
+ Record.push_back(I.first);
+ Record.push_back((unsigned)I.second.getSeverity());
}
}
Record.push_back(-1); // mark the end of the diag/map pairs for this
@@ -2648,7 +2668,7 @@
// Create a blob abbreviation for the C++ ctor initializer offsets.
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -2668,7 +2688,7 @@
// Create a blob abbreviation for the C++ base specifiers offsets.
using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -2764,7 +2784,7 @@
using namespace llvm;
// Write the type offsets array
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index
@@ -2807,7 +2827,7 @@
FileGroupedDeclIDs.push_back(LocDeclEntry.second);
}
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -2821,14 +2841,12 @@
Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3);
ArrayRef<RawComment *> RawComments = Context->Comments.getComments();
RecordData Record;
- for (ArrayRef<RawComment *>::iterator I = RawComments.begin(),
- E = RawComments.end();
- I != E; ++I) {
+ for (const auto *I : RawComments) {
Record.clear();
- AddSourceRange((*I)->getSourceRange(), Record);
- Record.push_back((*I)->getKind());
- Record.push_back((*I)->isTrailingComment());
- Record.push_back((*I)->isAlmostTrailingComment());
+ AddSourceRange(I->getSourceRange(), Record);
+ Record.push_back(I->getKind());
+ Record.push_back(I->isTrailingComment());
+ Record.push_back(I->isAlmostTrailingComment());
Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);
}
Stream.ExitBlock();
@@ -3015,7 +3033,7 @@
}
// Create a blob abbreviation
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
@@ -3273,10 +3291,8 @@
// where the user adds new macro definitions when building the AST
// file.
SmallVector<const IdentifierInfo *, 128> IIs;
- for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
- IDEnd = PP.getIdentifierTable().end();
- ID != IDEnd; ++ID)
- IIs.push_back(ID->second);
+ for (const auto &ID : PP.getIdentifierTable())
+ IIs.push_back(ID.second);
// Sort the identifiers lexicographically before getting them references so
// that their order is stable.
std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());
@@ -3288,7 +3304,7 @@
// for identifiers that appear here for the first time.
IdentifierOffsets.resize(NextIdentID - FirstIdentID);
for (auto IdentIDPair : IdentifierIDs) {
- IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first);
+ auto *II = const_cast<IdentifierInfo *>(IdentIDPair.first);
IdentID ID = IdentIDPair.second;
assert(II && "NULL identifier in identifier table");
if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
@@ -3307,7 +3323,7 @@
}
// Create a blob abbreviation
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -3319,7 +3335,7 @@
}
// Write the offsets table for identifier IDs.
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
@@ -3497,7 +3513,7 @@
"must call buildLookups first");
// FIXME: We need to build the lookups table, which is logically const.
- DeclContext *DC = const_cast<DeclContext*>(ConstDC);
+ auto *DC = const_cast<DeclContext*>(ConstDC);
assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
// Create the on-disk hash table representation.
@@ -3679,7 +3695,7 @@
if (isa<NamespaceDecl>(DC) && Chain &&
Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) {
// Only do this once, for the first local declaration of the namespace.
- for (NamespaceDecl *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev;
+ for (auto *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl())
if (!Prev->isFromASTFile())
return 0;
@@ -3835,7 +3851,8 @@
// Emit the categories map.
using namespace llvm;
- llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -3864,10 +3881,8 @@
AddDeclRef(LPT->D, Record);
Record.push_back(LPT->Toks.size());
- for (CachedTokens::iterator TokIt = LPT->Toks.begin(),
- TokEnd = LPT->Toks.end();
- TokIt != TokEnd; ++TokIt) {
- AddToken(*TokIt, Record);
+ for (const auto &Tok : LPT->Toks) {
+ AddToken(Tok, Record);
}
}
Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record);
@@ -3887,7 +3902,7 @@
Stream.EnterSubblock(EXTENSION_BLOCK_ID, 4);
// Emit the metadata record abbreviation.
- llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
+ auto *Abv = new llvm::BitCodeAbbrev();
Abv->Add(llvm::BitCodeAbbrevOp(EXTENSION_METADATA));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
@@ -3924,9 +3939,7 @@
void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs,
RecordDataImpl &Record) {
Record.push_back(Attrs.size());
- for (ArrayRef<const Attr *>::iterator i = Attrs.begin(),
- e = Attrs.end(); i != e; ++i){
- const Attr *A = *i;
+ for (const auto *A : Attrs) {
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
AddSourceRange(A->getRange(), Record);
@@ -4139,6 +4152,10 @@
RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID);
RegisterPredefDecl(Context.MakeIntegerSeqDecl,
PREDEF_DECL_MAKE_INTEGER_SEQ_ID);
+ RegisterPredefDecl(Context.CFConstantStringTypeDecl,
+ PREDEF_DECL_CF_CONSTANT_STRING_ID);
+ RegisterPredefDecl(Context.CFConstantStringTagDecl,
+ PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID);
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
@@ -4192,11 +4209,9 @@
// Build a record containing all of pending implicit instantiations.
RecordData PendingInstantiations;
- for (std::deque<Sema::PendingImplicitInstantiation>::iterator
- I = SemaRef.PendingInstantiations.begin(),
- N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
- AddDeclRef(I->first, PendingInstantiations);
- AddSourceLocation(I->second, PendingInstantiations);
+ for (const auto &I : SemaRef.PendingInstantiations) {
+ AddDeclRef(I.first, PendingInstantiations);
+ AddSourceLocation(I.second, PendingInstantiations);
}
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
"There are local ones at end of translation unit!");
@@ -4215,12 +4230,9 @@
// Build a record containing all of the known namespaces.
RecordData KnownNamespaces;
- for (llvm::MapVector<NamespaceDecl*, bool>::iterator
- I = SemaRef.KnownNamespaces.begin(),
- IEnd = SemaRef.KnownNamespaces.end();
- I != IEnd; ++I) {
- if (!I->second)
- AddDeclRef(I->first, KnownNamespaces);
+ for (const auto &I : SemaRef.KnownNamespaces) {
+ if (!I.second)
+ AddDeclRef(I.first, KnownNamespaces);
}
// Build a record of all used, undefined objects that require definitions.
@@ -4228,10 +4240,9 @@
SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
SemaRef.getUndefinedButUsed(Undefined);
- for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
- I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
- AddDeclRef(I->first, UndefinedButUsed);
- AddSourceLocation(I->second, UndefinedButUsed);
+ for (const auto &I : Undefined) {
+ AddDeclRef(I.first, UndefinedButUsed);
+ AddSourceLocation(I.second, UndefinedButUsed);
}
// Build a record containing all delete-expressions that we would like to
@@ -4272,7 +4283,7 @@
}
}
- llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
+ auto *Abv = new llvm::BitCodeAbbrev();
Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv);
@@ -4317,20 +4328,16 @@
// Make sure visible decls, added to DeclContexts previously loaded from
// an AST file, are registered for serialization.
- for (SmallVectorImpl<const Decl *>::iterator
- I = UpdatingVisibleDecls.begin(),
- E = UpdatingVisibleDecls.end(); I != E; ++I) {
- GetDeclRef(*I);
+ for (const auto *I : UpdatingVisibleDecls) {
+ GetDeclRef(I);
}
// Make sure all decls associated with an identifier are registered for
// serialization, if we're storing decls with identifiers.
if (!WritingModule || !getLangOpts().CPlusPlus) {
llvm::SmallVector<const IdentifierInfo*, 256> IIs;
- for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
- IDEnd = PP.getIdentifierTable().end();
- ID != IDEnd; ++ID) {
- const IdentifierInfo *II = ID->second;
+ for (const auto &ID : PP.getIdentifierTable()) {
+ const IdentifierInfo *II = ID.second;
if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
IIs.push_back(II);
}
@@ -4372,7 +4379,7 @@
// c++-base-specifiers-id:i32
// type-id:i32)
//
- llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -4617,6 +4624,11 @@
AddSourceLocation(Update.getLoc(), Record);
break;
+ case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
+ AddStmt(const_cast<Expr*>(
+ cast<ParmVarDecl>(Update.getDecl())->getDefaultArg()));
+ break;
+
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
auto *RD = cast<CXXRecordDecl>(D);
UpdatedDeclContexts.insert(RD->getPrimaryContext());
@@ -4702,7 +4714,7 @@
}
if (HasUpdatedBody) {
- const FunctionDecl *Def = cast<FunctionDecl>(D);
+ const auto *Def = cast<FunctionDecl>(D);
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
Record.push_back(Def->isInlined());
AddSourceLocation(Def->getInnerLocStart(), Record);
@@ -4723,11 +4735,10 @@
return;
RecordData Record;
- for (SmallVectorImpl<ReplacedDeclInfo>::iterator
- I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
- Record.push_back(I->ID);
- Record.push_back(I->Offset);
- Record.push_back(I->Loc);
+ for (const auto &I : ReplacedDecls) {
+ Record.push_back(I.ID);
+ Record.push_back(I.Offset);
+ Record.push_back(I.Loc);
}
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
}
@@ -5250,9 +5261,8 @@
case TemplateName::OverloadedTemplate: {
OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();
Record.push_back(OvT->size());
- for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end();
- I != E; ++I)
- AddDeclRef(*I, Record);
+ for (const auto &I : *OvT)
+ AddDeclRef(I, Record);
break;
}
@@ -5342,10 +5352,8 @@
AddSourceLocation(TemplateParams->getLAngleLoc(), Record);
AddSourceLocation(TemplateParams->getRAngleLoc(), Record);
Record.push_back(TemplateParams->size());
- for (TemplateParameterList::const_iterator
- P = TemplateParams->begin(), PEnd = TemplateParams->end();
- P != PEnd; ++P)
- AddDeclRef(*P, Record);
+ for (const auto &P : *TemplateParams)
+ AddDeclRef(P, Record);
}
/// \brief Emit a template argument list.
@@ -5660,7 +5668,7 @@
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
assert(D->isCompleteDefinition());
assert(!WritingAST && "Already writing the AST!");
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
// We are interested when a PCH decl is modified.
if (RD->isFromASTFile()) {
// A forward reference was mutated into a definition. Rewrite it.
@@ -5789,6 +5797,15 @@
D->getMemberSpecializationInfo()->getPointOfInstantiation()));
}
+void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, D));
+}
+
void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {
assert(!WritingAST && "Already writing the AST!");
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index cc67b17..54bba28 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -276,7 +276,10 @@
void ASTDeclWriter::VisitDecl(Decl *D) {
Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
- Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+ if (D->getDeclContext() != D->getLexicalDeclContext())
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+ else
+ Record.push_back(0);
Record.push_back(D->isInvalidDecl());
Record.push_back(D->hasAttrs());
if (D->hasAttrs())
@@ -340,7 +343,8 @@
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
VisitTypedefNameDecl(D);
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
@@ -402,7 +406,8 @@
Writer.AddDeclRef(nullptr, Record);
}
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
@@ -430,7 +435,8 @@
Record.push_back(D->hasObjectMember());
Record.push_back(D->hasVolatileMember());
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
@@ -688,7 +694,8 @@
Record.push_back(D->getAccessControl());
Record.push_back(D->getSynthesize());
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->isInvalidDecl() &&
@@ -820,7 +827,8 @@
if (!D->getDeclName())
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->isInvalidDecl() &&
@@ -894,7 +902,8 @@
Record.push_back(VarNotTemplate);
}
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->isInvalidDecl() &&
@@ -942,7 +951,8 @@
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
- if (!D->hasAttrs() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ !D->hasAttrs() &&
!D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
@@ -1162,7 +1172,8 @@
Record.push_back(0);
}
- if (D->getFirstDecl() == D->getMostRecentDecl() &&
+ if (D->getDeclContext() == D->getLexicalDeclContext() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->hasAttrs() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -1631,7 +1642,7 @@
Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1664,7 +1675,7 @@
Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1702,7 +1713,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1750,7 +1761,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1793,7 +1804,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1840,7 +1851,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1869,7 +1880,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
@@ -1915,7 +1926,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
Abv->Add(BitCodeAbbrevOp(0)); // Invalid
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Implicit
@@ -2022,7 +2033,7 @@
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // getKind
CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
// Abbreviation for EXPR_IMPLICIT_CAST
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 74dc56e..7b5440b 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -40,7 +40,8 @@
ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
- void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args);
+ void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &ArgInfo,
+ const TemplateArgumentLoc *Args);
void VisitStmt(Stmt *S);
#define STMT(Type, Base) \
@@ -49,13 +50,13 @@
};
}
-void ASTStmtWriter::
-AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args) {
- Writer.AddSourceLocation(Args.getTemplateKeywordLoc(), Record);
- Writer.AddSourceLocation(Args.LAngleLoc, Record);
- Writer.AddSourceLocation(Args.RAngleLoc, Record);
- for (unsigned i=0; i != Args.NumTemplateArgs; ++i)
- Writer.AddTemplateArgumentLoc(Args.getTemplateArgs()[i], Record);
+void ASTStmtWriter::AddTemplateKWAndArgsInfo(
+ const ASTTemplateKWAndArgsInfo &ArgInfo, const TemplateArgumentLoc *Args) {
+ Writer.AddSourceLocation(ArgInfo.TemplateKWLoc, Record);
+ Writer.AddSourceLocation(ArgInfo.LAngleLoc, Record);
+ Writer.AddSourceLocation(ArgInfo.RAngleLoc, Record);
+ for (unsigned i = 0; i != ArgInfo.NumTemplateArgs; ++i)
+ Writer.AddTemplateArgumentLoc(Args[i], Record);
}
void ASTStmtWriter::VisitStmt(Stmt *S) {
@@ -386,7 +387,8 @@
Writer.AddDeclRef(E->getFoundDecl(), Record);
if (E->hasTemplateKWAndArgsInfo())
- AddTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo());
+ AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+ E->getTrailingObjects<TemplateArgumentLoc>());
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
@@ -482,24 +484,24 @@
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
- const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+ const OffsetOfNode &ON = E->getComponent(I);
Record.push_back(ON.getKind()); // FIXME: Stable encoding
Writer.AddSourceLocation(ON.getSourceRange().getBegin(), Record);
Writer.AddSourceLocation(ON.getSourceRange().getEnd(), Record);
switch (ON.getKind()) {
- case OffsetOfExpr::OffsetOfNode::Array:
+ case OffsetOfNode::Array:
Record.push_back(ON.getArrayExprIndex());
break;
-
- case OffsetOfExpr::OffsetOfNode::Field:
+
+ case OffsetOfNode::Field:
Writer.AddDeclRef(ON.getField(), Record);
break;
-
- case OffsetOfExpr::OffsetOfNode::Identifier:
+
+ case OffsetOfNode::Identifier:
Writer.AddIdentifierRef(ON.getFieldName(), Record);
break;
-
- case OffsetOfExpr::OffsetOfNode::Base:
+
+ case OffsetOfNode::Base:
Writer.AddCXXBaseSpecifier(*ON.getBase(), Record);
break;
}
@@ -1334,15 +1336,8 @@
void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
-
- bool HasOtherExprStored = E->Param.getInt();
- // Store these first, the reader reads them before creation.
- Record.push_back(HasOtherExprStored);
- if (HasOtherExprStored)
- Writer.AddStmt(E->getExpr());
Writer.AddDeclRef(E->getParam(), Record);
Writer.AddSourceLocation(E->getUsedLocation(), Record);
-
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
@@ -1440,9 +1435,11 @@
Record.push_back(E->HasTemplateKWAndArgsInfo);
if (E->HasTemplateKWAndArgsInfo) {
- const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
- Record.push_back(Args.NumTemplateArgs);
- AddTemplateKWAndArgsInfo(Args);
+ const ASTTemplateKWAndArgsInfo &ArgInfo =
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
+ Record.push_back(ArgInfo.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(ArgInfo,
+ E->getTrailingObjects<TemplateArgumentLoc>());
}
if (!E->isImplicitAccess())
@@ -1467,9 +1464,11 @@
Record.push_back(E->HasTemplateKWAndArgsInfo);
if (E->HasTemplateKWAndArgsInfo) {
- const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
- Record.push_back(Args.NumTemplateArgs);
- AddTemplateKWAndArgsInfo(Args);
+ const ASTTemplateKWAndArgsInfo &ArgInfo =
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
+ Record.push_back(ArgInfo.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(ArgInfo,
+ E->getTrailingObjects<TemplateArgumentLoc>());
}
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
@@ -1498,9 +1497,10 @@
Record.push_back(E->HasTemplateKWAndArgsInfo);
if (E->HasTemplateKWAndArgsInfo) {
- const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
- Record.push_back(Args.NumTemplateArgs);
- AddTemplateKWAndArgsInfo(Args);
+ const ASTTemplateKWAndArgsInfo &ArgInfo =
+ *E->getTrailingASTTemplateKWAndArgsInfo();
+ Record.push_back(ArgInfo.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingTemplateArgumentLoc());
}
Record.push_back(E->getNumDecls());
@@ -1689,6 +1689,14 @@
Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR;
}
+void ASTStmtWriter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getBase());
+ Writer.AddStmt(E->getIdx());
+ Writer.AddSourceLocation(E->getRBracketLoc(), Record);
+ Code = serialization::EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR;
+}
+
void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
VisitExpr(E);
Writer.AddSourceRange(E->getSourceRange(), Record);
@@ -1803,9 +1811,13 @@
void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
Record.push_back(C->getScheduleKind());
+ Record.push_back(C->getFirstScheduleModifier());
+ Record.push_back(C->getSecondScheduleModifier());
Writer->Writer.AddStmt(C->getChunkSize());
Writer->Writer.AddStmt(C->getHelperChunkSize());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getFirstScheduleModifierLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getSecondScheduleModifierLoc(), Record);
Writer->Writer.AddSourceLocation(C->getScheduleKindLoc(), Record);
Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
}
@@ -1835,6 +1847,8 @@
void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {}
+void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {}
+
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
@@ -1982,6 +1996,56 @@
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
}
+void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Record.push_back(C->getMapTypeModifier());
+ Record.push_back(C->getMapType());
+ Writer->Writer.AddSourceLocation(C->getMapLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
+ Writer->Writer.AddStmt(C->getNumTeams());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
+ Writer->Writer.AddStmt(C->getThreadLimit());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) {
+ Writer->Writer.AddStmt(C->getPriority());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
+ Writer->Writer.AddStmt(C->getGrainsize());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
+ Writer->Writer.AddStmt(C->getNumTasks());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPHintClause(OMPHintClause *C) {
+ Writer->Writer.AddStmt(C->getHint());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) {
+ Record.push_back(C->getDistScheduleKind());
+ Writer->Writer.AddStmt(C->getChunkSize());
+ Writer->Writer.AddStmt(C->getHelperChunkSize());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getDistScheduleKindLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//
@@ -2088,6 +2152,7 @@
void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
VisitStmt(D);
+ Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
Writer.AddDeclarationNameInfo(D->getDirectiveName(), Record);
Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE;
@@ -2210,6 +2275,21 @@
Code = serialization::STMT_OMP_CANCEL_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_TASKLOOP_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_TASKLOOP_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index e157478..26d42ba 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -307,8 +307,7 @@
warnIfNilArg(C, msg, /* Arg */1, Class);
} else if (S == SetObjectForKeyedSubscriptSel) {
CanBeSubscript = true;
- Arg = 0;
- warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
+ Arg = 1;
} else if (S == RemoveObjectForKeySel) {
Arg = 0;
}
@@ -993,9 +992,7 @@
ProgramPoint P = N->getLocation();
if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
- if (BE->getSrc()->getLoopTarget() == FCS)
- return true;
- return false;
+ return BE->getSrc()->getLoopTarget() == FCS;
}
// Keep looking for a block edge.
@@ -1039,11 +1036,8 @@
CountSelectorII = &C.getASTContext().Idents.get("count");
// If the method returns collection count, record the value.
- if (S.isUnarySelector() &&
- (S.getIdentifierInfoForSlot(0) == CountSelectorII))
- return true;
-
- return false;
+ return S.isUnarySelector() &&
+ (S.getIdentifierInfoForSlot(0) == CountSelectorII);
}
void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 657d538..58ff48d 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -57,6 +57,7 @@
ObjCMissingSuperCallChecker.cpp
ObjCSelfInitChecker.cpp
ObjCUnusedIVarsChecker.cpp
+ PaddingChecker.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
PthreadLockChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index d32b282..1753744 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -948,15 +948,15 @@
const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
switch (MR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ case MemRegion::FunctionCodeRegionKind: {
+ const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
}
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockCodeRegionKind:
os << "block text";
return true;
case MemRegion::BlockDataRegionKind:
@@ -2013,10 +2013,7 @@
// properties are held. However, if the user chooses to turn off some of these
// checks, we ignore the issues and leave the call evaluation to a generic
// handler.
- if (!C.isDifferent())
- return false;
-
- return true;
+ return C.isDifferent();
}
void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index a5ed64d..2337400 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -82,10 +82,7 @@
if (Left.isNegative())
return false;
- if (Left % FlexSize == 0)
- return true;
-
- return false;
+ return Left % FlexSize == 0;
}
void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 25caa00..d17a8b5 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -28,7 +28,7 @@
using namespace clang;
using namespace ento;
-static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
+static bool scan_ivar_release(Stmt *S, const ObjCIvarDecl *ID,
const ObjCPropertyDecl *PD,
Selector Release,
IdentifierInfo* SelfII,
@@ -76,42 +76,67 @@
return false;
}
+static bool isSynthesizedRetainableProperty(const ObjCPropertyImplDecl *I,
+ const ObjCIvarDecl **ID,
+ const ObjCPropertyDecl **PD) {
+
+ if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ return false;
+
+ (*ID) = I->getPropertyIvarDecl();
+ if (!(*ID))
+ return false;
+
+ QualType T = (*ID)->getType();
+ if (!T->isObjCRetainableType())
+ return false;
+
+ (*PD) = I->getPropertyDecl();
+ // Shouldn't be able to synthesize a property that doesn't exist.
+ assert(*PD);
+
+ return true;
+}
+
+static bool synthesizedPropertyRequiresRelease(const ObjCPropertyDecl *PD) {
+ // A synthesized property must be released if and only if the kind of setter
+ // was neither 'assign' or 'weak'.
+ ObjCPropertyDecl::SetterKind SK = PD->getSetterKind();
+ return (SK != ObjCPropertyDecl::Assign && SK != ObjCPropertyDecl::Weak);
+}
+
static void checkObjCDealloc(const CheckerBase *Checker,
const ObjCImplementationDecl *D,
const LangOptions &LOpts, BugReporter &BR) {
- assert (LOpts.getGC() != LangOptions::GCOnly);
+ assert(LOpts.getGC() != LangOptions::GCOnly);
+ assert(!LOpts.ObjCAutoRefCount);
ASTContext &Ctx = BR.getContext();
const ObjCInterfaceDecl *ID = D->getClassInterface();
- // Does the class contain any ivars that are pointers (or id<...>)?
+ // Does the class contain any synthesized properties that are retainable?
// If not, skip the check entirely.
- // NOTE: This is motivated by PR 2517:
- // http://llvm.org/bugs/show_bug.cgi?id=2517
-
- bool containsPointerIvar = false;
-
- for (const auto *Ivar : ID->ivars()) {
- QualType T = Ivar->getType();
-
- if (!T->isObjCObjectPointerType() ||
- Ivar->hasAttr<IBOutletAttr>() || // Skip IBOutlets.
- Ivar->hasAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
+ bool containsRetainedSynthesizedProperty = false;
+ for (const auto *I : D->property_impls()) {
+ const ObjCIvarDecl *ID = nullptr;
+ const ObjCPropertyDecl *PD = nullptr;
+ if (!isSynthesizedRetainableProperty(I, &ID, &PD))
continue;
- containsPointerIvar = true;
- break;
+ if (synthesizedPropertyRequiresRelease(PD)) {
+ containsRetainedSynthesizedProperty = true;
+ break;
+ }
}
- if (!containsPointerIvar)
+ if (!containsRetainedSynthesizedProperty)
return;
// Determine if the class subclasses NSObject.
IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");
-
for ( ; ID ; ID = ID->getSuperClass()) {
IdentifierInfo *II = ID->getIdentifier();
@@ -142,9 +167,6 @@
}
}
- PathDiagnosticLocation DLoc =
- PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
-
if (!MD) { // No dealloc found.
const char* name = LOpts.getGC() == LangOptions::NonGC
@@ -155,6 +177,9 @@
llvm::raw_string_ostream os(buf);
os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";
+ PathDiagnosticLocation DLoc =
+ PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
+
BR.EmitBasicReport(D, Checker, name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
return;
@@ -170,28 +195,12 @@
// Scan for missing and extra releases of ivars used by implementations
// of synthesized properties
for (const auto *I : D->property_impls()) {
- // We can only check the synthesized properties
- if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ const ObjCIvarDecl *ID = nullptr;
+ const ObjCPropertyDecl *PD = nullptr;
+ if (!isSynthesizedRetainableProperty(I, &ID, &PD))
continue;
- ObjCIvarDecl *ID = I->getPropertyIvarDecl();
- if (!ID)
- continue;
-
- QualType T = ID->getType();
- if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
- continue;
-
- const ObjCPropertyDecl *PD = I->getPropertyDecl();
- if (!PD)
- continue;
-
- // ivars cannot be set via read-only properties, so we'll skip them
- if (PD->isReadOnly())
- continue;
-
- // ivar must be released if and only if the kind of setter was not 'assign'
- bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
+ bool requiresRelease = synthesizedPropertyRequiresRelease(PD);
if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
!= requiresRelease) {
const char *name = nullptr;
@@ -203,24 +212,28 @@
? "missing ivar release (leak)"
: "missing ivar release (Hybrid MM, non-GC)";
- os << "The '" << *ID
- << "' instance variable was retained by a synthesized property but "
- "wasn't released in 'dealloc'";
+ os << "The '" << *ID << "' instance variable in '" << *D
+ << "' was retained by a synthesized property "
+ "but was not released in 'dealloc'";
} else {
name = LOpts.getGC() == LangOptions::NonGC
? "extra ivar release (use-after-release)"
: "extra ivar release (Hybrid MM, non-GC)";
- os << "The '" << *ID
- << "' instance variable was not retained by a synthesized property "
+ os << "The '" << *ID << "' instance variable in '" << *D
+ << "' was not retained by a synthesized property "
"but was released in 'dealloc'";
}
- PathDiagnosticLocation SDLoc =
- PathDiagnosticLocation::createBegin(I, BR.getSourceManager());
+ // If @synthesize statement is missing, fall back to @property statement.
+ const Decl *SPDecl = I->getLocation().isValid()
+ ? static_cast<const Decl *>(I)
+ : static_cast<const Decl *>(PD);
+ PathDiagnosticLocation SPLoc =
+ PathDiagnosticLocation::createBegin(SPDecl, BR.getSourceManager());
BR.EmitBasicReport(MD, Checker, name,
- categories::CoreFoundationObjectiveC, os.str(), SDLoc);
+ categories::CoreFoundationObjectiveC, os.str(), SPLoc);
}
}
}
@@ -235,7 +248,8 @@
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- if (mgr.getLangOpts().getGC() == LangOptions::GCOnly)
+ if (mgr.getLangOpts().getGC() == LangOptions::GCOnly ||
+ mgr.getLangOpts().ObjCAutoRefCount)
return;
checkObjCDealloc(this, cast<ObjCImplementationDecl>(D), mgr.getLangOpts(),
BR);
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index eab9756..60f1618 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -86,8 +86,7 @@
// Helpers.
bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
- typedef void (WalkAST::*FnCheck)(const CallExpr *,
- const FunctionDecl *);
+ typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
// Checker-specific methods.
void checkLoopConditionForFloat(const ForStmt *FS);
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index c419225..8133d29 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -46,6 +46,8 @@
def DeadCode : Package<"deadcode">;
def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
+def Performance : Package<"performance">, InPackage<OptIn>;
+
def Security : Package <"security">;
def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
@@ -273,6 +275,18 @@
} // end "alpha.deadcode"
//===----------------------------------------------------------------------===//
+// Performance checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Performance in {
+
+def PaddingChecker : Checker<"Padding">,
+ HelpText<"Check for excessively padded structs.">,
+ DescFile<"PaddingChecker.cpp">;
+
+} // end: "padding"
+
+//===----------------------------------------------------------------------===//
// Security checkers.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 5d8baf6..f2a269a 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -401,6 +401,11 @@
// Check for '&'. Any VarDecl whose address has been taken we treat as
// escaped.
// FIXME: What about references?
+ if (auto *LE = dyn_cast<LambdaExpr>(S)) {
+ findLambdaReferenceCaptures(LE);
+ return;
+ }
+
const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
if (!U)
return;
@@ -412,6 +417,28 @@
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
Escaped.insert(VD);
}
+
+ // Treat local variables captured by reference in C++ lambdas as escaped.
+ void findLambdaReferenceCaptures(const LambdaExpr *LE) {
+ const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
+ llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+ FieldDecl *ThisCaptureField;
+ LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
+
+ for (const LambdaCapture &C : LE->captures()) {
+ if (!C.capturesVariable())
+ continue;
+
+ VarDecl *VD = C.getCapturedVar();
+ const FieldDecl *FD = CaptureFields[VD];
+ if (!FD)
+ continue;
+
+ // If the capture field is a reference type, it is capture-by-reference.
+ if (FD->getType()->isReferenceType())
+ Escaped.insert(VD);
+ }
+ }
};
} // end anonymous namespace
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index acf0004..2eef168 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -230,11 +230,12 @@
if (!N)
return;
+ const LangOptions &Opts = C.getLangOpts();
const SourceManager &SM = C.getSourceManager();
FullSourceLoc FL(S->getLocStart(), SM);
std::string HashContent =
GetIssueString(SM, FL, getCheckName().getName(), BT->getCategory(),
- C.getLocationContext()->getDecl());
+ C.getLocationContext()->getDecl(), Opts);
C.emitReport(llvm::make_unique<BugReport>(*BT, HashContent, N));
}
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 5dd2832..152b937 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -34,8 +34,7 @@
mutable std::unique_ptr<BuiltinBug> BT_null;
mutable std::unique_ptr<BuiltinBug> BT_undef;
- void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C,
- bool IsBind = false) const;
+ void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const;
public:
void checkLocation(SVal location, bool isLoad, const Stmt* S,
@@ -89,8 +88,31 @@
}
}
+static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
+ const Expr *E = nullptr;
+
+ // Walk through lvalue casts to get the original expression
+ // that syntactically caused the load.
+ if (const Expr *expr = dyn_cast<Expr>(S))
+ E = expr->IgnoreParenLValueCasts();
+
+ if (IsBind) {
+ const VarDecl *VD;
+ const Expr *Init;
+ std::tie(VD, Init) = parseAssignment(S);
+ if (VD && Init)
+ E = Init;
+ }
+ return E;
+}
+
+static bool suppressReport(const Expr *E) {
+ // Do not report dereferences on memory in non-default address spaces.
+ return E->getType().getQualifiers().hasAddressSpace();
+}
+
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
- CheckerContext &C, bool IsBind) const {
+ CheckerContext &C) const {
// Generate an error node.
ExplodedNode *N = C.generateErrorNode(State);
if (!N)
@@ -106,19 +128,6 @@
SmallVector<SourceRange, 2> Ranges;
- // Walk through lvalue casts to get the original expression
- // that syntactically caused the load.
- if (const Expr *expr = dyn_cast<Expr>(S))
- S = expr->IgnoreParenLValueCasts();
-
- if (IsBind) {
- const VarDecl *VD;
- const Expr *Init;
- std::tie(VD, Init) = parseAssignment(S);
- if (VD && Init)
- S = Init;
- }
-
switch (S->getStmtClass()) {
case Stmt::ArraySubscriptExprClass: {
os << "Array access";
@@ -209,8 +218,11 @@
// The explicit NULL case.
if (nullState) {
if (!notNullState) {
- reportBug(nullState, S, C);
- return;
+ const Expr *expr = getDereferenceExpr(S);
+ if (!suppressReport(expr)) {
+ reportBug(nullState, expr, C);
+ return;
+ }
}
// Otherwise, we have the case where the location could either be
@@ -218,7 +230,7 @@
// dereference.
if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
- /*IsDirectDereference=*/false};
+ /*IsDirectDereference=*/true};
dispatchEvent(event);
}
}
@@ -248,8 +260,11 @@
if (StNull) {
if (!StNonNull) {
- reportBug(StNull, S, C, /*isBind=*/true);
- return;
+ const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
+ if (!suppressReport(expr)) {
+ reportBug(StNull, expr, C);
+ return;
+ }
}
// At this point the value could be either null or non-null.
@@ -257,7 +272,7 @@
if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
&C.getBugReporter(),
- /*IsDirectDereference=*/false};
+ /*IsDirectDereference=*/true};
dispatchEvent(event);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index a71def2..5efb909 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -41,13 +41,12 @@
/// Checks for the init, dealloc, and any other functions that might be allowed
/// to perform direct instance variable assignment based on their name.
static bool DefaultMethodFilter(const ObjCMethodDecl *M) {
- if (M->getMethodFamily() == OMF_init || M->getMethodFamily() == OMF_dealloc ||
- M->getMethodFamily() == OMF_copy ||
- M->getMethodFamily() == OMF_mutableCopy ||
- M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
- M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
- return true;
- return false;
+ return M->getMethodFamily() == OMF_init ||
+ M->getMethodFamily() == OMF_dealloc ||
+ M->getMethodFamily() == OMF_copy ||
+ M->getMethodFamily() == OMF_mutableCopy ||
+ M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
+ M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos;
}
class DirectIvarAssignment :
@@ -124,7 +123,7 @@
IvarToPropertyMapTy IvarToPropMap;
// Find all properties for this class.
- for (const auto *PD : InterD->properties()) {
+ for (const auto *PD : InterD->instance_properties()) {
// Find the corresponding IVar.
const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
Mgr.getASTContext());
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 60c6aa5..31e9150 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -11,28 +11,37 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace ento;
namespace {
-class ExprInspectionChecker : public Checker< eval::Call > {
+class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols> {
mutable std::unique_ptr<BugType> BT;
void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
CheckerContext &C) const;
+ void reportBug(llvm::StringRef Msg, CheckerContext &C) const;
+
public:
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
};
}
+REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
+
bool ExprInspectionChecker::evalCall(const CallExpr *CE,
CheckerContext &C) const {
// These checks should have no effect on the surrounding environment
@@ -42,7 +51,12 @@
.Case("clang_analyzer_checkInlined",
&ExprInspectionChecker::analyzerCheckInlined)
.Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
- .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
+ .Case("clang_analyzer_warnIfReached",
+ &ExprInspectionChecker::analyzerWarnIfReached)
+ .Case("clang_analyzer_warnOnDeadSymbol",
+ &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
+ .Case("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
+ .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
.Default(nullptr);
if (!Handler)
@@ -84,6 +98,18 @@
}
}
+void ExprInspectionChecker::reportBug(llvm::StringRef Msg,
+ CheckerContext &C) const {
+ if (!BT)
+ BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
+
+ C.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
+}
+
void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
CheckerContext &C) const {
const LocationContext *LC = C.getPredecessor()->getLocationContext();
@@ -93,26 +119,12 @@
if (LC->getCurrentStackFrame()->getParent() != nullptr)
return;
- if (!BT)
- BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
-
- ExplodedNode *N = C.generateNonFatalErrorNode();
- if (!N)
- return;
- C.emitReport(
- llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
+ reportBug(getArgumentValueString(CE, C), C);
}
void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
CheckerContext &C) const {
-
- if (!BT)
- BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
-
- ExplodedNode *N = C.generateNonFatalErrorNode();
- if (!N)
- return;
- C.emitReport(llvm::make_unique<BugReport>(*BT, "REACHABLE", N));
+ reportBug("REACHABLE", C);
}
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
@@ -127,14 +139,61 @@
if (LC->getCurrentStackFrame()->getParent() == nullptr)
return;
- if (!BT)
- BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+ reportBug(getArgumentValueString(CE, C), C);
+}
- ExplodedNode *N = C.generateNonFatalErrorNode();
- if (!N)
+void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (CE->getNumArgs() == 0)
+ reportBug("Missing argument for explaining", C);
+
+ SVal V = C.getSVal(CE->getArg(0));
+ SValExplainer Ex(C.getASTContext());
+ reportBug(Ex.Visit(V), C);
+}
+
+void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (CE->getNumArgs() == 0)
+ reportBug("Missing region for obtaining extent", C);
+
+ auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->getArg(0)).getAsRegion());
+ if (!MR)
+ reportBug("Obtaining extent of a non-region", C);
+
+ ProgramStateRef State = C.getState();
+ State = State->BindExpr(CE, C.getLocationContext(),
+ MR->getExtent(C.getSValBuilder()));
+ C.addTransition(State);
+}
+
+void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (CE->getNumArgs() == 0)
return;
- C.emitReport(
- llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
+ SVal Val = C.getSVal(CE->getArg(0));
+ SymbolRef Sym = Val.getAsSymbol();
+ if (!Sym)
+ return;
+
+ ProgramStateRef State = C.getState();
+ State = State->add<MarkedSymbols>(Sym);
+ C.addTransition(State);
+}
+
+void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
+ for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
+ SymbolRef Sym = *I;
+ if (!SymReaper.isDead(Sym))
+ continue;
+
+ reportBug("SYMBOL DEAD", C);
+ State = State->remove<MarkedSymbols>(Sym);
+ }
+ C.addTransition(State);
}
void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 1d80851..8c8acc6 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -658,10 +658,8 @@
return false;
// If either the format string content or the pointer itself are tainted, warn.
- if (generateReportIfTainted(CE->getArg(ArgNum),
- MsgUncontrolledFormatString, C))
- return true;
- return false;
+ return generateReportIfTainted(CE->getArg(ArgNum),
+ MsgUncontrolledFormatString, C);
}
bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
@@ -686,11 +684,7 @@
if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
return false;
- if (generateReportIfTainted(CE->getArg(ArgNum),
- MsgSanitizeSystemArgs, C))
- return true;
-
- return false;
+ return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
}
// TODO: Should this check be a part of the CString checker?
@@ -728,11 +722,8 @@
ArgNum = 2;
}
- if (ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
- generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C))
- return true;
-
- return false;
+ return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
+ generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
}
void ento::registerGenericTaintChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
index 6cfd07a..0c3bff5 100644
--- a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -305,9 +305,7 @@
const Stmt *Stmt2, bool IgnoreSideEffects) {
if (!Stmt1 || !Stmt2) {
- if (!Stmt1 && !Stmt2)
- return true;
- return false;
+ return !Stmt1 && !Stmt2;
}
// If Stmt1 & Stmt2 are of different class then they are not
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index dffff38..153c05b 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -390,6 +390,8 @@
for (ObjCInterfaceDecl::PropertyMap::iterator
I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
const ObjCPropertyDecl *PD = I->second;
+ if (PD->isClassProperty())
+ continue;
const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
&FirstIvarDecl);
diff --git a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index 56346cd..504b8b3 100644
--- a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -619,11 +619,46 @@
}
}
+
+static bool isDebuggingName(std::string name) {
+ return StringRef(name).lower().find("debug") != StringRef::npos;
+}
+
+/// Returns true when, heuristically, the analyzer may be analyzing debugging
+/// code. We use this to suppress localization diagnostics in un-localized user
+/// interfaces that are only used for debugging and are therefore not user
+/// facing.
+static bool isDebuggingContext(CheckerContext &C) {
+ const Decl *D = C.getCurrentAnalysisDeclContext()->getDecl();
+ if (!D)
+ return false;
+
+ if (auto *ND = dyn_cast<NamedDecl>(D)) {
+ if (isDebuggingName(ND->getNameAsString()))
+ return true;
+ }
+
+ const DeclContext *DC = D->getDeclContext();
+
+ if (auto *CD = dyn_cast<ObjCContainerDecl>(DC)) {
+ if (isDebuggingName(CD->getNameAsString()))
+ return true;
+ }
+
+ return false;
+}
+
+
/// Reports a localization error for the passed in method call and SVal
void NonLocalizedStringChecker::reportLocalizationError(
SVal S, const ObjCMethodCall &M, CheckerContext &C,
int argumentNumber) const {
+ // Don't warn about localization errors in classes and methods that
+ // may be debug code.
+ if (isDebuggingContext(C))
+ return;
+
ExplodedNode *ErrNode = C.getPredecessor();
static CheckerProgramPointTag Tag("NonLocalizedStringChecker",
"UnlocalizedString");
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 294f361..1e56d70 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -201,12 +201,8 @@
static bool isBadDeallocationArgument(const MemRegion *Arg) {
if (!Arg)
return false;
- if (isa<AllocaRegion>(Arg) ||
- isa<BlockDataRegion>(Arg) ||
- isa<TypedRegion>(Arg)) {
- return true;
- }
- return false;
+ return isa<AllocaRegion>(Arg) || isa<BlockDataRegion>(Arg) ||
+ isa<TypedRegion>(Arg);
}
/// Given the address expression, retrieve the value it's pointing to. Assume
@@ -240,11 +236,7 @@
DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal,
nonloc::SymbolVal(RetSym));
ProgramStateRef ErrState = State->assume(NoErr, noError);
- if (ErrState == State) {
- return true;
- }
-
- return false;
+ return ErrState == State;
}
// Report deallocator mismatch. Remove the region from tracking - reporting a
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 54b1a6e..fee030f 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1000,12 +1000,9 @@
// Ex: [NSData dataWithBytesNoCopy:bytes length:10];
// (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
- if (FirstSlot == "dataWithBytesNoCopy" ||
- FirstSlot == "initWithBytesNoCopy" ||
- FirstSlot == "initWithCharactersNoCopy")
- return true;
-
- return false;
+ return FirstSlot == "dataWithBytesNoCopy" ||
+ FirstSlot == "initWithBytesNoCopy" ||
+ FirstSlot == "initWithCharactersNoCopy";
}
static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
@@ -1516,15 +1513,15 @@
bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ case MemRegion::FunctionCodeRegionKind: {
+ const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
}
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockCodeRegionKind:
os << "block text";
return true;
case MemRegion::BlockDataRegionKind:
@@ -2511,6 +2508,16 @@
return true;
}
+ if (FName == "postEvent" &&
+ FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
+ return true;
+ }
+
+ if (FName == "postEvent" &&
+ FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
+ return true;
+ }
+
// Handle cases where we know a buffer's /address/ can escape.
// Note that the above checks handle some special cases where we know that
// even though the address escapes, it's still our responsibility to free the
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 8d0a060..c1deade 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -66,6 +66,7 @@
.Case("assfail", true)
.Case("db_error", true)
.Case("__assert", true)
+ .Case("__assert2", true)
// For the purpose of static analysis, we do not care that
// this MSVC function will return if the user decides to continue.
.Case("_wassert", true)
diff --git a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 137dedb..e096e20 100644
--- a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -26,13 +26,16 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "llvm/Support/Path.h"
+
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Path.h"
+
using namespace clang;
using namespace ento;
@@ -89,18 +92,6 @@
NullablePassedToNonnull
};
-const char *const ErrorMessages[] = {
- "Null is assigned to a pointer which is expected to have non-null value",
- "Null passed to a callee that requires a non-null argument",
- "Null is returned from a function that is expected to return a non-null "
- "value",
- "Nullable pointer is assigned to a pointer which is expected to have "
- "non-null value",
- "Nullable pointer is returned from a function that is expected to return a "
- "non-null value",
- "Nullable pointer is dereferenced",
- "Nullable pointer is passed to a callee that requires a non-null argument"};
-
class NullabilityChecker
: public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
check::PostCall, check::PostStmt<ExplicitCastExpr>,
@@ -169,17 +160,19 @@
///
/// When \p SuppressPath is set to true, no more bugs will be reported on this
/// path by this checker.
- void reportBugIfPreconditionHolds(ErrorKind Error, ExplodedNode *N,
- const MemRegion *Region, CheckerContext &C,
+ void reportBugIfPreconditionHolds(StringRef Msg, ErrorKind Error,
+ ExplodedNode *N, const MemRegion *Region,
+ CheckerContext &C,
const Stmt *ValueExpr = nullptr,
bool SuppressPath = false) const;
- void reportBug(ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
- BugReporter &BR, const Stmt *ValueExpr = nullptr) const {
+ void reportBug(StringRef Msg, ErrorKind Error, ExplodedNode *N,
+ const MemRegion *Region, BugReporter &BR,
+ const Stmt *ValueExpr = nullptr) const {
if (!BT)
BT.reset(new BugType(this, "Nullability", "Memory error"));
- const char *Msg = ErrorMessages[static_cast<int>(Error)];
- std::unique_ptr<BugReport> R(new BugReport(*BT, Msg, N));
+
+ auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
if (Region) {
R->markInteresting(Region);
R->addVisitor(llvm::make_unique<NullabilityBugVisitor>(Region));
@@ -366,29 +359,25 @@
if (!D)
return false;
- if (const auto *BlockD = dyn_cast<BlockDecl>(D)) {
- if (checkParamsForPreconditionViolation(BlockD->parameters(), State,
- LocCtxt)) {
- if (!N->isSink())
- C.addTransition(State->set<PreconditionViolated>(true), N);
- return true;
- }
+ ArrayRef<ParmVarDecl*> Params;
+ if (const auto *BD = dyn_cast<BlockDecl>(D))
+ Params = BD->parameters();
+ else if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ Params = FD->parameters();
+ else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ Params = MD->parameters();
+ else
return false;
- }
- if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) {
- if (checkParamsForPreconditionViolation(FuncDecl->parameters(), State,
- LocCtxt)) {
- if (!N->isSink())
- C.addTransition(State->set<PreconditionViolated>(true), N);
- return true;
- }
- return false;
+ if (checkParamsForPreconditionViolation(Params, State, LocCtxt)) {
+ if (!N->isSink())
+ C.addTransition(State->set<PreconditionViolated>(true), N);
+ return true;
}
return false;
}
-void NullabilityChecker::reportBugIfPreconditionHolds(
+void NullabilityChecker::reportBugIfPreconditionHolds(StringRef Msg,
ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
CheckerContext &C, const Stmt *ValueExpr, bool SuppressPath) const {
ProgramStateRef OriginalState = N->getState();
@@ -400,7 +389,7 @@
N = C.addTransition(OriginalState, N);
}
- reportBug(Error, N, Region, C.getBugReporter(), ValueExpr);
+ reportBug(Msg, Error, N, Region, C.getBugReporter(), ValueExpr);
}
/// Cleaning up the program state.
@@ -454,12 +443,30 @@
// Do not suppress errors on defensive code paths, because dereferencing
// a nullable pointer is always an error.
if (Event.IsDirectDereference)
- reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
- else
- reportBug(ErrorKind::NullablePassedToNonnull, Event.SinkNode, Region, BR);
+ reportBug("Nullable pointer is dereferenced",
+ ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
+ else {
+ reportBug("Nullable pointer is passed to a callee that requires a "
+ "non-null", ErrorKind::NullablePassedToNonnull,
+ Event.SinkNode, Region, BR);
+ }
}
}
+/// Find the outermost subexpression of E that is not an implicit cast.
+/// This looks through the implicit casts to _Nonnull that ARC adds to
+/// return expressions of ObjC types when the return type of the function or
+/// method is non-null but the express is not.
+static const Expr *lookThroughImplicitCasts(const Expr *E) {
+ assert(E);
+
+ while (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ E = ICE->getSubExpr();
+ }
+
+ return E;
+}
+
/// This method check when nullable pointer or null value is returned from a
/// function that has nonnull return type.
///
@@ -484,25 +491,57 @@
if (!RetSVal)
return;
+ bool InSuppressedMethodFamily = false;
+
+ QualType RequiredRetType;
AnalysisDeclContext *DeclCtxt =
C.getLocationContext()->getAnalysisDeclContext();
- const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
- if (!FuncType)
+ const Decl *D = DeclCtxt->getDecl();
+ if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ // HACK: This is a big hammer to avoid warning when there are defensive
+ // nil checks in -init and -copy methods. We should add more sophisticated
+ // logic here to suppress on common defensive idioms but still
+ // warn when there is a likely problem.
+ ObjCMethodFamily Family = MD->getMethodFamily();
+ if (OMF_init == Family || OMF_copy == Family || OMF_mutableCopy == Family)
+ InSuppressedMethodFamily = true;
+
+ RequiredRetType = MD->getReturnType();
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ RequiredRetType = FD->getReturnType();
+ } else {
return;
+ }
NullConstraint Nullness = getNullConstraint(*RetSVal, State);
- Nullability StaticNullability =
- getNullabilityAnnotation(FuncType->getReturnType());
+ Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
+
+ // If the returned value is null but the type of the expression
+ // generating it is nonnull then we will suppress the diagnostic.
+ // This enables explicit suppression when returning a nil literal in a
+ // function with a _Nonnull return type:
+ // return (NSString * _Nonnull)0;
+ Nullability RetExprTypeLevelNullability =
+ getNullabilityAnnotation(lookThroughImplicitCasts(RetExpr)->getType());
if (Filter.CheckNullReturnedFromNonnull &&
Nullness == NullConstraint::IsNull &&
- StaticNullability == Nullability::Nonnull) {
+ RetExprTypeLevelNullability != Nullability::Nonnull &&
+ RequiredNullability == Nullability::Nonnull &&
+ !InSuppressedMethodFamily) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
return;
- reportBugIfPreconditionHolds(ErrorKind::NilReturnedToNonnull, N, nullptr, C,
+
+ SmallString<256> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Null is returned from a " << C.getDeclDescription(D) <<
+ " that is expected to return a non-null value";
+
+ reportBugIfPreconditionHolds(OS.str(),
+ ErrorKind::NilReturnedToNonnull, N, nullptr, C,
RetExpr);
return;
}
@@ -518,17 +557,25 @@
if (Filter.CheckNullableReturnedFromNonnull &&
Nullness != NullConstraint::IsNotNull &&
TrackedNullabValue == Nullability::Nullable &&
- StaticNullability == Nullability::Nonnull) {
+ RequiredNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullableReturnedFromNonnull");
ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
- reportBugIfPreconditionHolds(ErrorKind::NullableReturnedToNonnull, N,
+
+ SmallString<256> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Nullable pointer is returned from a " << C.getDeclDescription(D) <<
+ " that is expected to return a non-null value";
+
+ reportBugIfPreconditionHolds(OS.str(),
+ ErrorKind::NullableReturnedToNonnull, N,
Region, C);
}
return;
}
- if (StaticNullability == Nullability::Nullable) {
+ if (RequiredNullability == Nullability::Nullable) {
State = State->set<NullabilityMap>(Region,
- NullabilityState(StaticNullability, S));
+ NullabilityState(RequiredNullability,
+ S));
C.addTransition(State);
}
}
@@ -564,18 +611,26 @@
NullConstraint Nullness = getNullConstraint(*ArgSVal, State);
- Nullability ParamNullability = getNullabilityAnnotation(Param->getType());
- Nullability ArgStaticNullability =
+ Nullability RequiredNullability =
+ getNullabilityAnnotation(Param->getType());
+ Nullability ArgExprTypeLevelNullability =
getNullabilityAnnotation(ArgExpr->getType());
+ unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
+
if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
- ArgStaticNullability != Nullability::Nonnull &&
- ParamNullability == Nullability::Nonnull) {
+ ArgExprTypeLevelNullability != Nullability::Nonnull &&
+ RequiredNullability == Nullability::Nonnull) {
ExplodedNode *N = C.generateErrorNode(State);
if (!N)
return;
- reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C,
- ArgExpr);
+ SmallString<256> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Null passed to a callee that requires a non-null " << ParamIdx
+ << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
+ reportBugIfPreconditionHolds(OS.str(), ErrorKind::NilPassedToNonnull, N,
+ nullptr, C,
+ ArgExpr, /*SuppressPath=*/false);
return;
}
@@ -592,26 +647,32 @@
continue;
if (Filter.CheckNullablePassedToNonnull &&
- ParamNullability == Nullability::Nonnull) {
+ RequiredNullability == Nullability::Nonnull) {
ExplodedNode *N = C.addTransition(State);
- reportBugIfPreconditionHolds(ErrorKind::NullablePassedToNonnull, N,
+ SmallString<256> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Nullable pointer is passed to a callee that requires a non-null "
+ << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
+ reportBugIfPreconditionHolds(OS.str(),
+ ErrorKind::NullablePassedToNonnull, N,
Region, C, ArgExpr, /*SuppressPath=*/true);
return;
}
if (Filter.CheckNullableDereferenced &&
Param->getType()->isReferenceType()) {
ExplodedNode *N = C.addTransition(State);
- reportBugIfPreconditionHolds(ErrorKind::NullableDereferenced, N, Region,
+ reportBugIfPreconditionHolds("Nullable pointer is dereferenced",
+ ErrorKind::NullableDereferenced, N, Region,
C, ArgExpr, /*SuppressPath=*/true);
return;
}
continue;
}
// No tracked nullability yet.
- if (ArgStaticNullability != Nullability::Nullable)
+ if (ArgExprTypeLevelNullability != Nullability::Nullable)
continue;
State = State->set<NullabilityMap>(
- Region, NullabilityState(ArgStaticNullability, ArgExpr));
+ Region, NullabilityState(ArgExprTypeLevelNullability, ArgExpr));
}
if (State != OrigState)
C.addTransition(State);
@@ -862,6 +923,72 @@
}
}
+/// For a given statement performing a bind, attempt to syntactically
+/// match the expression resulting in the bound value.
+static const Expr * matchValueExprForBind(const Stmt *S) {
+ // For `x = e` the value expression is the right-hand side.
+ if (auto *BinOp = dyn_cast<BinaryOperator>(S)) {
+ if (BinOp->getOpcode() == BO_Assign)
+ return BinOp->getRHS();
+ }
+
+ // For `int x = e` the value expression is the initializer.
+ if (auto *DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl()) {
+ auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!VD)
+ return nullptr;
+
+ if (const Expr *Init = VD->getInit())
+ return Init;
+ }
+ }
+
+ return nullptr;
+}
+
+/// Returns true if \param S is a DeclStmt for a local variable that
+/// ObjC automated reference counting initialized with zero.
+static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S) {
+ // We suppress diagnostics for ARC zero-initialized _Nonnull locals. This
+ // prevents false positives when a _Nonnull local variable cannot be
+ // initialized with an initialization expression:
+ // NSString * _Nonnull s; // no-warning
+ // @autoreleasepool {
+ // s = ...
+ // }
+ //
+ // FIXME: We should treat implicitly zero-initialized _Nonnull locals as
+ // uninitialized in Sema's UninitializedValues analysis to warn when a use of
+ // the zero-initialized definition will unexpectedly yield nil.
+
+ // Locals are only zero-initialized when automated reference counting
+ // is turned on.
+ if (!C.getASTContext().getLangOpts().ObjCAutoRefCount)
+ return false;
+
+ auto *DS = dyn_cast<DeclStmt>(S);
+ if (!DS || !DS->isSingleDecl())
+ return false;
+
+ auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!VD)
+ return false;
+
+ // Sema only zero-initializes locals with ObjCLifetimes.
+ if(!VD->getType().getQualifiers().hasObjCLifetime())
+ return false;
+
+ const Expr *Init = VD->getInit();
+ assert(Init && "ObjC local under ARC without initializer");
+
+ // Return false if the local is explicitly initialized (e.g., with '= nil').
+ if (!isa<ImplicitValueInitExpr>(Init))
+ return false;
+
+ return true;
+}
+
/// Propagate the nullability information through binds and warn when nullable
/// pointer or null symbol is assigned to a pointer with a nonnull type.
void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
@@ -893,13 +1020,21 @@
if (Filter.CheckNullPassedToNonnull &&
RhsNullness == NullConstraint::IsNull &&
ValNullability != Nullability::Nonnull &&
- LocNullability == Nullability::Nonnull) {
+ LocNullability == Nullability::Nonnull &&
+ !isARCNilInitializedLocal(C, S)) {
static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
return;
- reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
- S);
+
+ const Stmt *ValueExpr = matchValueExprForBind(S);
+ if (!ValueExpr)
+ ValueExpr = S;
+
+ reportBugIfPreconditionHolds("Null is assigned to a pointer which is "
+ "expected to have non-null value",
+ ErrorKind::NilAssignedToNonnull, N, nullptr, C,
+ ValueExpr);
return;
}
// Intentionally missing case: '0' is bound to a reference. It is handled by
@@ -920,7 +1055,9 @@
LocNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
- reportBugIfPreconditionHolds(ErrorKind::NullableAssignedToNonnull, N,
+ reportBugIfPreconditionHolds("Nullable pointer is assigned to a pointer "
+ "which is expected to have non-null value",
+ ErrorKind::NullableAssignedToNonnull, N,
ValueRegion, C);
}
return;
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 224251b..b10ec84 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -66,9 +66,8 @@
// The type must be an array/pointer type.
// This could be a null constant, which is allowed.
- if (E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull))
- return true;
- return false;
+ return static_cast<bool>(
+ E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull));
}
public:
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index f344dd0..ffa3a27 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -404,10 +404,7 @@
if (II == NSObjectII)
break;
}
- if (!ID)
- return false;
-
- return true;
+ return ID != nullptr;
}
/// \brief Returns true if the location is 'self'.
diff --git a/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
new file mode 100644
index 0000000..05bb7b7
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
@@ -0,0 +1,314 @@
+//=======- PaddingChecker.cpp ------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a checker that checks for padding that could be
+// removed by re-ordering members.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <numeric>
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
+private:
+ mutable std::unique_ptr<BugType> PaddingBug;
+ mutable int64_t AllowedPad;
+ mutable BugReporter *BR;
+
+public:
+ void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
+ BugReporter &BRArg) const {
+ BR = &BRArg;
+ AllowedPad =
+ MGR.getAnalyzerOptions().getOptionAsInteger("AllowedPad", 24, this);
+ assert(AllowedPad >= 0 && "AllowedPad option should be non-negative");
+
+ // The calls to checkAST* from AnalysisConsumer don't
+ // visit template instantiations or lambda classes. We
+ // want to visit those, so we make our own RecursiveASTVisitor.
+ struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
+ const PaddingChecker *Checker;
+ bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
+ explicit LocalVisitor(const PaddingChecker *Checker) : Checker(Checker) {}
+ bool VisitRecordDecl(const RecordDecl *RD) {
+ Checker->visitRecord(RD);
+ return true;
+ }
+ bool VisitVarDecl(const VarDecl *VD) {
+ Checker->visitVariable(VD);
+ return true;
+ }
+ // TODO: Visit array new and mallocs for arrays.
+ };
+
+ LocalVisitor visitor(this);
+ visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
+ }
+
+ /// \brief Look for records of overly padded types. If padding *
+ /// PadMultiplier exceeds AllowedPad, then generate a report.
+ /// PadMultiplier is used to share code with the array padding
+ /// checker.
+ void visitRecord(const RecordDecl *RD, uint64_t PadMultiplier = 1) const {
+ if (shouldSkipDecl(RD))
+ return;
+
+ auto &ASTContext = RD->getASTContext();
+ const ASTRecordLayout &RL = ASTContext.getASTRecordLayout(RD);
+ assert(llvm::isPowerOf2_64(RL.getAlignment().getQuantity()));
+
+ CharUnits BaselinePad = calculateBaselinePad(RD, ASTContext, RL);
+ if (BaselinePad.isZero())
+ return;
+ CharUnits OptimalPad = calculateOptimalPad(RD, ASTContext, RL);
+
+ CharUnits DiffPad = PadMultiplier * (BaselinePad - OptimalPad);
+ if (DiffPad.getQuantity() <= AllowedPad) {
+ assert(!DiffPad.isNegative() && "DiffPad should not be negative");
+ // There is not enough excess padding to trigger a warning.
+ return;
+ }
+ reportRecord(RD, BaselinePad, OptimalPad);
+ }
+
+ /// \brief Look for arrays of overly padded types. If the padding of the
+ /// array type exceeds AllowedPad, then generate a report.
+ void visitVariable(const VarDecl *VD) const {
+ const ArrayType *ArrTy = VD->getType()->getAsArrayTypeUnsafe();
+ if (ArrTy == nullptr)
+ return;
+ uint64_t Elts = 0;
+ if (const ConstantArrayType *CArrTy = dyn_cast<ConstantArrayType>(ArrTy))
+ Elts = CArrTy->getSize().getZExtValue();
+ if (Elts == 0)
+ return;
+ const RecordType *RT = ArrTy->getElementType()->getAs<RecordType>();
+ if (RT == nullptr)
+ return;
+
+ // TODO: Recurse into the fields and base classes to see if any
+ // of those have excess padding.
+ visitRecord(RT->getDecl(), Elts);
+ }
+
+ bool shouldSkipDecl(const RecordDecl *RD) const {
+ auto Location = RD->getLocation();
+ // If the construct doesn't have a source file, then it's not something
+ // we want to diagnose.
+ if (!Location.isValid())
+ return true;
+ SrcMgr::CharacteristicKind Kind =
+ BR->getSourceManager().getFileCharacteristic(Location);
+ // Throw out all records that come from system headers.
+ if (Kind != SrcMgr::C_User)
+ return true;
+
+ // Not going to attempt to optimize unions.
+ if (RD->isUnion())
+ return true;
+ // How do you reorder fields if you haven't got any?
+ if (RD->field_empty())
+ return true;
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ // Tail padding with base classes ends up being very complicated.
+ // We will skip objects with base classes for now.
+ if (CXXRD->getNumBases() != 0)
+ return true;
+ // Virtual bases are complicated, skipping those for now.
+ if (CXXRD->getNumVBases() != 0)
+ return true;
+ // Can't layout a template, so skip it. We do still layout the
+ // instantiations though.
+ if (CXXRD->getTypeForDecl()->isDependentType())
+ return true;
+ if (CXXRD->getTypeForDecl()->isInstantiationDependentType())
+ return true;
+ }
+ auto IsTrickyField = [](const FieldDecl *FD) -> bool {
+ // Bitfield layout is hard.
+ if (FD->isBitField())
+ return true;
+
+ // Variable length arrays are tricky too.
+ QualType Ty = FD->getType();
+ if (Ty->isIncompleteArrayType())
+ return true;
+ return false;
+ };
+
+ if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
+ return true;
+ return false;
+ }
+
+ static CharUnits calculateBaselinePad(const RecordDecl *RD,
+ const ASTContext &ASTContext,
+ const ASTRecordLayout &RL) {
+ CharUnits PaddingSum;
+ CharUnits Offset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
+ for (const auto &FD : RD->fields()) {
+ // This checker only cares about the padded size of the
+ // field, and not the data size. If the field is a record
+ // with tail padding, then we won't put that number in our
+ // total because reordering fields won't fix that problem.
+ CharUnits FieldSize = ASTContext.getTypeSizeInChars(FD->getType());
+ auto FieldOffsetBits = RL.getFieldOffset(FD->getFieldIndex());
+ CharUnits FieldOffset = ASTContext.toCharUnitsFromBits(FieldOffsetBits);
+ PaddingSum += (FieldOffset - Offset);
+ Offset = FieldOffset + FieldSize;
+ }
+ PaddingSum += RL.getSize() - Offset;
+ return PaddingSum;
+ }
+
+ /// Optimal padding overview:
+ /// 1. Find a close approximation to where we can place our first field.
+ /// This will usually be at offset 0.
+ /// 2. Try to find the best field that can legally be placed at the current
+ /// offset.
+ /// a. "Best" is the largest alignment that is legal, but smallest size.
+ /// This is to account for overly aligned types.
+ /// 3. If no fields can fit, pad by rounding the current offset up to the
+ /// smallest alignment requirement of our fields. Measure and track the
+ // amount of padding added. Go back to 2.
+ /// 4. Increment the current offset by the size of the chosen field.
+ /// 5. Remove the chosen field from the set of future possibilities.
+ /// 6. Go back to 2 if there are still unplaced fields.
+ /// 7. Add tail padding by rounding the current offset up to the structure
+ /// alignment. Track the amount of padding added.
+
+ static CharUnits calculateOptimalPad(const RecordDecl *RD,
+ const ASTContext &ASTContext,
+ const ASTRecordLayout &RL) {
+ struct CharUnitPair {
+ CharUnits Align;
+ CharUnits Size;
+ bool operator<(const CharUnitPair &RHS) const {
+ // Order from small alignments to large alignments,
+ // then large sizes to small sizes.
+ return std::make_pair(Align, -Size) <
+ std::make_pair(RHS.Align, -RHS.Size);
+ }
+ };
+ SmallVector<CharUnitPair, 20> Fields;
+ auto GatherSizesAndAlignments = [](const FieldDecl *FD) {
+ CharUnitPair RetVal;
+ auto &Ctx = FD->getASTContext();
+ std::tie(RetVal.Size, RetVal.Align) =
+ Ctx.getTypeInfoInChars(FD->getType());
+ assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity()));
+ if (auto Max = FD->getMaxAlignment())
+ RetVal.Align = std::max(Ctx.toCharUnitsFromBits(Max), RetVal.Align);
+ return RetVal;
+ };
+ std::transform(RD->field_begin(), RD->field_end(),
+ std::back_inserter(Fields), GatherSizesAndAlignments);
+ std::sort(Fields.begin(), Fields.end());
+
+ // This lets us skip over vptrs and non-virtual bases,
+ // so that we can just worry about the fields in our object.
+ // Note that this does cause us to miss some cases where we
+ // could pack more bytes in to a base class's tail padding.
+ CharUnits NewOffset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
+ CharUnits NewPad;
+
+ while (!Fields.empty()) {
+ unsigned TrailingZeros =
+ llvm::countTrailingZeros((unsigned long long)NewOffset.getQuantity());
+ // If NewOffset is zero, then countTrailingZeros will be 64. Shifting
+ // 64 will overflow our unsigned long long. Shifting 63 will turn
+ // our long long (and CharUnits internal type) negative. So shift 62.
+ long long CurAlignmentBits = 1ull << (std::min)(TrailingZeros, 62u);
+ CharUnits CurAlignment = CharUnits::fromQuantity(CurAlignmentBits);
+ CharUnitPair InsertPoint = {CurAlignment, CharUnits::Zero()};
+ auto CurBegin = Fields.begin();
+ auto CurEnd = Fields.end();
+
+ // In the typical case, this will find the last element
+ // of the vector. We won't find a middle element unless
+ // we started on a poorly aligned address or have an overly
+ // aligned field.
+ auto Iter = std::upper_bound(CurBegin, CurEnd, InsertPoint);
+ if (Iter != CurBegin) {
+ // We found a field that we can layout with the current alignment.
+ --Iter;
+ NewOffset += Iter->Size;
+ Fields.erase(Iter);
+ } else {
+ // We are poorly aligned, and we need to pad in order to layout another
+ // field. Round up to at least the smallest field alignment that we
+ // currently have.
+ CharUnits NextOffset = NewOffset.alignTo(Fields[0].Align);
+ NewPad += NextOffset - NewOffset;
+ NewOffset = NextOffset;
+ }
+ }
+ // Calculate tail padding.
+ CharUnits NewSize = NewOffset.alignTo(RL.getAlignment());
+ NewPad += NewSize - NewOffset;
+ return NewPad;
+ }
+
+ void reportRecord(const RecordDecl *RD, CharUnits BaselinePad,
+ CharUnits TargetPad) const {
+ if (!PaddingBug)
+ PaddingBug =
+ llvm::make_unique<BugType>(this, "Excessive Padding", "Performance");
+
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+
+ Os << "Excessive padding in '";
+ Os << QualType::getAsString(RD->getTypeForDecl(), Qualifiers()) << "'";
+
+ if (auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ // TODO: make this show up better in the console output and in
+ // the HTML. Maybe just make it show up in HTML like the path
+ // diagnostics show.
+ SourceLocation ILoc = TSD->getPointOfInstantiation();
+ if (ILoc.isValid())
+ Os << " instantiated here: "
+ << ILoc.printToString(BR->getSourceManager());
+ }
+
+ Os << " (" << BaselinePad.getQuantity() << " padding bytes, where "
+ << TargetPad.getQuantity() << " is optimal). Consider reordering "
+ << "the fields or adding explicit padding members.";
+
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::create(RD, BR->getSourceManager());
+
+ auto Report = llvm::make_unique<BugReport>(*PaddingBug, Os.str(), CELoc);
+ Report->setDeclWithIssue(RD);
+ Report->addRange(RD->getSourceRange());
+
+ BR->emitReport(std::move(Report));
+ }
+};
+}
+
+void ento::registerPaddingChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<PaddingChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 7026a2e..62e6f02 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -51,14 +51,11 @@
check::PreCall,
check::DeadSymbols,
check::PointerEscape> {
-
- mutable IdentifierInfo *IIfopen, *IIfclose;
+ CallDescription OpenFn, CloseFn;
std::unique_ptr<BugType> DoubleCloseBugType;
std::unique_ptr<BugType> LeakBugType;
- void initIdentifierInfo(ASTContext &Ctx) const;
-
void reportDoubleClose(SymbolRef FileDescSym,
const CallEvent &Call,
CheckerContext &C) const;
@@ -106,7 +103,7 @@
} // end anonymous namespace
SimpleStreamChecker::SimpleStreamChecker()
- : IIfopen(nullptr), IIfclose(nullptr) {
+ : OpenFn("fopen"), CloseFn("fclose", 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
@@ -119,12 +116,10 @@
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- initIdentifierInfo(C.getASTContext());
-
if (!Call.isGlobalCFunction())
return;
- if (Call.getCalleeIdentifier() != IIfopen)
+ if (!Call.isCalled(OpenFn))
return;
// Get the symbolic value corresponding to the file handle.
@@ -140,15 +135,10 @@
void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- initIdentifierInfo(C.getASTContext());
-
if (!Call.isGlobalCFunction())
return;
- if (Call.getCalleeIdentifier() != IIfclose)
- return;
-
- if (Call.getNumArgs() != 1)
+ if (!Call.isCalled(CloseFn))
return;
// Get the symbolic value corresponding to the file handle.
@@ -275,13 +265,6 @@
return State;
}
-void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const {
- if (IIfopen)
- return;
- IIfopen = &Ctx.Idents.get("fopen");
- IIfclose = &Ctx.Idents.get("fclose");
-}
-
void ento::registerSimpleStreamChecker(CheckerManager &mgr) {
mgr.registerChecker<SimpleStreamChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 2eefb93..79fc701 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -156,6 +156,15 @@
if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType())
return;
+ // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
+ // so the stack address is not escaping here.
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
+ if (isa<BlockDataRegion>(R) &&
+ ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
+ return;
+ }
+ }
+
EmitStackError(C, R, RetE);
}
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 9f66dc9..a03abce 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -235,12 +235,9 @@
return false;
// Run each of the checks on the conditions
- if (containsMacro(cond) || containsEnum(cond)
- || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
- || containsStmt<UnaryExprOrTypeTraitExpr>(cond))
- return true;
-
- return false;
+ return containsMacro(cond) || containsEnum(cond) ||
+ containsStaticLocal(cond) || containsBuiltinOffsetOf(cond) ||
+ containsStmt<UnaryExprOrTypeTraitExpr>(cond);
}
// Returns true if the given CFGBlock is empty
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 663518f..11be764 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2712,8 +2712,7 @@
if (Ranges.size() == 1 && !Ranges.begin()->isValid())
return llvm::make_range(ranges_iterator(), ranges_iterator());
- return llvm::iterator_range<BugReport::ranges_iterator>(Ranges.begin(),
- Ranges.end());
+ return llvm::make_range(Ranges.begin(), Ranges.end());
}
PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ec1310d..ae5cd54 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -828,8 +829,53 @@
// Check if this is inlined defensive checks.
const LocationContext *CurLC =Succ->getLocationContext();
const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
- if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+ if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
BR.markInvalid("Suppress IDC", CurLC);
+ return nullptr;
+ }
+
+ // Treat defensive checks in function-like macros as if they were an inlined
+ // defensive check. If the bug location is not in a macro and the
+ // terminator for the current location is in a macro then suppress the
+ // warning.
+ auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
+
+ if (!BugPoint)
+ return nullptr;
+
+ SourceLocation BugLoc = BugPoint->getStmt()->getLocStart();
+ if (BugLoc.isMacroID())
+ return nullptr;
+
+ ProgramPoint CurPoint = Succ->getLocation();
+ const Stmt *CurTerminatorStmt = nullptr;
+ if (auto BE = CurPoint.getAs<BlockEdge>()) {
+ CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
+ } else if (auto SP = CurPoint.getAs<StmtPoint>()) {
+ const Stmt *CurStmt = SP->getStmt();
+ if (!CurStmt->getLocStart().isMacroID())
+ return nullptr;
+
+ CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
+ CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminator();
+ } else {
+ return nullptr;
+ }
+
+ if (!CurTerminatorStmt)
+ return nullptr;
+
+ SourceLocation TerminatorLoc = CurTerminatorStmt->getLocStart();
+ if (TerminatorLoc.isMacroID()) {
+ const SourceManager &SMgr = BRC.getSourceManager();
+ std::pair<FileID, unsigned> TLInfo = SMgr.getDecomposedLoc(TerminatorLoc);
+ SrcMgr::SLocEntry SE = SMgr.getSLocEntry(TLInfo.first);
+ const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion();
+ if (EInfo.isFunctionMacroExpansion()) {
+ BR.markInvalid("Suppress Macro IDC", CurLC);
+ return nullptr;
+ }
+ }
}
return nullptr;
}
@@ -1542,6 +1588,16 @@
}
}
+ // The analyzer issues a false positive when the constructor of
+ // std::__independent_bits_engine from algorithms is used.
+ if (const CXXConstructorDecl *MD = dyn_cast<CXXConstructorDecl>(D)) {
+ const CXXRecordDecl *CD = MD->getParent();
+ if (CD->getName() == "__independent_bits_engine") {
+ BR.markInvalid(getTag(), nullptr);
+ return nullptr;
+ }
+ }
+
// The analyzer issues a false positive on
// std::basic_string<uint8_t> v; v.push_back(1);
// and
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index a07427a..59b90b5 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -210,6 +210,16 @@
return PostImplicitCall(D, Loc, getLocationContext(), Tag);
}
+bool CallEvent::isCalled(const CallDescription &CD) const {
+ assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported");
+ if (!CD.II)
+ CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
+ if (getCalleeIdentifier() != CD.II)
+ return false;
+ return (CD.RequiredArgs == CallDescription::NoArgRequirement ||
+ CD.RequiredArgs == getNumArgs());
+}
+
SVal CallEvent::getArgSVal(unsigned Index) const {
const Expr *ArgE = getArgExpr(Index);
if (!ArgE)
@@ -420,8 +430,8 @@
return getSVal(CE->getCallee()).getAsFunctionDecl();
}
-void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values,
- RegionAndSymbolInvalidationTraits *ETraits) const {
+void CXXInstanceCall::getExtraInvalidatedValues(
+ ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const {
SVal ThisVal = getCXXThisVal();
Values.push_back(ThisVal);
@@ -442,7 +452,7 @@
return;
ETraits->setTrait(ThisRegion->getBaseRegion(),
- RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents);
}
}
@@ -598,10 +608,25 @@
void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const {
- const BlockDecl *D = cast<BlockDecl>(CalleeCtx->getDecl());
SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ ArrayRef<ParmVarDecl*> Params;
+ if (isConversionFromLambda()) {
+ auto *LambdaOperatorDecl = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+ Params = LambdaOperatorDecl->parameters();
+
+ // For blocks converted from a C++ lambda, the callee declaration is the
+ // operator() method on the lambda so we bind "this" to
+ // the lambda captured by the block.
+ const VarRegion *CapturedLambdaRegion = getRegionStoringCapturedLambda();
+ SVal ThisVal = loc::MemRegionVal(CapturedLambdaRegion);
+ Loc ThisLoc = SVB.getCXXThis(LambdaOperatorDecl, CalleeCtx);
+ Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
+ } else {
+ Params = cast<BlockDecl>(CalleeCtx->getDecl())->parameters();
+ }
+
addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
- D->parameters());
+ Params);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 37b2564..548b06e 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -35,6 +35,13 @@
return funI->getName();
}
+StringRef CheckerContext::getDeclDescription(const Decl *D) {
+ if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
+ return "method";
+ if (isa<BlockDecl>(D))
+ return "anonymous block";
+ return "function";
+}
bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
StringRef Name) {
@@ -57,12 +64,8 @@
return false;
// Look through 'extern "C"' and anything similar invented in the future.
- const DeclContext *DC = FD->getDeclContext();
- while (DC->isTransparentContext())
- DC = DC->getParent();
-
- // If this function is in a namespace, it is not a C library function.
- if (!DC->isTranslationUnit())
+ // If this function is not in TU directly, it is not a C library function.
+ if (!FD->getDeclContext()->getRedeclContext()->isTranslationUnit())
return false;
// If this function is not externally visible, it is not a C library function.
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index a15e157..ba03e2f 100644
--- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -49,12 +49,12 @@
CheckerOptInfo &opt, CheckerInfoSet &collected) {
// Use a binary search to find the possible start of the package.
CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
- CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
+ auto end = checkers.cend();
CheckerRegistry::CheckerInfoList::const_iterator i =
- std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
+ std::lower_bound(checkers.cbegin(), end, packageInfo, checkerNameLT);
// If we didn't even find a possible package, give up.
- if (i == e)
+ if (i == end)
return;
// If what we found doesn't actually start the package, give up.
@@ -73,7 +73,7 @@
size = packageSize->getValue();
// Step through all the checkers in the package.
- for (e = i+size; i != e; ++i) {
+ for (auto checkEnd = i+size; i != checkEnd; ++i) {
if (opt.isEnabled())
collected.insert(&*i);
else
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index d55858d..e2cb52c 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -171,10 +171,6 @@
// Copy the binding to the new map.
EBMapRef = EBMapRef.add(BlkExpr, X);
- // If the block expr's value is a memory region, then mark that region.
- if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>())
- SymReaper.markLive(R->getRegion());
-
// Mark all symbols in the block expr's value live.
RSScaner.scan(X);
continue;
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index b6aed88..662b0a2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -476,8 +476,12 @@
if (BMI->isAnyMemberInitializer()) {
// Constructors build the object directly in the field,
// but non-objects must be copied in from the initializer.
- const Expr *Init = BMI->getInit()->IgnoreImplicit();
- if (!isa<CXXConstructExpr>(Init)) {
+ if (auto *CtorExpr = findDirectConstructorForCurrentCFGElement()) {
+ assert(BMI->getInit()->IgnoreImplicit() == CtorExpr);
+ (void)CtorExpr;
+ // The field was directly constructed, so there is no need to bind.
+ } else {
+ const Expr *Init = BMI->getInit()->IgnoreImplicit();
const ValueDecl *Field;
if (BMI->isIndirectMemberInitializer()) {
Field = BMI->getIndirectMember();
@@ -755,6 +759,7 @@
case Stmt::CXXUuidofExprClass:
case Stmt::CXXFoldExprClass:
case Stmt::MSPropertyRefExprClass:
+ case Stmt::MSPropertySubscriptExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::ArrayTypeTraitExprClass:
@@ -828,6 +833,9 @@
case Stmt::OMPTeamsDirectiveClass:
case Stmt::OMPCancellationPointDirectiveClass:
case Stmt::OMPCancelDirectiveClass:
+ case Stmt::OMPTaskLoopDirectiveClass:
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPDistributeDirectiveClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -1571,7 +1579,6 @@
return;
}
-
if (const Expr *Ex = dyn_cast<Expr>(Condition))
Condition = Ex->IgnoreParens();
@@ -1867,7 +1874,7 @@
const auto *MD = D ? dyn_cast<CXXMethodDecl>(D) : nullptr;
const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
SVal V;
- bool CaptureByReference = false;
+ bool IsReference;
if (AMgr.options.shouldInlineLambdas() && DeclRefEx &&
DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
MD->getParent()->isLambda()) {
@@ -1882,22 +1889,22 @@
// created in the lambda object.
assert(VD->getType().isConstQualified());
V = state->getLValue(VD, LocCtxt);
+ IsReference = false;
} else {
Loc CXXThis =
svalBuilder.getCXXThis(MD, LocCtxt->getCurrentStackFrame());
SVal CXXThisVal = state->getSVal(CXXThis);
V = state->getLValue(FD, CXXThisVal);
- if (FD->getType()->isReferenceType() &&
- !VD->getType()->isReferenceType())
- CaptureByReference = true;
+ IsReference = FD->getType()->isReferenceType();
}
} else {
V = state->getLValue(VD, LocCtxt);
+ IsReference = VD->getType()->isReferenceType();
}
// For references, the 'lvalue' is the pointer address stored in the
// reference region.
- if (VD->getType()->isReferenceType() || CaptureByReference) {
+ if (IsReference) {
if (const MemRegion *R = V.getAsRegion())
V = state->getSVal(R);
else
@@ -1943,7 +1950,6 @@
const Expr *Base = A->getBase()->IgnoreParens();
const Expr *Idx = A->getIdx()->IgnoreParens();
-
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
@@ -2049,6 +2055,7 @@
namespace {
class CollectReachableSymbolsCallback final : public SymbolVisitor {
InvalidatedSymbols Symbols;
+
public:
CollectReachableSymbolsCallback(ProgramStateRef State) {}
const InvalidatedSymbols &getSymbols() const { return Symbols; }
@@ -2171,7 +2178,6 @@
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
StoreE, *this, *PP);
-
StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx);
// If the location is not a 'Loc', it will already be handled by
@@ -2185,7 +2191,6 @@
return;
}
-
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index a1bca61..175225b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -189,8 +189,9 @@
CanQualType T = getContext().getCanonicalType(BE->getType());
+ const BlockDecl *BD = BE->getBlockDecl();
// Get the value of the block itself.
- SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
+ SVal V = svalBuilder.getBlockPointer(BD, T,
Pred->getLocationContext(),
currBldrCtx->blockCount());
@@ -204,11 +205,32 @@
BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
E = BDR->referenced_vars_end();
+ auto CI = BD->capture_begin();
+ auto CE = BD->capture_end();
for (; I != E; ++I) {
- const MemRegion *capturedR = I.getCapturedRegion();
- const MemRegion *originalR = I.getOriginalRegion();
+ const VarRegion *capturedR = I.getCapturedRegion();
+ const VarRegion *originalR = I.getOriginalRegion();
+
+ // If the capture had a copy expression, use the result of evaluating
+ // that expression, otherwise use the original value.
+ // We rely on the invariant that the block declaration's capture variables
+ // are a prefix of the BlockDataRegion's referenced vars (which may include
+ // referenced globals, etc.) to enable fast lookup of the capture for a
+ // given referenced var.
+ const Expr *copyExpr = nullptr;
+ if (CI != CE) {
+ assert(CI->getVariable() == capturedR->getDecl());
+ copyExpr = CI->getCopyExpr();
+ CI++;
+ }
+
if (capturedR != originalR) {
- SVal originalV = State->getSVal(loc::MemRegionVal(originalR));
+ SVal originalV;
+ if (copyExpr) {
+ originalV = State->getSVal(copyExpr, Pred->getLocationContext());
+ } else {
+ originalV = State->getSVal(loc::MemRegionVal(originalR));
+ }
State = State->bindLoc(loc::MemRegionVal(capturedR), originalV);
}
}
@@ -294,7 +316,7 @@
case CK_ArrayToPointerDecay:
case CK_BitCast:
case CK_AddressSpaceConversion:
- case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_NullToPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
@@ -323,6 +345,17 @@
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
+ // Negate the result if we're treating the boolean as a signed i1
+ if (CastE->getCastKind() == CK_BooleanToSignedIntegral)
+ V = evalMinus(V);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ case CK_IntegralCast: {
+ // Delegate to SValBuilder to process.
+ SVal V = state->getSVal(Ex, LCtx);
+ V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
@@ -470,7 +503,10 @@
ExplodedNode *UpdatedN = N;
SVal InitVal = state->getSVal(InitEx, LC);
- if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) {
+ assert(DS->isSingleDecl());
+ if (auto *CtorExpr = findDirectConstructorForCurrentCFGElement()) {
+ assert(InitEx->IgnoreImplicit() == CtorExpr);
+ (void)CtorExpr;
// We constructed the object directly in the variable.
// No need to bind anything.
B.generateNode(DS, UpdatedN, state);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 1958d7b..556e223 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -103,49 +103,32 @@
}
-static const MemRegion *getRegionForConstructedObject(
- const CXXConstructExpr *CE, ExplodedNode *Pred, ExprEngine &Eng,
- unsigned int CurrStmtIdx) {
+const MemRegion *
+ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
+ ExplodedNode *Pred) {
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
- const NodeBuilderContext &CurrBldrCtx = Eng.getBuilderContext();
// See if we're constructing an existing region by looking at the next
// element in the CFG.
- const CFGBlock *B = CurrBldrCtx.getBlock();
- unsigned int NextStmtIdx = CurrStmtIdx + 1;
- if (NextStmtIdx < B->size()) {
- CFGElement Next = (*B)[NextStmtIdx];
- // Is this a destructor? If so, we might be in the middle of an assignment
- // to a local or member: look ahead one more element to see what we find.
- while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) {
- ++NextStmtIdx;
- Next = (*B)[NextStmtIdx];
- }
-
- // Is this a constructor for a local variable?
- if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {
- if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) {
- if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
- if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) {
- SVal LValue = State->getLValue(Var, LCtx);
- QualType Ty = Var->getType();
- LValue = makeZeroElementRegion(State, LValue, Ty);
- return LValue.getAsRegion();
- }
+ if (auto Elem = findElementDirectlyInitializedByCurrentConstructor()) {
+ if (Optional<CFGStmt> StmtElem = Elem->getAs<CFGStmt>()) {
+ auto *DS = cast<DeclStmt>(StmtElem->getStmt());
+ if (const auto *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
+ if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) {
+ SVal LValue = State->getLValue(Var, LCtx);
+ QualType Ty = Var->getType();
+ LValue = makeZeroElementRegion(State, LValue, Ty);
+ return LValue.getAsRegion();
}
}
- }
-
- // Is this a constructor for a member?
- if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) {
+ } else if (Optional<CFGInitializer> InitElem = Elem->getAs<CFGInitializer>()) {
const CXXCtorInitializer *Init = InitElem->getInitializer();
assert(Init->isAnyMemberInitializer());
-
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
- Loc ThisPtr = Eng.getSValBuilder().getCXXThis(CurCtor,
- LCtx->getCurrentStackFrame());
+ Loc ThisPtr =
+ getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
const ValueDecl *Field;
@@ -167,13 +150,86 @@
// Don't forget to update the pre-constructor initialization code in
// ExprEngine::VisitCXXConstructExpr.
}
-
// If we couldn't find an existing region to construct into, assume we're
// constructing a temporary.
- MemRegionManager &MRMgr = Eng.getSValBuilder().getRegionManager();
+ MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
return MRMgr.getCXXTempObjectRegion(CE, LCtx);
}
+/// Returns true if the initializer for \Elem can be a direct
+/// constructor.
+static bool canHaveDirectConstructor(CFGElement Elem){
+ // DeclStmts and CXXCtorInitializers for fields can be directly constructed.
+
+ if (Optional<CFGStmt> StmtElem = Elem.getAs<CFGStmt>()) {
+ if (isa<DeclStmt>(StmtElem->getStmt())) {
+ return true;
+ }
+ }
+
+ if (Elem.getKind() == CFGElement::Initializer) {
+ return true;
+ }
+
+ return false;
+}
+
+Optional<CFGElement>
+ExprEngine::findElementDirectlyInitializedByCurrentConstructor() {
+ const NodeBuilderContext &CurrBldrCtx = getBuilderContext();
+ // See if we're constructing an existing region by looking at the next
+ // element in the CFG.
+ const CFGBlock *B = CurrBldrCtx.getBlock();
+ assert(isa<CXXConstructExpr>(((*B)[currStmtIdx]).castAs<CFGStmt>().getStmt()));
+ unsigned int NextStmtIdx = currStmtIdx + 1;
+ if (NextStmtIdx >= B->size())
+ return None;
+
+ CFGElement Next = (*B)[NextStmtIdx];
+
+ // Is this a destructor? If so, we might be in the middle of an assignment
+ // to a local or member: look ahead one more element to see what we find.
+ while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) {
+ ++NextStmtIdx;
+ Next = (*B)[NextStmtIdx];
+ }
+
+ if (canHaveDirectConstructor(Next))
+ return Next;
+
+ return None;
+}
+
+const CXXConstructExpr *
+ExprEngine::findDirectConstructorForCurrentCFGElement() {
+ // Go backward in the CFG to see if the previous element (ignoring
+ // destructors) was a CXXConstructExpr. If so, that constructor
+ // was constructed directly into an existing region.
+ // This process is essentially the inverse of that performed in
+ // findElementDirectlyInitializedByCurrentConstructor().
+ if (currStmtIdx == 0)
+ return nullptr;
+
+ const CFGBlock *B = getBuilderContext().getBlock();
+ assert(canHaveDirectConstructor((*B)[currStmtIdx]));
+
+ unsigned int PreviousStmtIdx = currStmtIdx - 1;
+ CFGElement Previous = (*B)[PreviousStmtIdx];
+
+ while (Previous.getAs<CFGImplicitDtor>() && PreviousStmtIdx > 0) {
+ --PreviousStmtIdx;
+ Previous = (*B)[PreviousStmtIdx];
+ }
+
+ if (Optional<CFGStmt> PrevStmtElem = Previous.getAs<CFGStmt>()) {
+ if (auto *CtorExpr = dyn_cast<CXXConstructExpr>(PrevStmtElem->getStmt())) {
+ return CtorExpr;
+ }
+ }
+
+ return nullptr;
+}
+
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
@@ -188,7 +244,7 @@
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
- Target = getRegionForConstructedObject(CE, Pred, *this, currStmtIdx);
+ Target = getRegionForConstructedObject(CE, Pred);
break;
}
case CXXConstructExpr::CK_VirtualBase:
@@ -531,9 +587,23 @@
for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(),
e = LE->capture_init_end();
i != e; ++i, ++CurField) {
- SVal Field = State->getLValue(*CurField, V);
- SVal InitExpr = State->getSVal(*i, LocCtxt);
- State = State->bindLoc(Field, InitExpr);
+ FieldDecl *FieldForCapture = *CurField;
+ SVal FieldLoc = State->getLValue(FieldForCapture, V);
+
+ SVal InitVal;
+ if (!FieldForCapture->hasCapturedVLAType()) {
+ Expr *InitExpr = *i;
+ assert(InitExpr && "Capture missing initialization expression");
+ InitVal = State->getSVal(InitExpr, LocCtxt);
+ } else {
+ // The field stores the length of a captured variable-length array.
+ // These captures don't have initialization expressions; instead we
+ // get the length from the VLAType size expression.
+ Expr *SizeExpr = FieldForCapture->getCapturedVLAType()->getSizeExpr();
+ InitVal = State->getSVal(SizeExpr, LocCtxt);
+ }
+
+ State = State->bindLoc(FieldLoc, InitVal);
}
// Decay the Loc into an RValue, because there might be a
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 25c0cf2..74cc8d2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -421,7 +421,8 @@
const LocationContext *CurLC = Pred->getLocationContext();
const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
const LocationContext *ParentOfCallee = CallerSFC;
- if (Call.getKind() == CE_Block) {
+ if (Call.getKind() == CE_Block &&
+ !cast<BlockCall>(Call).isConversionFromLambda()) {
const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
assert(BR && "If we have the block definition we should have its region");
AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 86eab41..b3edb85 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -123,10 +123,10 @@
// The path as already been prechecked that all parts of the path are
// from the same file and that it is non-empty.
- const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
+ const SourceManager &SMgr = path.front()->getLocation().getManager();
assert(!path.empty());
FileID FID =
- (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
+ path.front()->getLocation().asLocation().getExpansionLoc().getFileID();
assert(FID.isValid());
// Create a new rewriter to generate HTML.
@@ -144,7 +144,7 @@
// Retrieve the relative position of the declaration which will be used
// for the file name
FullSourceLoc L(
- SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()),
+ SMgr.getExpansionLoc(path.back()->getLocation().asLocation()),
SMgr);
FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr);
offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
@@ -188,8 +188,8 @@
DirName += '/';
}
- int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber();
- int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber();
+ int LineNumber = path.back()->getLocation().asLocation().getExpansionLineNumber();
+ int ColumnNumber = path.back()->getLocation().asLocation().getExpansionColumnNumber();
// Add the name of the file as an <h1> tag.
@@ -255,8 +255,8 @@
os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT "
- << GetIssueHash(SMgr, L, D.getCheckName(), D.getBugType(), DeclWithIssue)
- << " -->\n";
+ << GetIssueHash(SMgr, L, D.getCheckName(), D.getBugType(), DeclWithIssue,
+ PP.getLangOpts()) << " -->\n";
os << "\n<!-- BUGLINE "
<< LineNumber
diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp
index abe20d6..0a3af3d 100644
--- a/lib/StaticAnalyzer/Core/IssueHash.cpp
+++ b/lib/StaticAnalyzer/Core/IssueHash.cpp
@@ -127,14 +127,13 @@
}
static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
- const Decl *D) {
+ const LangOptions &LangOpts) {
static StringRef Whitespaces = " \t\n";
- const LangOptions &Opts = D->getASTContext().getLangOpts();
StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
L.getExpansionLineNumber());
unsigned col = Str.find_first_not_of(Whitespaces);
-
+ col++;
SourceLocation StartOfLine =
SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
llvm::MemoryBuffer *Buffer =
@@ -145,7 +144,7 @@
const char *BufferPos = SM.getCharacterData(StartOfLine);
Token Token;
- Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), Opts,
+ Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
size_t NextStart = 0;
@@ -175,20 +174,23 @@
std::string clang::GetIssueString(const SourceManager &SM,
FullSourceLoc &IssueLoc,
StringRef CheckerName, StringRef BugType,
- const Decl *D) {
+ const Decl *D,
+ const LangOptions &LangOpts) {
static StringRef Delimiter = "$";
return (llvm::Twine(CheckerName) + Delimiter +
GetEnclosingDeclContextSignature(D) + Delimiter +
llvm::utostr(IssueLoc.getExpansionColumnNumber()) + Delimiter +
- NormalizeLine(SM, IssueLoc, D) + Delimiter + BugType)
+ NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
.str();
}
SmallString<32> clang::GetIssueHash(const SourceManager &SM,
FullSourceLoc &IssueLoc,
StringRef CheckerName, StringRef BugType,
- const Decl *D) {
+ const Decl *D,
+ const LangOptions &LangOpts) {
+
return GetHashOfContent(
- GetIssueString(SM, IssueLoc, CheckerName, BugType, D));
+ GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
}
diff --git a/lib/StaticAnalyzer/Core/LoopWidening.cpp b/lib/StaticAnalyzer/Core/LoopWidening.cpp
index 726f86f..05865c2 100644
--- a/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -1,4 +1,4 @@
-//===--- LoopWidening.cpp - Instruction class definition --------*- C++ -*-===//
+//===--- LoopWidening.cpp - Widen loops -------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 632a381..30052cc 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -245,7 +245,7 @@
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
-void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger((unsigned)getKind());
}
@@ -357,31 +357,31 @@
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
}
-void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const NamedDecl *FD,
const MemRegion*) {
- ID.AddInteger(MemRegion::FunctionTextRegionKind);
+ ID.AddInteger(MemRegion::FunctionCodeRegionKind);
ID.AddPointer(FD);
}
-void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- FunctionTextRegion::ProfileRegion(ID, FD, superRegion);
+void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
}
-void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockDecl *BD, CanQualType,
const AnalysisDeclContext *AC,
const MemRegion*) {
- ID.AddInteger(MemRegion::BlockTextRegionKind);
+ ID.AddInteger(MemRegion::BlockCodeRegionKind);
ID.AddPointer(BD);
}
-void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
+void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
}
void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockTextRegion *BC,
+ const BlockCodeRegion *BC,
const LocationContext *LC,
unsigned BlkCount,
const MemRegion *sReg) {
@@ -457,11 +457,11 @@
os << "alloca{" << (const void*) Ex << ',' << Cnt << '}';
}
-void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
+void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
-void BlockTextRegion::dumpToStream(raw_ostream &os) const {
+void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
os << "block_code{" << (const void*) this << '}';
}
@@ -533,6 +533,10 @@
os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
}
+void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "CodeSpaceRegion";
+}
+
void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "StaticGlobalsMemSpace{" << CR << '}';
}
@@ -711,11 +715,11 @@
return LazyAllocate(heap);
}
-const MemSpaceRegion *MemRegionManager::getUnknownRegion() {
+const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
-const MemSpaceRegion *MemRegionManager::getCodeRegion() {
+const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
return LazyAllocate(code);
}
@@ -815,11 +819,11 @@
const Decl *STCD = STC->getDecl();
if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD))
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- getFunctionTextRegion(cast<NamedDecl>(STCD)));
+ getFunctionCodeRegion(cast<NamedDecl>(STCD)));
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
// FIXME: The fallback type here is totally bogus -- though it should
// never be queried, it will prevent uniquing with the real
- // BlockTextRegion. Ideally we'd fix the AST so that we always had a
+ // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
// signature.
QualType T;
if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
@@ -830,8 +834,8 @@
T = getContext().getFunctionNoProtoType(T);
T = getContext().getBlockPointerType(T);
- const BlockTextRegion *BTR =
- getBlockTextRegion(BD, C.getCanonicalType(T),
+ const BlockCodeRegion *BTR =
+ getBlockCodeRegion(BD, C.getCanonicalType(T),
STC->getAnalysisDeclContext());
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
BTR);
@@ -852,7 +856,7 @@
}
const BlockDataRegion *
-MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
const LocationContext *LC,
unsigned blockCount) {
const MemRegion *sReg = nullptr;
@@ -925,15 +929,15 @@
return R;
}
-const FunctionTextRegion *
-MemRegionManager::getFunctionTextRegion(const NamedDecl *FD) {
- return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
+const FunctionCodeRegion *
+MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
+ return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
}
-const BlockTextRegion *
-MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
+const BlockCodeRegion *
+MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
AnalysisDeclContext *AC) {
- return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
+ return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
}
@@ -1177,6 +1181,7 @@
/// Returns true if \p Base is an immediate base class of \p Child
static bool isImmediateBase(const CXXRecordDecl *Child,
const CXXRecordDecl *Base) {
+ assert(Child && "Child must not be null");
// Note that we do NOT canonicalize the base class here, because
// ASTRecordLayout doesn't either. If that leads us down the wrong path,
// so be it; at least we won't crash.
@@ -1195,7 +1200,7 @@
while (1) {
switch (R->getKind()) {
- case GenericMemSpaceRegionKind:
+ case CodeSpaceRegionKind:
case StackLocalsSpaceRegionKind:
case StackArgumentsSpaceRegionKind:
case HeapSpaceRegionKind:
@@ -1208,8 +1213,8 @@
assert(Offset == 0 && !SymbolicOffsetBase);
goto Finish;
- case FunctionTextRegionKind:
- case BlockTextRegionKind:
+ case FunctionCodeRegionKind:
+ case BlockCodeRegionKind:
case BlockDataRegionKind:
// These will never have bindings, but may end up having values requested
// if the user does some strange casting.
@@ -1256,18 +1261,18 @@
if (!Child) {
// We cannot compute the offset of the base class.
SymbolicOffsetBase = R;
- }
-
- if (RootIsSymbolic) {
- // Base layers on symbolic regions may not be type-correct.
- // Double-check the inheritance here, and revert to a symbolic offset
- // if it's invalid (e.g. due to a reinterpret_cast).
- if (BOR->isVirtual()) {
- if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
- SymbolicOffsetBase = R;
- } else {
- if (!isImmediateBase(Child, BOR->getDecl()))
- SymbolicOffsetBase = R;
+ } else {
+ if (RootIsSymbolic) {
+ // Base layers on symbolic regions may not be type-correct.
+ // Double-check the inheritance here, and revert to a symbolic offset
+ // if it's invalid (e.g. due to a reinterpret_cast).
+ if (BOR->isVirtual()) {
+ if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ } else {
+ if (!isImmediateBase(Child, BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ }
}
}
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 2bf4394..55e1222 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -295,7 +295,7 @@
const SourceManager* SM = nullptr;
if (!Diags.empty())
- SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
+ SM = &Diags.front()->path.front()->getLocation().getManager();
for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
@@ -399,7 +399,7 @@
*SM);
const Decl *DeclWithIssue = D->getDeclWithIssue();
EmitString(o, GetIssueHash(*SM, L, D->getCheckName(), D->getBugType(),
- DeclWithIssue))
+ DeclWithIssue, LangOpts))
<< '\n';
// Output information about the semantic context where
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 4f9ad9e..100fa75 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -536,19 +536,19 @@
// TODO: should be rewritten using SymExpr::symbol_iterator.
switch (sym->getKind()) {
- case SymExpr::RegionValueKind:
- case SymExpr::ConjuredKind:
- case SymExpr::DerivedKind:
- case SymExpr::ExtentKind:
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolRegionValueKind:
+ case SymExpr::SymbolConjuredKind:
+ case SymExpr::SymbolDerivedKind:
+ case SymExpr::SymbolExtentKind:
+ case SymExpr::SymbolMetadataKind:
break;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
return scan(cast<SymbolCast>(sym)->getOperand());
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
return scan(cast<SymIntExpr>(sym)->getLHS());
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
return scan(cast<IntSymExpr>(sym)->getRHS());
- case SymExpr::SymSymKind: {
+ case SymExpr::SymSymExprKind: {
const SymSymExpr *x = cast<SymSymExpr>(sym);
return scan(x->getLHS()) && scan(x->getRHS());
}
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 0a2b2e6..77b0ad3 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -171,7 +171,7 @@
case APSIntType::RTR_Below:
// The entire range is outside the symbol's set of possible values.
// If this is a conventionally-ordered range, the state is infeasible.
- if (Lower < Upper)
+ if (Lower <= Upper)
return false;
// However, if the range wraps around, it spans all possible values.
@@ -222,7 +222,7 @@
case APSIntType::RTR_Above:
// The entire range is outside the symbol's set of possible values.
// If this is a conventionally-ordered range, the state is infeasible.
- if (Lower < Upper)
+ if (Lower <= Upper)
return false;
// However, if the range wraps around, it spans all possible values.
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 1fe83ef..a63f6e4 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2348,8 +2348,12 @@
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) {
+ // Element index of a binding key is live.
+ SymReaper.markElementIndicesLive(I.getKey().getRegion());
+
VisitBinding(I.getData());
+ }
}
void removeDeadBindingsWorker::VisitBinding(SVal V) {
@@ -2370,6 +2374,7 @@
// If V is a region, then add it to the worklist.
if (const MemRegion *R = V.getAsRegion()) {
AddToWorkList(R);
+ SymReaper.markLive(R);
// All regions captured by a block are also live.
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 4f8ccd0..22bc14e 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -95,6 +95,9 @@
SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
QualType T = region->getValueType();
+ if (T->isNullPtrType())
+ return makeZeroVal(T);
+
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
@@ -112,6 +115,9 @@
unsigned Count) {
QualType T = Ex->getType();
+ if (T->isNullPtrType())
+ return makeZeroVal(T);
+
// Compute the type of the result. If the expression is not an R-value, the
// result should be a location.
QualType ExType = Ex->getType();
@@ -126,6 +132,9 @@
const LocationContext *LCtx,
QualType type,
unsigned count) {
+ if (type->isNullPtrType())
+ return makeZeroVal(type);
+
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
@@ -142,6 +151,9 @@
const LocationContext *LCtx,
QualType type,
unsigned visitCount) {
+ if (type->isNullPtrType())
+ return makeZeroVal(type);
+
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
@@ -160,6 +172,8 @@
QualType T = E->getType();
assert(Loc::isLocType(T));
assert(SymbolManager::canSymbolicate(T));
+ if (T->isNullPtrType())
+ return makeZeroVal(T);
SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount);
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
@@ -185,6 +199,9 @@
const TypedValueRegion *region) {
QualType T = region->getValueType();
+ if (T->isNullPtrType())
+ return makeZeroVal(T);
+
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
@@ -197,15 +214,15 @@
}
DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
- return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func));
+ return loc::MemRegionVal(MemMgr.getFunctionCodeRegion(func));
}
DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
CanQualType locTy,
const LocationContext *locContext,
unsigned blockCount) {
- const BlockTextRegion *BC =
- MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisDeclContext());
+ const BlockCodeRegion *BC =
+ MemMgr.getBlockCodeRegion(block, locTy, locContext->getAnalysisDeclContext());
const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext,
blockCount);
return loc::MemRegionVal(BD);
@@ -275,11 +292,17 @@
case Stmt::ImplicitCastExprClass: {
const CastExpr *CE = cast<CastExpr>(E);
- if (CE->getCastKind() == CK_ArrayToPointerDecay) {
- Optional<SVal> ArrayVal = getConstantVal(CE->getSubExpr());
- if (!ArrayVal)
+ switch (CE->getCastKind()) {
+ default:
+ break;
+ case CK_ArrayToPointerDecay:
+ case CK_BitCast: {
+ const Expr *SE = CE->getSubExpr();
+ Optional<SVal> Val = getConstantVal(SE);
+ if (!Val)
return None;
- return evalCast(*ArrayVal, CE->getType(), CE->getSubExpr()->getType());
+ return evalCast(*Val, CE->getType(), SE->getType());
+ }
}
// FALLTHROUGH
}
@@ -400,6 +423,45 @@
return true;
}
+// Handles casts of type CK_IntegralCast.
+// At the moment, this function will redirect to evalCast, except when the range
+// of the original value is known to be greater than the max of the target type.
+SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
+ QualType castTy, QualType originalTy) {
+
+ // No truncations if target type is big enough.
+ if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy))
+ return evalCast(val, castTy, originalTy);
+
+ const SymExpr *se = val.getAsSymbolicExpression();
+ if (!se) // Let evalCast handle non symbolic expressions.
+ return evalCast(val, castTy, originalTy);
+
+ // Find the maximum value of the target type.
+ APSIntType ToType(getContext().getTypeSize(castTy),
+ castTy->isUnsignedIntegerType());
+ llvm::APSInt ToTypeMax = ToType.getMaxValue();
+ NonLoc ToTypeMaxVal =
+ makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
+ : ToTypeMax.getSExtValue(),
+ castTy)
+ .castAs<NonLoc>();
+ // Check the range of the symbol being casted against the maximum value of the
+ // target type.
+ NonLoc FromVal = val.castAs<NonLoc>();
+ QualType CmpTy = getConditionType();
+ NonLoc CompVal =
+ evalBinOpNN(state, BO_LE, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>();
+ ProgramStateRef IsNotTruncated, IsTruncated;
+ std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal);
+ if (!IsNotTruncated && IsTruncated) {
+ // Symbol is truncated so we evaluate it as a cast.
+ NonLoc CastVal = makeNonLoc(se, originalTy, castTy);
+ return CastVal;
+ }
+ return evalCast(val, castTy, originalTy);
+}
+
// FIXME: should rewrite according to the cast kind.
SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
castTy = Context.getCanonicalType(castTy);
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 8de939f..dffee6c 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -51,7 +51,7 @@
const FunctionDecl *SVal::getAsFunctionDecl() const {
if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
- if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
+ if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
return FD;
}
@@ -240,7 +240,7 @@
void SVal::dumpToStream(raw_ostream &os) const {
switch (getBaseKind()) {
- case UnknownKind:
+ case UnknownValKind:
os << "Unknown";
break;
case NonLocKind:
@@ -249,7 +249,7 @@
case LocKind:
castAs<Loc>().dumpToStream(os);
break;
- case UndefinedKind:
+ case UndefinedValKind:
os << "Undefined";
break;
}
@@ -313,7 +313,7 @@
case loc::GotoLabelKind:
os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
break;
- case loc::MemRegionKind:
+ case loc::MemRegionValKind:
os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
break;
default:
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index a704ce2..72b852b 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -141,9 +141,9 @@
// unless this is a weak function or a symbolic region.
if (castTy->isBooleanType()) {
switch (val.getSubKind()) {
- case loc::MemRegionKind: {
+ case loc::MemRegionValKind: {
const MemRegion *R = val.castAs<loc::MemRegionVal>().getRegion();
- if (const FunctionTextRegion *FTR = dyn_cast<FunctionTextRegion>(R))
+ if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R))
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl()))
if (FD->isWeak())
// FIXME: Currently we are using an extent symbol here,
@@ -689,7 +689,7 @@
// completely unknowable.
return UnknownVal();
}
- case loc::MemRegionKind: {
+ case loc::MemRegionValKind: {
if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
@@ -718,7 +718,7 @@
// Get both values as regions, if possible.
const MemRegion *LeftMR = lhs.getAsRegion();
- assert(LeftMR && "MemRegionKind SVal doesn't have a region!");
+ assert(LeftMR && "MemRegionValKind SVal doesn't have a region!");
const MemRegion *RightMR = rhs.getAsRegion();
if (!RightMR)
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 7cdb55a..de29f0e 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -100,7 +100,7 @@
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
case MemRegion::CXXThisRegionKind:
- case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::CodeSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
case MemRegion::HeapSpaceRegionKind:
@@ -112,8 +112,8 @@
llvm_unreachable("Invalid region cast");
}
- case MemRegion::FunctionTextRegionKind:
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::FunctionCodeRegionKind:
+ case MemRegion::BlockCodeRegionKind:
case MemRegion::BlockDataRegionKind:
case MemRegion::StringRegionKind:
// FIXME: Need to handle arbitrary downcasts.
@@ -393,7 +393,7 @@
const MemRegion* BaseR = nullptr;
switch (BaseL.getSubKind()) {
- case loc::MemRegionKind:
+ case loc::MemRegionValKind:
BaseR = BaseL.castAs<loc::MemRegionVal>().getRegion();
break;
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index df4d22a..2dd252c 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -115,22 +115,22 @@
const SymExpr *SE = itr.pop_back_val();
switch (SE->getKind()) {
- case SymExpr::RegionValueKind:
- case SymExpr::ConjuredKind:
- case SymExpr::DerivedKind:
- case SymExpr::ExtentKind:
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolRegionValueKind:
+ case SymExpr::SymbolConjuredKind:
+ case SymExpr::SymbolDerivedKind:
+ case SymExpr::SymbolExtentKind:
+ case SymExpr::SymbolMetadataKind:
return;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
itr.push_back(cast<SymbolCast>(SE)->getOperand());
return;
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
itr.push_back(cast<SymIntExpr>(SE)->getLHS());
return;
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
itr.push_back(cast<IntSymExpr>(SE)->getRHS());
return;
- case SymExpr::SymSymKind: {
+ case SymExpr::SymSymExprKind: {
const SymSymExpr *x = cast<SymSymExpr>(SE);
itr.push_back(x->getLHS());
itr.push_back(x->getRHS());
@@ -391,6 +391,18 @@
void SymbolReaper::markLive(const MemRegion *region) {
RegionRoots.insert(region);
+ markElementIndicesLive(region);
+}
+
+void SymbolReaper::markElementIndicesLive(const MemRegion *region) {
+ for (auto SR = dyn_cast<SubRegion>(region); SR;
+ SR = dyn_cast<SubRegion>(SR->getSuperRegion())) {
+ if (auto ER = dyn_cast<ElementRegion>(SR)) {
+ SVal Idx = ER->getIndex();
+ for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI)
+ markLive(*SI);
+ }
+ }
}
void SymbolReaper::markInUse(SymbolRef sym) {
@@ -446,35 +458,35 @@
bool KnownLive;
switch (sym->getKind()) {
- case SymExpr::RegionValueKind:
+ case SymExpr::SymbolRegionValueKind:
KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
break;
- case SymExpr::ConjuredKind:
+ case SymExpr::SymbolConjuredKind:
KnownLive = false;
break;
- case SymExpr::DerivedKind:
+ case SymExpr::SymbolDerivedKind:
KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
break;
- case SymExpr::ExtentKind:
+ case SymExpr::SymbolExtentKind:
KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
break;
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolMetadataKind:
KnownLive = MetadataInUse.count(sym) &&
isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
if (KnownLive)
MetadataInUse.erase(sym);
break;
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
break;
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
break;
- case SymExpr::SymSymKind:
+ case SymExpr::SymSymExprKind:
KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
isLive(cast<SymSymExpr>(sym)->getRHS());
break;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
break;
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index ca92ffe..083ee51 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -14,7 +14,7 @@
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "ModelInjector.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DataRecursiveASTVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -141,7 +141,7 @@
namespace {
class AnalysisConsumer : public AnalysisASTConsumer,
- public DataRecursiveASTVisitor<AnalysisConsumer> {
+ public RecursiveASTVisitor<AnalysisConsumer> {
enum {
AM_None = 0,
AM_Syntax = 0x1,
@@ -274,7 +274,7 @@
llvm::errs() << ": " << Loc.getFilename();
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- llvm::errs() << ' ' << *ND << '\n';
+ llvm::errs() << ' ' << ND->getQualifiedNameAsString() << '\n';
}
else if (isa<BlockDecl>(D)) {
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
@@ -368,7 +368,11 @@
bool VisitBlockDecl(BlockDecl *BD) {
if (BD->hasBody()) {
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
- HandleCode(BD, RecVisitorMode);
+ // Since we skip function template definitions, we should skip blocks
+ // declared in those functions as well.
+ if (!BD->isDependentContext()) {
+ HandleCode(BD, RecVisitorMode);
+ }
}
return true;
}
@@ -492,10 +496,11 @@
(Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
// Add the visited callees to the global visited set.
- for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
- E = VisitedCallees.end(); I != E; ++I) {
- Visited.insert(*I);
- }
+ for (const Decl *Callee : VisitedCallees)
+ // Decls from CallGraph are already canonical. But Decls coming from
+ // CallExprs may be not. We should canonicalize them manually.
+ Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
+ : Callee->getCanonicalDecl());
VisitedAsTopLevel.insert(D);
}
}
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index d8269db..75fa4c6 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -83,10 +83,7 @@
// For now, none of the static analyzer API is considered stable.
// Versions must match exactly.
- if (strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0)
- return true;
-
- return false;
+ return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
}
void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags,
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index e6b9867..82f5601 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -116,8 +116,7 @@
cl::HideUnrelatedOptions(Category);
- Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
- argv));
+ Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv, Overview);
SourcePathList = SourcePaths;
if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
@@ -132,8 +131,12 @@
Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
ErrorMessage);
}
- if (!Compilations)
- llvm::report_fatal_error(ErrorMessage);
+ if (!Compilations) {
+ llvm::errs() << "Error while trying to load a compilation database:\n"
+ << ErrorMessage << "Running without flags.\n";
+ Compilations.reset(
+ new FixedCompilationDatabase(".", std::vector<std::string>()));
+ }
}
auto AdjustingCompilations =
llvm::make_unique<ArgumentsAdjustingCompilations>(
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
index 301c7b7..47bbdeb 100644
--- a/lib/Tooling/Core/Replacement.cpp
+++ b/lib/Tooling/Core/Replacement.cpp
@@ -143,34 +143,32 @@
ReplacementText);
}
-unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
- unsigned NewPosition = Position;
- for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
- ++I) {
- if (I->getOffset() >= Position)
- break;
- if (I->getOffset() + I->getLength() > Position)
- NewPosition += I->getOffset() + I->getLength() - Position;
- NewPosition += I->getReplacementText().size() - I->getLength();
+template <typename T>
+unsigned shiftedCodePositionInternal(const T &Replaces, unsigned Position) {
+ unsigned Offset = 0;
+ for (const auto& R : Replaces) {
+ if (R.getOffset() + R.getLength() <= Position) {
+ Offset += R.getReplacementText().size() - R.getLength();
+ continue;
+ }
+ if (R.getOffset() < Position &&
+ R.getOffset() + R.getReplacementText().size() <= Position) {
+ Position = R.getOffset() + R.getReplacementText().size() - 1;
+ }
+ break;
}
- return NewPosition;
+ return Position + Offset;
+}
+
+unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
+ return shiftedCodePositionInternal(Replaces, Position);
}
// FIXME: Remove this function when Replacements is implemented as std::vector
// instead of std::set.
unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
unsigned Position) {
- unsigned NewPosition = Position;
- for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->getOffset() >= Position)
- break;
- if (I->getOffset() + I->getLength() > Position)
- NewPosition += I->getOffset() + I->getLength() - Position;
- NewPosition += I->getReplacementText().size() - I->getLength();
- }
- return NewPosition;
+ return shiftedCodePositionInternal(Replaces, Position);
}
void deduplicate(std::vector<Replacement> &Replaces,
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index 1a015f0..4775b0d 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -47,14 +47,16 @@
# Find all variables that start with COMPILER_RT and populate a variable with
# them.
get_cmake_property(variableNames VARIABLES)
- foreach(varaibleName ${variableNames})
- if(${varaibleName} MATCHES "^COMPILER_RT")
+ foreach(variableName ${variableNames})
+ if(variableName MATCHES "^COMPILER_RT")
+ string(REPLACE ";" "\;" value "${${variableName}}")
list(APPEND COMPILER_RT_PASSTHROUGH_VARIABLES
- -D${varaibleName}=${${varaibleName}})
+ -D${variableName}=${value})
endif()
endforeach()
ExternalProject_Add(compiler-rt
+ DEPENDS llvm-config clang
PREFIX ${COMPILER_RT_PREFIX}
SOURCE_DIR ${COMPILER_RT_SRC_ROOT}
STAMP_DIR ${STAMP_DIR}
@@ -63,6 +65,7 @@
-DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
-DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
-DLLVM_CONFIG_PATH=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-config
-DCOMPILER_RT_OUTPUT_DIR=${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}
-DCOMPILER_RT_EXEC_OUTPUT_DIR=${LLVM_RUNTIME_OUTPUT_INTDIR}
@@ -85,8 +88,6 @@
WORKING_DIRECTORY ${BINARY_DIR}
)
- add_dependencies(compiler-rt-configure clang llvm-config)
-
install(CODE "execute_process\(COMMAND \${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=\${CMAKE_INSTALL_PREFIX} -P ${BINARY_DIR}/cmake_install.cmake \)"
COMPONENT compiler-rt)
@@ -110,7 +111,7 @@
if(LLVM_INCLUDE_TESTS)
# Add binaries that compiler-rt tests depend on.
set(COMPILER_RT_TEST_DEPENDENCIES
- FileCheck count not llvm-nm llvm-symbolizer)
+ FileCheck count not llvm-nm llvm-objdump llvm-symbolizer)
# Add top-level targets for various compiler-rt test suites.
set(COMPILER_RT_TEST_SUITES check-asan check-asan-dynamic check-dfsan
diff --git a/test/Analysis/DeallocMissingRelease.m b/test/Analysis/DeallocMissingRelease.m
new file mode 100644
index 0000000..3a2b556
--- /dev/null
+++ b/test/Analysis/DeallocMissingRelease.m
@@ -0,0 +1,192 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-runtime-has-weak %s 2>&1 | FileCheck -check-prefix=CHECK-ARC -allow-empty '--implicit-check-not=error:' '--implicit-check-not=warning:' %s
+
+#define nil ((id)0)
+
+#define NON_ARC !__has_feature(objc_arc)
+
+#if NON_ARC
+#define WEAK_ON_ARC
+#else
+#define WEAK_ON_ARC __weak
+#endif
+
+typedef signed char BOOL;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (Class)class;
+@end
+
+@interface NSObject <NSObject> {}
+- (void)dealloc;
+- (id)init;
+- (id)retain;
+- (oneway void)release;
+@end
+
+typedef struct objc_selector *SEL;
+
+//===------------------------------------------------------------------------===
+// Do not warn about missing release in -dealloc for ivars.
+
+@interface MyIvarClass1 : NSObject {
+ NSObject *_ivar;
+}
+@end
+
+@implementation MyIvarClass1
+- (instancetype)initWithIvar:(NSObject *)ivar
+{
+ self = [super init];
+ if (!self)
+ return nil;
+#if NON_ARC
+ _ivar = [ivar retain];
+#endif
+ return self;
+}
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+@interface MyIvarClass2 : NSObject {
+ NSObject *_ivar;
+}
+- (NSObject *)ivar;
+- (void)setIvar:(NSObject *)ivar;
+@end
+
+@implementation MyIvarClass2
+- (instancetype)init
+{
+ self = [super init];
+ return self;
+}
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+- (NSObject *)ivar
+{
+ return _ivar;
+}
+- (void)setIvar:(NSObject *)ivar
+{
+#if NON_ARC
+ [_ivar release];
+ _ivar = [ivar retain];
+#else
+ _ivar = ivar;
+#endif
+}
+@end
+
+//===------------------------------------------------------------------------===
+// Warn about missing release in -dealloc for properties.
+
+@interface MyPropertyClass1 : NSObject
+// CHECK: DeallocMissingRelease.m:[[@LINE+1]]:1: warning: The '_ivar' instance variable in 'MyPropertyClass1' was retained by a synthesized property but was not released in 'dealloc'
+@property (copy) NSObject *ivar;
+@end
+
+@implementation MyPropertyClass1
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+@interface MyPropertyClass2 : NSObject
+// CHECK: DeallocMissingRelease.m:[[@LINE+1]]:1: warning: The '_ivar' instance variable in 'MyPropertyClass2' was retained by a synthesized property but was not released in 'dealloc'
+@property (retain) NSObject *ivar;
+@end
+
+@implementation MyPropertyClass2
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+@interface MyPropertyClass3 : NSObject {
+ NSObject *_ivar;
+}
+@property (retain) NSObject *ivar;
+@end
+
+@implementation MyPropertyClass3
+// CHECK: DeallocMissingRelease.m:[[@LINE+1]]:1: warning: The '_ivar' instance variable in 'MyPropertyClass3' was retained by a synthesized property but was not released in 'dealloc'
+@synthesize ivar = _ivar;
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+@interface MyPropertyClass4 : NSObject {
+ void (^_blockPropertyIvar)(void);
+}
+@property (copy) void (^blockProperty)(void);
+@end
+
+@implementation MyPropertyClass4
+// CHECK: DeallocMissingRelease.m:[[@LINE+1]]:1: warning: The '_blockPropertyIvar' instance variable in 'MyPropertyClass4' was retained by a synthesized property but was not released in 'dealloc'
+@synthesize blockProperty = _blockPropertyIvar;
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+@interface MyPropertyClass5 : NSObject {
+ WEAK_ON_ARC NSObject *_ivar;
+}
+@property (weak) NSObject *ivar;
+@end
+
+@implementation MyPropertyClass5
+@synthesize ivar = _ivar; // no-warning
+- (void)dealloc
+{
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+
+//===------------------------------------------------------------------------===
+// <rdar://problem/6380411>: 'myproperty' has kind 'assign' and thus the
+// assignment through the setter does not perform a release.
+
+@interface MyObject : NSObject {
+ id __unsafe_unretained _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty=_myproperty; // no-warning
+- (void)dealloc {
+ // Don't claim that myproperty is released since it the property
+ // has the 'assign' attribute.
+ self.myproperty = 0; // no-warning
+#if NON_ARC
+ [super dealloc];
+#endif
+}
+@end
+// CHECK: 4 warnings generated.
diff --git a/test/Analysis/Inputs/qt-simulator.h b/test/Analysis/Inputs/qt-simulator.h
new file mode 100644
index 0000000..d1d6c03
--- /dev/null
+++ b/test/Analysis/Inputs/qt-simulator.h
@@ -0,0 +1,16 @@
+#pragma clang system_header
+
+struct QObject {
+};
+
+struct QEvent {
+ enum Type { None };
+ QEvent(Type) {}
+};
+
+struct QCoreApplication : public QObject {
+ static void postEvent(QObject *receiver, QEvent *event);
+ static QCoreApplication *instance();
+};
+
+struct QApplication : public QCoreApplication {};
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index 3586921..f9049c3 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -198,6 +198,25 @@
storage.assignExternal(new _CharT[4]);
}
};
+
+template<class _Engine, class _UIntType>
+class __independent_bits_engine {
+public:
+ // constructors and seeding functions
+ __independent_bits_engine(_Engine& __e, size_t __w);
+};
+
+template<class _Engine, class _UIntType>
+__independent_bits_engine<_Engine, _UIntType>
+ ::__independent_bits_engine(_Engine& __e, size_t __w)
+{
+ // Fake error trigger.
+ // No warning is expected as we are suppressing warning coming
+ // out of std::basic_string.
+ int z = 0;
+ z = 5/z;
+}
+
}
void* operator new(std::size_t, const std::nothrow_t&) throw();
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
index b465959..d6af44b 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc %s -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck -check-prefix=CHECK-ARC -allow-empty '--implicit-check-not=error:' '--implicit-check-not=warning:' %s
+
typedef signed char BOOL;
@protocol NSObject
- (BOOL)isEqual:(id)object;
@@ -13,23 +14,74 @@
typedef struct objc_selector *SEL;
-// <rdar://problem/6380411>: 'myproperty' has kind 'assign' and thus the
-// assignment through the setter does not perform a release.
+//===------------------------------------------------------------------------===
+// Do not warn about missing -dealloc method. Not enough context to know
+// whether the ivar is retained or not.
-@interface MyObject : NSObject {
- id _myproperty;
-}
-@property(assign) id myproperty;
-@end
-
-@implementation MyObject
-@synthesize myproperty=_myproperty; // no-warning
-- (void)dealloc {
- self.myproperty = 0;
- [super dealloc];
+@interface MissingDeallocWithIvar : NSObject {
+ NSObject *_ivar;
}
@end
+@implementation MissingDeallocWithIvar
+@end
+
+//===------------------------------------------------------------------------===
+// Do not warn about missing -dealloc method. These properties are not
+// retained or synthesized.
+
+@interface MissingDeallocWithIntProperty : NSObject
+@property (assign) int ivar;
+@end
+
+@implementation MissingDeallocWithIntProperty
+@end
+
+@interface MissingDeallocWithSELProperty : NSObject
+@property (assign) SEL ivar;
+@end
+
+@implementation MissingDeallocWithSELProperty
+@end
+
+//===------------------------------------------------------------------------===
+// Warn about missing -dealloc method.
+
+@interface MissingDeallocWithCopyProperty : NSObject
+@property (copy) NSObject *ivar;
+@end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithCopyProperty' lacks a 'dealloc' instance method
+@implementation MissingDeallocWithCopyProperty
+@end
+
+@interface MissingDeallocWithRetainProperty : NSObject
+@property (retain) NSObject *ivar;
+@end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithRetainProperty' lacks a 'dealloc' instance method
+@implementation MissingDeallocWithRetainProperty
+@end
+
+@interface MissingDeallocWithIVarAndRetainProperty : NSObject {
+ NSObject *_ivar2;
+}
+@property (retain) NSObject *ivar1;
+@end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithIVarAndRetainProperty' lacks a 'dealloc' instance method
+@implementation MissingDeallocWithIVarAndRetainProperty
+@end
+
+@interface MissingDeallocWithReadOnlyRetainedProperty : NSObject
+@property (readonly,retain) NSObject *ivar;
+@end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithReadOnlyRetainedProperty' lacks a 'dealloc' instance method
+@implementation MissingDeallocWithReadOnlyRetainedProperty
+@end
+
+
//===------------------------------------------------------------------------===
// Don't warn about iVars that are selectors.
@@ -65,27 +117,6 @@
@end
//===------------------------------------------------------------------------===
-// <rdar://problem/6380411>
-// Was bogus warning: "The '_myproperty' instance variable was not retained by a
-// synthesized property but was released in 'dealloc'"
-
-@interface MyObject_rdar6380411 : NSObject {
- id _myproperty;
-}
-@property(assign) id myproperty;
-@end
-
-@implementation MyObject_rdar6380411
-@synthesize myproperty=_myproperty;
-- (void)dealloc {
- // Don't claim that myproperty is released since it the property
- // has the 'assign' attribute.
- self.myproperty = 0; // no-warning
- [super dealloc];
-}
-@end
-
-//===------------------------------------------------------------------------===
// PR 3187: http://llvm.org/bugs/show_bug.cgi?id=3187
// - Disable the missing -dealloc check for classes that subclass SenTestCase
@@ -112,3 +143,4 @@
// do something which uses resourcepath
}
@end
+// CHECK: 4 warnings generated.
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index d04b331..c868459 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -155,13 +155,12 @@
}
void testNilArgNSMutableDictionary5(NSMutableDictionary *d, NSString* key) {
- d[key] = 0; // expected-warning {{Value stored into 'NSMutableDictionary' cannot be nil}}
+ d[key] = 0; // no-warning - removing the mapping for the given key
}
void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) {
if (key)
;
d[key] = 0; // expected-warning {{'NSMutableDictionary' key cannot be nil}}
- // expected-warning@-1 {{Value stored into 'NSMutableDictionary' cannot be nil}}
}
NSDictionary *testNilArgNSDictionary1(NSString* key) {
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index 9b7011e..5ed92df 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -131,3 +131,15 @@
int *p = 0;
*p = 0xDEADBEEF; // no-warning
}
+#undef assert
+
+// Test that hard-coded Android __assert2 name is recognized as a noreturn
+#define assert(_Expression) ((_Expression) ? (void)0 : __assert2(0, 0, 0, 0));
+extern void __assert2(const char *, int, const char *, const char *);
+extern void _wassert(const char * _Message, const char *_File, unsigned _Line);
+void test___assert2() {
+ assert(0);
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+#undef assert
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index 8f76120..6d5a6df 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -14,6 +14,7 @@
id _Y;
id _Z;
id _K;
+ id _L;
id _N;
id _M;
id _V;
@@ -23,6 +24,7 @@
@property(retain) id Y;
@property(assign) id Z;
@property(assign) id K;
+@property(weak) id L;
@property(readonly) id N;
@property(retain) id M;
@property(retain) id V;
@@ -33,13 +35,14 @@
@implementation MyClass
@synthesize X = _X;
-@synthesize Y = _Y; // expected-warning{{The '_Y' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
-@synthesize Z = _Z; // expected-warning{{The '_Z' instance variable was not retained by a synthesized property but was released in 'dealloc'}}
+@synthesize Y = _Y; // expected-warning{{The '_Y' instance variable in 'MyClass' was retained by a synthesized property but was not released in 'dealloc'}}
+@synthesize Z = _Z; // expected-warning{{The '_Z' instance variable in 'MyClass' was not retained by a synthesized property but was released in 'dealloc'}}
@synthesize K = _K;
-@synthesize N = _N;
+@synthesize L = _L; // no-warning
+@synthesize N = _N; // expected-warning{{The '_N' instance variable in 'MyClass' was not retained by a synthesized property but was released in 'dealloc'}}
@synthesize M = _M;
@synthesize V = _V;
-@synthesize W = _W; // expected-warning{{The '_W' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
+@synthesize W = _W; // expected-warning{{The '_W' instance variable in 'MyClass' was retained by a synthesized property but was not released in 'dealloc'}}
-(id) O{ return 0; }
-(void) setO:(id)arg { }
diff --git a/test/Analysis/analyze_display_progress.cpp b/test/Analysis/analyze_display_progress.cpp
new file mode 100644
index 0000000..c84ab63
--- /dev/null
+++ b/test/Analysis/analyze_display_progress.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s
+
+void f() {};
+void g() {};
+void h() {}
+
+struct SomeStruct {
+ void f() {}
+};
+
+struct SomeOtherStruct {
+ void f() {}
+};
+
+namespace ns {
+ struct SomeStruct {
+ void f() {}
+ };
+}
+
+// CHECK: analyze_display_progress.cpp f
+// CHECK: analyze_display_progress.cpp g
+// CHECK: analyze_display_progress.cpp h
+// CHECK: analyze_display_progress.cpp SomeStruct::f
+// CHECK: analyze_display_progress.cpp SomeOtherStruct::f
+// CHECK: analyze_display_progress.cpp ns::SomeStruct::f
diff --git a/test/Analysis/blocks.mm b/test/Analysis/blocks.mm
new file mode 100644
index 0000000..5f93888
--- /dev/null
+++ b/test/Analysis/blocks.mm
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -fblocks -analyzer-opt-analyze-nested-blocks %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// expected-no-diagnostics
+
+void testBlockWithoutCopyExpression(int i) {
+ // Captures i, with no copy expression.
+ (void)(^void() {
+ (void)i;
+ });
+}
+
+// CHECK-LABEL:void testBlockWithoutCopyExpression(int i)
+// CHECK-NEXT: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ^{ }
+// CHECK-NEXT: 2: (void)([B1.1]) (CStyleCastExpr, ToVoid, void)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+
+struct StructWithCopyConstructor {
+ StructWithCopyConstructor(int i);
+ StructWithCopyConstructor(const StructWithCopyConstructor &s);
+};
+void testBlockWithCopyExpression(StructWithCopyConstructor s) {
+ // Captures s, with a copy expression calling the copy constructor for StructWithCopyConstructor.
+ (void)(^void() {
+ (void)s;
+ });
+}
+
+// CHECK-LABEL:void testBlockWithCopyExpression(StructWithCopyConstructor s)
+// CHECK-NEXT: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: s
+// CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, const struct StructWithCopyConstructor)
+// CHECK-NEXT: 3: ^{ }
+// CHECK-NEXT: 4: (void)([B1.3]) (CStyleCastExpr, ToVoid, void)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+
+void testBlockWithCaptureByReference() {
+ __block StructWithCopyConstructor s(5);
+ // Captures s by reference, so no copy expression.
+ (void)(^void() {
+ (void)s;
+ });
+}
+
+// CHECK-LABEL:void testBlockWithCaptureByReference()
+// CHECK-NEXT: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: 5
+// CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, struct StructWithCopyConstructor)
+// CHECK-NEXT: 3: StructWithCopyConstructor s(5) __attribute__((blocks("byref")));
+// CHECK-NEXT: 4: ^{ }
+// CHECK-NEXT: 5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
diff --git a/test/Analysis/bool-assignment.c b/test/Analysis/bool-assignment.c
index 0f782fb..285569e 100644
--- a/test/Analysis/bool-assignment.c
+++ b/test/Analysis/bool-assignment.c
@@ -42,6 +42,15 @@
BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
return;
}
+ if (y > 200 && y < 250) {
+ // FIXME: Currently we are loosing this warning due to a SymbolCast in RHS.
+ BOOL x = y; // no-warning
+ return;
+ }
+ if (y >= 127 && y < 150) {
+ BOOL x = y; // expected-warning{{Assignment of a non-Boolean value}}
+ return;
+ }
if (y > 1) {
BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
return;
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index 4b46004..b73528e 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -288,17 +288,17 @@
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$namespaceAA{$debug</string>
+// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$namespaceAA{$debug</string>
+// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int f()$28$namespaceAA{$debug</string>
+// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
// CHECK-NEXT: <key>category</key><string>debug</string>
// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f8ee38da3de42e209c4afa886b5531ab</string>
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f5471f52854dc14167fe96db50c4ba5f</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 2027ee6..78cba16 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
//===----------------------------------------------------------------------===//
// Basic dead store checking (but in C++ mode).
@@ -174,6 +174,20 @@
return radar13213575_testit<true>(5) + radar13213575_testit<false>(3);
}
+template <class T>
+void test_block_in_dependent_context(typename T::some_t someArray) {
+ ^{
+ int i = someArray[0]; // no-warning
+ }();
+}
+
+void test_block_in_non_dependent_context(int *someArray) {
+ ^{
+ int i = someArray[0]; // expected-warning {{Value stored to 'i' during its initialization is never read}}
+ }();
+}
+
+
//===----------------------------------------------------------------------===//
// Dead store checking involving lambdas.
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/diagnostics/report-issues-within-main-file.cpp b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
index cb99896..5fd7abd 100644
--- a/test/Analysis/diagnostics/report-issues-within-main-file.cpp
+++ b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
@@ -949,7 +949,7 @@
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f21ac032efaa3d1459a5ed31f0ad44f0</string>
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f689fbd54138491e228f0f89bb02bfb2</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>mainPlusHeader</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>2</string>
diff --git a/test/Analysis/explain-svals.cpp b/test/Analysis/explain-svals.cpp
new file mode 100644
index 0000000..c0ed749
--- /dev/null
+++ b/test/Analysis/explain-svals.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s
+
+typedef unsigned long size_t;
+
+struct S {
+ struct S3 {
+ int y[10];
+ };
+ struct S2 : S3 {
+ int *x;
+ } s2[10];
+ int z;
+};
+
+
+void clang_analyzer_explain(int);
+void clang_analyzer_explain(void *);
+void clang_analyzer_explain(S);
+
+size_t clang_analyzer_getExtent(void *);
+
+size_t strlen(const char *);
+
+int conjure();
+S conjure_S();
+
+int glob;
+static int stat_glob;
+void *glob_ptr;
+
+// Test strings are regex'ed because we need to match exact string
+// rather than a substring.
+
+void test_1(int param, void *ptr) {
+ clang_analyzer_explain(&glob); // expected-warning-re{{{{^pointer to global variable 'glob'$}}}}
+ clang_analyzer_explain(param); // expected-warning-re{{{{^argument 'param'$}}}}
+ clang_analyzer_explain(ptr); // expected-warning-re{{{{^argument 'ptr'$}}}}
+ if (param == 42)
+ clang_analyzer_explain(param); // expected-warning-re{{{{^signed 32-bit integer '42'$}}}}
+}
+
+void test_2(char *ptr, int ext) {
+ clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}}
+ clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}}
+ clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}}
+ clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}}
+ clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}}
+ clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}}
+ int *x = new int[ext];
+ clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of pointee of symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}}
+ // Sic! What gets computed is the extent of the element-region.
+ clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^signed 32-bit integer '4'$}}}}
+ delete[] x;
+}
+
+void test_3(S s) {
+ clang_analyzer_explain(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
+ clang_analyzer_explain(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
+ clang_analyzer_explain(&s.s2[5].y[3]); // expected-warning-re{{{{^pointer to element of type 'int' with index 3 of field 'y' of base object 'S::S3' inside element of type 'struct S::S2' with index 5 of field 's2' of parameter 's'$}}}}
+ if (!s.s2[7].x) {
+ clang_analyzer_explain(s.s2[7].x); // expected-warning-re{{{{^concrete memory address '0'$}}}}
+ // FIXME: we need to be explaining '1' rather than '0' here; not explainer bug.
+ clang_analyzer_explain(s.s2[7].x + 1); // expected-warning-re{{{{^concrete memory address '0'$}}}}
+ }
+}
+
+void test_4(int x, int y) {
+ int z;
+ static int stat;
+ clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}}
+ clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}}
+ clang_analyzer_explain(x + y); // expected-warning-re{{{{^unknown value$}}}}
+ clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}}
+ clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}}
+ clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}}
+ clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}}
+ clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}}
+ clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}}
+ clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of compound literal \(int \[3\]\)\{1, 2, 3\}$}}}}
+}
+
+namespace {
+class C {
+ int x[10];
+
+public:
+ void test_5(int i) {
+ clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}}
+ clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}}
+ clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}}
+ }
+};
+} // end of anonymous namespace
+
+void test_6() {
+ clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+ clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'struct S' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+}
diff --git a/test/Analysis/index-type.c b/test/Analysis/index-type.c
new file mode 100644
index 0000000..fc638df
--- /dev/null
+++ b/test/Analysis/index-type.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2 -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2 -DM32 -verify %s
+// expected-no-diagnostics
+
+#define UINT_MAX (~0u)
+
+#ifdef M32
+
+#define X86_ARRAY_SIZE (UINT_MAX/2 + 4)
+
+void testIndexTooBig() {
+ char arr[X86_ARRAY_SIZE];
+ char *ptr = arr + UINT_MAX/2;
+ ptr += 2; // index shouldn't overflow
+ *ptr = 42; // no-warning
+}
+
+#else // 64-bit tests
+
+#define ARRAY_SIZE 0x100000000
+
+void testIndexOverflow64() {
+ char arr[ARRAY_SIZE];
+ char *ptr = arr + UINT_MAX/2;
+ ptr += 2; // don't overflow 64-bit index
+ *ptr = 42; // no-warning
+}
+
+#define ULONG_MAX (~0ul)
+#define BIG_INDEX (ULONG_MAX/16)
+
+void testIndexTooBig64() {
+ char arr[ULONG_MAX/8-1];
+ char *ptr = arr + BIG_INDEX;
+ ptr += 2; // don't overflow 64-bit index
+ *ptr = 42; // no-warning
+}
+
+#endif
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index a71e35d..b31c315 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -143,3 +143,57 @@
clang_analyzer_eval(w.p[1] == 'y'); // expected-warning{{TRUE}}
}
}
+
+namespace ReferenceInitialization {
+ struct OtherStruct {
+ OtherStruct(int i);
+ ~OtherStruct();
+ };
+
+ struct MyStruct {
+ MyStruct(int i);
+ MyStruct(OtherStruct os);
+
+ void method() const;
+ };
+
+ void referenceInitializeLocal() {
+ const MyStruct &myStruct(5);
+ myStruct.method(); // no-warning
+ }
+
+ void referenceInitializeMultipleLocals() {
+ const MyStruct &myStruct1(5), myStruct2(5), &myStruct3(5);
+ myStruct1.method(); // no-warning
+ myStruct2.method(); // no-warning
+ myStruct3.method(); // no-warning
+ }
+
+ void referenceInitializeLocalWithCleanup() {
+ const MyStruct &myStruct(OtherStruct(5));
+ myStruct.method(); // no-warning
+ }
+
+ struct HasMyStruct {
+ const MyStruct &ms; // expected-note {{reference member declared here}}
+ const MyStruct &msWithCleanups; // expected-note {{reference member declared here}}
+
+ // clang's Sema issues a warning when binding a reference member to a
+ // temporary value.
+ HasMyStruct() : ms(5), msWithCleanups(OtherStruct(5)) {
+ // expected-warning@-1 {{binding reference member 'ms' to a temporary value}}
+ // expected-warning@-2 {{binding reference member 'msWithCleanups' to a temporary value}}
+
+ // At this point the members are not garbage so we should not expect an
+ // analyzer warning here even though binding a reference member
+ // to a member is a terrible idea.
+ ms.method(); // no-warning
+ msWithCleanups.method(); // no-warning
+ }
+ };
+
+ void referenceInitializeField() {
+ HasMyStruct hms;
+ }
+
+};
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 183df16..b7962b5 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -275,7 +275,7 @@
clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}}
clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}}
-}
+ }
double defaultFloatReference(const double &i = 42) {
return -i;
@@ -300,6 +300,13 @@
clang_analyzer_eval(defaultString("xyz") == 'y'); // expected-warning{{TRUE}}
clang_analyzer_eval(defaultString() == 'b'); // expected-warning{{TRUE}}
}
+
+ const void * const void_string = "abc";
+
+ void testBitcastedString() {
+ clang_analyzer_eval(0 != void_string); // expected-warning{{TRUE}}
+ clang_analyzer_eval('b' == ((char *)void_string)[1]); // expected-warning{{TRUE}}
+ }
}
namespace OperatorNew {
diff --git a/test/Analysis/inlining/analysis-order.c b/test/Analysis/inlining/analysis-order.c
new file mode 100644
index 0000000..5149818
--- /dev/null
+++ b/test/Analysis/inlining/analysis-order.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin.NoReturnFunctions -analyzer-display-progress %s 2>&1 | FileCheck %s
+
+// Do not analyze test1() again because it was inlined
+void test1();
+
+void test2() {
+ test1();
+}
+
+void test1() {
+}
+
+// CHECK: analysis-order.c test2
+// CHECK-NEXT: analysis-order.c test1
+// CHECK-NEXT: analysis-order.c test2
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
index e1c8f67..a0bc361 100644
--- a/test/Analysis/inlining/false-positive-suppression.c
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
int opaquePropertyCheck(void *object);
int coin();
@@ -93,6 +93,84 @@
return 5/y; // expected-warning {{Division by zero}}
}
+// Treat a function-like macro similarly to an inlined function, so suppress
+// warnings along paths resulting from inlined checks.
+#define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17)
+void testInlineCheckInMacro(int *p) {
+ int i = MACRO_WITH_CHECK(p);
+ (void)i;
+
+ *p = 1; // no-warning
+}
+
+#define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } )
+void testInlineCheckInNestedMacro(int *p) {
+ int i = MACRO_WITH_NESTED_CHECK(p);
+ (void)i;
+
+ *p = 1; // no-warning
+}
+
+// If there is a check in a macro that is not function-like, don't treat
+// it like a function so don't suppress.
+#define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17)
+void testNonFunctionMacro(int *p) {
+ int i = NON_FUNCTION_MACRO_WITH_CHECK ;
+ (void)i;
+
+ *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+
+// This macro will dereference its argument if the argument is NULL.
+#define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a)
+void testErrorInMacro(int *p) {
+ int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+ (void)i;
+}
+
+// Here the check (the "if") is not in a macro, so we should still warn.
+#define MACRO_IN_GUARD(a) (!(a))
+void testMacroUsedAsGuard(int *p) {
+ if (MACRO_IN_GUARD(p))
+ *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+// When a nil case split is introduced in a macro and the macro is in a guard,
+// we still shouldn't warn.
+int isNull(int *p);
+int isEqual(int *p, int *q);
+#define ISNULL(ptr) ((ptr) == 0 || isNull(ptr))
+#define ISEQUAL(a, b) ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b))
+#define ISNOTEQUAL(a, b) (!ISEQUAL(a, b))
+void testNestedDisjunctiveMacro(int *p, int *q) {
+ if (ISNOTEQUAL(p,q)) {
+ *p = 1; // no-warning
+ *q = 1; // no-warning
+ }
+
+ *p = 1; // no-warning
+ *q = 1; // no-warning
+}
+
+void testNestedDisjunctiveMacro2(int *p, int *q) {
+ if (ISEQUAL(p,q)) {
+ return;
+ }
+
+ *p = 1; // no-warning
+ *q = 1; // no-warning
+}
+
+
+// Here the check is entirely in non-macro code even though the code itself
+// is a macro argument.
+#define MACRO_DO_IT(a) (a)
+void testErrorInArgument(int *p) {
+ int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c
+ (void)i;
+}
+
// --------------------------
// "Suppression suppression"
// --------------------------
diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
index 711c30f..2a8520f 100644
--- a/test/Analysis/inlining/stl.cpp
+++ b/test/Analysis/inlining/stl.cpp
@@ -47,3 +47,8 @@
const std::basic_string<char32_t> &v2) {
v = v2;
}
+
+class MyEngine;
+void testSupprerssion_independent_bits_engine(MyEngine& e) {
+ std::__independent_bits_engine<MyEngine, unsigned int> x(e, 64); // no-warning
+}
diff --git a/test/Analysis/lambdas-generalized-capture.cpp b/test/Analysis/lambdas-generalized-capture.cpp
new file mode 100644
index 0000000..790e15e
--- /dev/null
+++ b/test/Analysis/lambdas-generalized-capture.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
+
+int clang_analyzer_eval(int);
+
+void generalizedCapture() {
+ int v = 7;
+ auto lambda = [x=v]() {
+ return x;
+ };
+
+ int result = lambda();
+ clang_analyzer_eval(result == 7); // expected-warning {{TRUE}}
+}
+
+void sideEffectsInGeneralizedCapture() {
+ int v = 7;
+ auto lambda = [x=v++]() {
+ return x;
+ };
+ clang_analyzer_eval(v == 8); // expected-warning {{TRUE}}
+
+ int r1 = lambda();
+ int r2 = lambda();
+ clang_analyzer_eval(r1 == 7); // expected-warning {{TRUE}}
+ clang_analyzer_eval(r2 == 7); // expected-warning {{TRUE}}
+ clang_analyzer_eval(v == 8); // expected-warning {{TRUE}}
+}
+
+int addOne(int p) {
+ return p + 1;
+}
+
+void inliningInGeneralizedCapture() {
+ int v = 7;
+ auto lambda = [x=addOne(v)]() {
+ return x;
+ };
+
+ int result = lambda();
+ clang_analyzer_eval(result == 8); // expected-warning {{TRUE}}
+}
+
+void caseSplitInGeneralizedCapture(bool p) {
+ auto lambda = [x=(p ? 1 : 2)]() {
+ return x;
+ };
+
+ int result = lambda();
+ clang_analyzer_eval(result == 1); // expected-warning {{FALSE}} expected-warning {{TRUE}}
+}
diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp
index 10f6d55..0b66e6b 100644
--- a/test/Analysis/lambdas.cpp
+++ b/test/Analysis/lambdas.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
@@ -90,6 +90,17 @@
clang_analyzer_eval(b == 8); // expected-warning{{TRUE}}
}
+void testAliasingBetweenParameterAndCapture() {
+ int i = 5;
+
+ auto l = [&i](int &p) {
+ i++;
+ p++;
+ };
+ l(i);
+ clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+}
+
// Nested lambdas.
void testNestedLambdas() {
@@ -162,6 +173,19 @@
clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
}
+// Captured variable-length array.
+
+void testVariableLengthArrayCaptured() {
+ int n = 2;
+ int array[n];
+ array[0] = 7;
+
+ int i = [&]{
+ return array[0];
+ }();
+
+ clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+}
// Test inline defensive checks
int getNum();
@@ -210,6 +234,110 @@
}();
}
+void captureReferenceByCopy(int &p) {
+ int v = 7;
+ p = 8;
+
+ // p is a reference captured by copy
+ [&v,p]() mutable {
+ v = p;
+ p = 22;
+ }();
+
+ clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
+}
+
+void captureReferenceByReference(int &p) {
+ int v = 7;
+ p = 8;
+
+ // p is a reference captured by reference
+ [&v,&p]() {
+ v = p;
+ p = 22;
+ }();
+
+ clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p == 22); // expected-warning{{TRUE}}
+}
+
+void callMutableLambdaMultipleTimes(int &p) {
+ int v = 0;
+ p = 8;
+
+ auto l = [&v, p]() mutable {
+ v = p;
+ p++;
+ };
+
+ l();
+
+ clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
+
+ l();
+
+ clang_analyzer_eval(v == 9); // expected-warning{{TRUE}}
+ clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
+}
+
+// PR 24914
+struct StructPR24914{
+ int x;
+};
+
+void takesConstStructArgument(const StructPR24914&);
+void captureStructReference(const StructPR24914& s) {
+ [s]() {
+ takesConstStructArgument(s);
+ }();
+}
+
+// Lambda capture counts as use for dead-store checking.
+
+int returnsValue();
+
+void captureByCopyCausesUse() {
+ int local1 = returnsValue(); // no-warning
+ int local2 = returnsValue(); // no-warning
+ int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
+
+ (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
+
+ int local4 = returnsValue(); // no-warning
+ int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
+
+ (void)[=]() {
+ (void)local4; // Implicit capture by copy counts as use
+ };
+}
+
+void captureByReference() {
+ int local1 = returnsValue(); // no-warning
+
+ auto lambda1 = [&local1]() { // Explicit capture by reference
+ local1++;
+ };
+
+ // Don't treat as a dead store because local1 was was captured by reference.
+ local1 = 7; // no-warning
+
+ lambda1();
+
+ int local2 = returnsValue(); // no-warning
+
+ auto lambda2 = [&]() {
+ local2++; // Implicit capture by reference
+ };
+
+ // Don't treat as a dead store because local2 was was captured by reference.
+ local2 = 7; // no-warning
+
+ lambda2();
+}
+
+
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
diff --git a/test/Analysis/lambdas.mm b/test/Analysis/lambdas.mm
new file mode 100644
index 0000000..6247f28
--- /dev/null
+++ b/test/Analysis/lambdas.mm
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fblocks -Wno-objc-root-class -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+
+int clang_analyzer_eval(int);
+
+@interface Super
+- (void)superMethod;
+@end
+
+@interface Sub : Super {
+ int _ivar1;
+ int _ivar2;
+}
+@end
+
+
+@implementation Sub
+- (void)callMethodOnSuperInCXXLambda; {
+ // Explicit capture.
+ [self]() {
+ [super superMethod];
+ }();
+
+ // Implicit capture.
+ [=]() {
+ [super superMethod];
+ }();
+}
+
+- (void)swapIvars {
+ int tmp = _ivar1;
+ _ivar1 = _ivar2;
+ _ivar2 = tmp;
+}
+
+- (void)callMethodOnSelfInCXXLambda; {
+ _ivar1 = 7;
+ _ivar2 = 8;
+ [self]() {
+ [self swapIvars];
+ }();
+
+ clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
+ clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
+}
+
+@end
+
+int getValue();
+void useValue(int v);
+
+void castToBlockNoDeadStore() {
+ int v = getValue(); // no-warning
+
+ (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above.
+ };
+}
+
+void takesBlock(void(^block)());
+
+void passToFunctionTakingBlockNoDeadStore() {
+ int v = 7; // no-warning
+ int x = 8; // no-warning
+ takesBlock([&v, x]() {
+ (void)v;
+ });
+}
+
+void castToBlockAndInline() {
+ int result = ((int(^)(int))[](int p) {
+ return p;
+ })(7);
+
+ clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
+}
+
+void castToBlockWithCaptureAndInline() {
+ int y = 7;
+
+ auto lambda = [y]{ return y; };
+ int(^block)() = lambda;
+
+ int result = block();
+ clang_analyzer_eval(result == 7); // expected-warning{{TRUE}}
+}
+
+void castMutableLambdaToBlock() {
+ int x = 0;
+
+ auto lambda = [x]() mutable {
+ x = x + 1;
+ return x;
+ };
+
+ // The block should copy the lambda before capturing.
+ int(^block)() = lambda;
+
+ int r1 = block();
+ clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}}
+
+ int r2 = block();
+ clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}}
+
+ // Because block copied the lambda, r3 should be 1.
+ int r3 = lambda();
+ clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}}
+
+ // Aliasing the block shouldn't copy the lambda.
+ int(^blockAlias)() = block;
+
+ int r4 = blockAlias();
+ clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}}
+
+ int r5 = block();
+ clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}}
+
+ // Another copy of lambda
+ int(^blockSecondCopy)() = lambda;
+ int r6 = blockSecondCopy();
+ clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}}
+}
+
+void castLambdaInLocalBlock() {
+ // Make sure we don't emit a spurious diagnostic about the address of a block
+ // escaping in the implicit conversion operator method for lambda-to-block
+ // conversions.
+ auto lambda = []{ }; // no-warning
+
+ void(^block)() = lambda;
+ (void)block;
+}
diff --git a/test/Analysis/localization.m b/test/Analysis/localization.m
index ce55609..cf0697c 100644
--- a/test/Analysis/localization.m
+++ b/test/Analysis/localization.m
@@ -90,6 +90,13 @@
[testLabel setText:bar]; // no-warning
}
+
+// Suppress diagnostic about user-facing string constants when the method name
+// contains the term "Debug".
+- (void)debugScreen:(UILabel *)label {
+ label.text = @"Unlocalized";
+}
+
// Plural Misuse Checker Tests
// These tests are modeled off incorrect uses of the many-one pattern
// from real projects.
@@ -205,3 +212,15 @@
// }
@end
+
+
+// Suppress diagnostic about user-facing string constants when the class name
+// contains "Debug"
+@interface MyDebugView : NSObject
+@end
+
+@implementation MyDebugView
+- (void)setupScreen:(UILabel *)label {
+ label.text = @"Unlocalized";
+}
+@end
diff --git a/test/Analysis/no-unreachable-dtors.cpp b/test/Analysis/no-unreachable-dtors.cpp
new file mode 100644
index 0000000..e0893b3
--- /dev/null
+++ b/test/Analysis/no-unreachable-dtors.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.Stats -verify -Wno-unreachable-code %s
+
+struct S {
+ ~S();
+};
+
+// the return at the end of an CompoundStmt does not lead to an unreachable block containing the dtors
+void test() { // expected-warning-re{{test -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: no | Empty WorkList: yes}}
+ S s;
+ return;
+}
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 240e8ed..79b3b3a 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -311,3 +311,21 @@
return *p; // no-warning
return 0;
}
+
+#define AS_ATTRIBUTE volatile __attribute__((address_space(256)))
+#define _get_base() ((void * AS_ATTRIBUTE *)0)
+void* test_address_space_array(unsigned long slot) {
+ return _get_base()[slot]; // no-warning
+}
+void test_address_space_condition(int AS_ATTRIBUTE *cpu_data) {
+ if (cpu_data == 0) {
+ *cpu_data = 3; // no-warning
+ }
+}
+struct X { int member; };
+int test_address_space_member() {
+ struct X AS_ATTRIBUTE *data = (struct X AS_ATTRIBUTE *)0UL;
+ int ret;
+ ret = data->member; // no-warning
+ return ret;
+}
diff --git a/test/Analysis/nullability-no-arc.mm b/test/Analysis/nullability-no-arc.mm
new file mode 100644
index 0000000..c0e693e
--- /dev/null
+++ b/test/Analysis/nullability-no-arc.mm
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
+
+#define nil 0
+
+@protocol NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+__attribute__((objc_root_class))
+@interface
+NSObject<NSObject>
+@end
+
+@interface TestObject : NSObject
+@end
+
+TestObject * _Nonnull returnsNilObjCInstanceIndirectly() {
+ TestObject *local = 0;
+ return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceIndirectlyWithSupressingCast() {
+ TestObject *local = 0;
+ return (TestObject * _Nonnull)local; // no-warning
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectly() {
+ // The first warning is from Sema. The second is from the static analyzer.
+ return nil; // expected-warning {{null returned from function that requires a non-null return value}}
+ // expected-warning@-1 {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectlyWithSuppressingCast() {
+ return (TestObject * _Nonnull)nil; // no-warning
+}
+
+void testObjCNonARCNoInitialization(TestObject * _Nonnull p) {
+ TestObject * _Nonnull implicitlyZeroInitialized; // no-warning
+ implicitlyZeroInitialized = p;
+}
+
+void testObjCNonARCExplicitZeroInitialization() {
+ TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
+}
diff --git a/test/Analysis/nullability.mm b/test/Analysis/nullability.mm
index 14cfb67..220a381 100644
--- a/test/Analysis/nullability.mm
+++ b/test/Analysis/nullability.mm
@@ -1,16 +1,29 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -verify %s
#define nil 0
#define BOOL int
+#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
+
+typedef struct _NSZone NSZone;
+
@protocol NSObject
+ (id)alloc;
- (id)init;
@end
+NS_ASSUME_NONNULL_BEGIN
@protocol NSCopying
+- (id)copyWithZone:(nullable NSZone *)zone;
+
@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(nullable NSZone *)zone;
+@end
+NS_ASSUME_NONNULL_END
+
__attribute__((objc_root_class))
@interface
NSObject<NSObject>
@@ -58,16 +71,16 @@
// Make every dereference a different path to avoid sinks after errors.
switch (getRandom()) {
case 0: {
- Dummy &r = *p; // expected-warning {{}}
+ Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
} break;
case 1: {
- int b = p->val; // expected-warning {{}}
+ int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
} break;
case 2: {
- int stuff = *ptr; // expected-warning {{}}
+ int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
} break;
case 3:
- takesNonnull(p); // expected-warning {{}}
+ takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
break;
case 4: {
Dummy d;
@@ -89,11 +102,11 @@
Dummy *q = 0;
if (getRandom()) {
takesNullable(q);
- takesNonnull(q); // expected-warning {{}}
+ takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
}
Dummy a;
Dummy *_Nonnull nonnull = &a;
- nonnull = q; // expected-warning {{}}
+ nonnull = q; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
q = &a;
takesNullable(q);
takesNonnull(q);
@@ -106,26 +119,26 @@
Dummy *p = nullable;
Dummy *q = nonnull;
switch(getRandom()) {
- case 1: nonnull = p; break; // expected-warning {{}}
+ case 1: nonnull = p; break; // expected-warning {{Nullable pointer is assigned to a pointer which is expected to have non-null value}}
case 2: p = 0; break;
case 3: q = p; break;
case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
- case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}}
- case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}}
- case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}}
+ case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 3rd parameter}}
+ case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+ case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
}
}
Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
Dummy *p = a;
- return p; // expected-warning {{}}
+ return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
}
Dummy *_Nonnull testNullReturn() {
Dummy *p = 0;
- return p; // expected-warning {{}}
+ return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
}
void testObjCMessageResultNullability() {
@@ -147,20 +160,20 @@
break;
case 3:
shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
- [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+ [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
break;
case 4:
shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
- [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+ [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
break;
case 5:
shouldBeNullable =
[eraseNullab(getUnspecifiedTestObject()) returnsNullable];
- [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+ [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
break;
case 6:
shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
- [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+ [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
break;
case 7: {
int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
@@ -169,9 +182,44 @@
}
}
-void testCast() {
+Dummy * _Nonnull testDirectCastNullableToNonnull() {
+ Dummy *p = returnsNullable();
+ takesNonnull((Dummy * _Nonnull)p); // no-warning
+ return (Dummy * _Nonnull)p; // no-warning
+}
+
+Dummy * _Nonnull testIndirectCastNullableToNonnull() {
Dummy *p = (Dummy * _Nonnull)returnsNullable();
- takesNonnull(p);
+ takesNonnull(p); // no-warning
+ return p; // no-warning
+}
+
+Dummy * _Nonnull testDirectCastNilToNonnull() {
+ takesNonnull((Dummy * _Nonnull)0); // no-warning
+ return (Dummy * _Nonnull)0; // no-warning
+}
+
+void testIndirectCastNilToNonnullAndPass() {
+ Dummy *p = (Dummy * _Nonnull)0;
+ // FIXME: Ideally the cast above would suppress this warning.
+ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+}
+
+void testIndirectNilPassToNonnull() {
+ Dummy *p = 0;
+ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+}
+
+void testConditionalNilPassToNonnull(Dummy *p) {
+ if (!p) {
+ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+ }
+}
+
+Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
+ Dummy *p = (Dummy * _Nonnull)0;
+ // FIXME: Ideally the cast above would suppress this warning.
+ return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
}
void testInvalidPropagation() {
@@ -182,7 +230,7 @@
void onlyReportFirstPreconditionViolationOnPath() {
Dummy *p = returnsNullable();
- takesNonnull(p); // expected-warning {{}}
+ takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
takesNonnull(p); // No warning.
// The first warning was not a sink. The analysis expected to continue.
int i = 0;
@@ -231,6 +279,14 @@
if (p) return;
}
+void testNilReturnWithBlock(Dummy *p) {
+ p = 0;
+ Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
+ return p; // TODO: We should warn in blocks.
+ };
+ myblock();
+}
+
Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
switch (getRandom()) {
case 1: inlinedNullable(p); break;
@@ -238,6 +294,128 @@
case 3: inlinedUnspecified(p); break;
}
if (getRandom())
- takesNonnull(p);
+ takesNonnull(p); // no-warning
+
+ if (getRandom()) {
+ Dummy *_Nonnull varWithInitializer = p; // no-warning
+
+ Dummy *_Nonnull var1WithInitializer = p, // no-warning
+ *_Nonnull var2WithInitializer = p; // no-warning
+ }
+
+ if (getRandom()) {
+ Dummy *_Nonnull varWithoutInitializer;
+ varWithoutInitializer = p; // no-warning
+ }
+
return p;
}
+
+
+@interface SomeClass : NSObject {
+ int instanceVar;
+}
+@end
+
+@implementation SomeClass (MethodReturn)
+- (id)initWithSomething:(int)i {
+ if (self = [super init]) {
+ instanceVar = i;
+ }
+
+ return self;
+}
+
+- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
+ TestObject *local = getNullableTestObject();
+ return local; // expected-warning {{Nullable pointer is returned from a method that is expected to return a non-null value}}
+}
+
+- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
+ TestObject *local = getNullableTestObject();
+ return (TestObject * _Nonnull)local; // no-warning
+}
+
+- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
+ TestObject *local = getNullableTestObject();
+ if (!p) // Pre-condition violated here.
+ return local; // no-warning
+ else
+ return p; // no-warning
+}
+@end
+
+@interface ClassWithInitializers : NSObject
+@end
+
+@implementation ClassWithInitializers
+- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
+ // This defensive check is a common-enough idiom that we filter don't want
+ // to issue a diagnostic for it,
+ if (self = [super init]) {
+ }
+
+ return self; // no-warning
+}
+
+- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
+ self = [super init];
+ // This leaks, but we're not checking for that here.
+
+ ClassWithInitializers *other = nil;
+ // False negative. Once we have more subtle suppression of defensive checks in
+ // initializers we should warn here.
+ return other;
+}
+@end
+
+@interface SubClassWithInitializers : ClassWithInitializers
+@end
+
+@implementation SubClassWithInitializers
+// Note: Because this is overridding
+// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
+// the return type of this method becomes implicitly id _Nonnull.
+- (id)initWithNonnullReturnAndSelfCheckingIdiom {
+ if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
+ }
+
+ return self; // no-warning
+}
+
+- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
+ // Another common return-checking idiom
+ self = [super initWithNonnullReturnAndSelfCheckingIdiom];
+ if (!self) {
+ return nil; // no-warning
+ }
+
+ return self;
+}
+@end
+
+@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
+ id i;
+}
+
+@end
+
+@implementation ClassWithCopyWithZone
+-(id)copyWithZone:(NSZone *)zone {
+ ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
+ if (!newInstance)
+ return nil;
+
+ newInstance->i = i;
+ return newInstance;
+}
+
+-(id)mutableCopyWithZone:(NSZone *)zone {
+ ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
+ if (newInstance) {
+ newInstance->i = i;
+ }
+
+ return newInstance;
+}
+@end
diff --git a/test/Analysis/nullability_nullonly.mm b/test/Analysis/nullability_nullonly.mm
index 56b3f9e..d82105c 100644
--- a/test/Analysis/nullability_nullonly.mm
+++ b/test/Analysis/nullability_nullonly.mm
@@ -1,4 +1,20 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
+// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
+
+#define nil 0
+#define BOOL int
+
+@protocol NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@protocol NSCopying
+@end
+
+__attribute__((objc_root_class))
+@interface
+NSObject<NSObject>
+@end
int getRandom();
@@ -15,18 +31,18 @@
Dummy *q = 0;
if (getRandom()) {
takesNullable(q);
- takesNonnull(q); // expected-warning {{}}
+ takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
}
}
Dummy *_Nonnull testNullReturn() {
Dummy *p = 0;
- return p; // expected-warning {{}}
+ return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
}
void onlyReportFirstPreconditionViolationOnPath() {
Dummy *p = 0;
- takesNonnull(p); // expected-warning {{}}
+ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
takesNonnull(p); // No warning.
// Passing null to nonnull is a sink. Stop the analysis.
int i = 0;
@@ -85,3 +101,61 @@
takesNonnull(p);
return p;
}
+
+@interface TestObject : NSObject
+@end
+
+TestObject *_Nonnull getNonnullTestObject();
+
+void testObjCARCImplicitZeroInitialization() {
+ TestObject * _Nonnull implicitlyZeroInitialized; // no-warning
+ implicitlyZeroInitialized = getNonnullTestObject();
+}
+
+void testObjCARCExplicitZeroInitialization() {
+ TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
+}
+
+// Under ARC, returned expressions of ObjC objects types are are implicitly
+// cast to _Nonnull when the functions return type is _Nonnull, so make
+// sure this doesn't implicit cast doesn't suppress a legitimate warning.
+TestObject * _Nonnull returnsNilObjCInstanceIndirectly() {
+ TestObject *local = 0;
+ return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceIndirectlyWithSupressingCast() {
+ TestObject *local = 0;
+ return (TestObject * _Nonnull)local; // no-warning
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectly() {
+ return nil; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectlyWithSuppressingCast() {
+ return (TestObject * _Nonnull)nil; // no-warning
+}
+
+@interface SomeClass : NSObject
+@end
+
+@implementation SomeClass (MethodReturn)
+- (SomeClass * _Nonnull)testReturnsNilInNonnull {
+ SomeClass *local = nil;
+ return local; // expected-warning {{Null is returned from a method that is expected to return a non-null value}}
+}
+
+- (SomeClass * _Nonnull)testReturnsCastSuppressedNilInNonnull {
+ SomeClass *local = nil;
+ return (SomeClass * _Nonnull)local; // no-warning
+}
+
+- (SomeClass * _Nonnull)testReturnsNilInNonnullWhenPreconditionViolated:(SomeClass * _Nonnull) p {
+ SomeClass *local = nil;
+ if (!p) // Pre-condition violated here.
+ return local; // no-warning
+ else
+ return p; // no-warning
+}
+@end
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index 56151dc..acc525e 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -std=c++11 -Wno-conversion-null -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_cc1 -std=c++11 -Wno-conversion-null -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -verify %s
+
+void clang_analyzer_eval(int);
// test to see if nullptr is detected as a null pointer
void foo1(void) {
@@ -87,3 +89,59 @@
// Create MaterializeTemporaryExpr with a nullptr inside.
const nullptr_t &r = nullptr;
}
+
+int getSymbol();
+
+struct X {
+ virtual void f() {}
+};
+
+void invokeF(X* x) {
+ x->f(); // expected-warning{{Called C++ object pointer is null}}
+}
+
+struct Type {
+ decltype(nullptr) x;
+};
+
+void shouldNotCrash() {
+ decltype(nullptr) p;
+ if (getSymbol())
+ invokeF(p); // expected-warning{{Function call argument is an uninit}}
+ if (getSymbol())
+ invokeF(nullptr);
+ if (getSymbol()) {
+ X *x = Type().x;
+ x->f(); // expected-warning{{Called C++ object pointer is null}}
+ }
+}
+
+void f(decltype(nullptr) p) {
+ int *q = nullptr;
+ clang_analyzer_eval(p == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(q == 0); // expected-warning{{TRUE}}
+}
+
+decltype(nullptr) returnsNullPtrType();
+void fromReturnType() {
+ ((X *)returnsNullPtrType())->f(); // expected-warning{{Called C++ object pointer is null}}
+}
+
+#define AS_ATTRIBUTE __attribute__((address_space(256)))
+class AS1 {
+public:
+ int x;
+ ~AS1() {
+ int AS_ATTRIBUTE *x = 0;
+ *x = 3; // no-warning
+ }
+};
+void test_address_space_field_access() {
+ AS1 AS_ATTRIBUTE *pa = 0;
+ pa->x = 0; // no-warning
+}
+void test_address_space_bind() {
+ AS1 AS_ATTRIBUTE *pa = 0;
+ AS1 AS_ATTRIBUTE &r = *pa;
+ r.x = 0; // no-warning
+}
diff --git a/test/Analysis/padding_c.c b/test/Analysis/padding_c.c
new file mode 100644
index 0000000..93cefca
--- /dev/null
+++ b/test/Analysis/padding_c.c
@@ -0,0 +1,236 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+
+#if __has_include(<stdalign.h>)
+#include <stdalign.h>
+#endif
+
+#if __has_include(<stdalign.h>) || defined(__cplusplus)
+// expected-warning@+1{{Excessive padding in 'struct FieldAttrAlign' (6 padding}}
+struct FieldAttrAlign {
+ char c1;
+ alignas(4) int i;
+ char c2;
+};
+
+// expected-warning@+1{{Excessive padding in 'struct FieldAttrOverAlign' (10 padding}}
+struct FieldAttrOverAlign {
+ char c1;
+ alignas(8) int i;
+ char c2;
+};
+
+#endif // __has_include(<stdalign.h>) || defined(__cplusplus)
+
+// Re-ordering members of these structs won't reduce padding, so don't warn
+struct LeadingChar { // no-warning
+ char c;
+ int i;
+};
+
+struct TrailingChar { // no-warning
+ int i;
+ char c;
+};
+
+struct Helpless { // no-warning
+ struct TrailingChar i1;
+ struct LeadingChar i2;
+ char c;
+};
+
+#pragma pack(push)
+#pragma pack(1)
+struct SquishedIntSandwich { // no-warning
+ char c1;
+ int i;
+ char c2;
+};
+#pragma pack(pop)
+
+// Re-ordering members of these structs will reduce padding, so warn
+struct IntSandwich { // expected-warning{{Excessive padding in 'struct IntSandwich'}}
+ char c1;
+ int i;
+ char c2;
+};
+
+struct TurDuckHen { // expected-warning{{Excessive padding in 'struct TurDuckHen'}}
+ char c1;
+ struct IntSandwich i;
+ char c2;
+};
+
+#pragma pack(push)
+#pragma pack(2)
+struct SmallIntSandwich { // expected-warning{{Excessive padding in 'struct SmallIntSandwich'}}
+ char c1;
+ int i1;
+ char c2;
+ int i2;
+ char c3;
+ int i3;
+ char c4;
+};
+#pragma pack(pop)
+
+union SomeUnion { // no-warning
+ char c;
+ short s;
+ int i;
+};
+
+struct HoldsAUnion { // expected-warning{{Excessive padding in 'struct HoldsAUnion'}}
+ char c1;
+ union SomeUnion u;
+ char c2;
+};
+
+struct BigCharArray { // no-warning
+ char c[129];
+};
+
+struct SmallCharArray { // no-warning
+ char c[5];
+};
+
+struct MediumIntArray { // no-warning
+ int i[5];
+};
+
+struct LargeSizeToSmallSize { // expected-warning{{Excessive padding in 'struct LargeSizeToSmallSize'}}
+ struct BigCharArray b;
+ struct MediumIntArray m;
+ struct SmallCharArray s;
+};
+
+struct LargeAlignToSmallAlign { // no-warning
+ struct MediumIntArray m;
+ struct BigCharArray b;
+ struct SmallCharArray s;
+};
+
+// Currently ignoring VLA padding problems. Still need to make sure we don't
+// choke on VLAs though
+struct HoldsVLA { // no-warning
+ char c1;
+ int x;
+ char c2;
+ int vla[];
+};
+
+// Currently ignoring bitfield padding problems. Still need to make sure we
+// don't choke on bitfields though
+struct HoldsBitfield { // no-warning
+ char c1;
+ int x;
+ char c2;
+ unsigned char b1 : 3;
+ unsigned char b2 : 3;
+ unsigned char b3 : 2;
+};
+
+typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich'}}
+ char c1;
+ int i;
+ char c2;
+} TypedefSandwich;
+
+// expected-warning@+1{{Excessive padding in 'struct StructAttrAlign' (10 padding}}
+struct StructAttrAlign {
+ char c1;
+ int i;
+ char c2;
+} __attribute__((aligned(8)));
+
+struct CorrectOverlyAlignedChar { // no-warning
+ char c __attribute__((aligned(4096)));
+ char c1;
+ int x1;
+ char c2;
+ int x2;
+ char c3;
+};
+
+struct OverlyAlignedChar { // expected-warning{{Excessive padding in 'struct OverlyAlignedChar'}}
+ char c1;
+ int x;
+ char c2;
+ char c __attribute__((aligned(4096)));
+};
+
+struct HoldsOverlyAlignedChar { // expected-warning{{Excessive padding in 'struct HoldsOverlyAlignedChar'}}
+ char c1;
+ struct OverlyAlignedChar o;
+ char c2;
+};
+
+void internalStructFunc() {
+ struct X { // expected-warning{{Excessive padding in 'struct X'}}
+ char c1;
+ int t;
+ char c2;
+ };
+ struct X obj;
+}
+
+void typedefStructFunc() {
+ typedef struct { // expected-warning{{Excessive padding in 'S'}}
+ char c1;
+ int t;
+ char c2;
+ } S;
+ S obj;
+}
+
+void anonStructFunc() {
+ struct { // expected-warning{{Excessive padding in 'struct (anonymous}}
+ char c1;
+ int t;
+ char c2;
+ } obj;
+}
+
+struct CorrectDefaultAttrAlign { // no-warning
+ long long i;
+ char c1;
+ char c2;
+} __attribute__((aligned));
+
+struct TooSmallShortSandwich { // no-warning
+ char c1;
+ short s;
+ char c2;
+};
+
+// expected-warning@+1{{Excessive padding in 'struct SmallArrayShortSandwich'}}
+struct SmallArrayShortSandwich {
+ char c1;
+ short s;
+ char c2;
+} ShortArray[20];
+
+// expected-warning@+1{{Excessive padding in 'struct SmallArrayInFunc'}}
+struct SmallArrayInFunc {
+ char c1;
+ short s;
+ char c2;
+};
+
+void arrayHolder() {
+ struct SmallArrayInFunc Arr[15];
+}
+
+// xxxexpected-warning@+1{{Excessive padding in 'struct SmallArrayInStruct'}}
+struct SmallArrayInStruct {
+ char c1;
+ short s;
+ char c2;
+};
+
+struct HoldsSmallArray {
+ struct SmallArrayInStruct Field[20];
+} HoldsSmallArrayElt;
+
+void nestedPadding() {
+ struct HoldsSmallArray Arr[15];
+}
diff --git a/test/Analysis/padding_cpp.cpp b/test/Analysis/padding_cpp.cpp
new file mode 100644
index 0000000..df2f2a8
--- /dev/null
+++ b/test/Analysis/padding_cpp.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -std=c++14 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+
+// Make sure that the C cases still work fine, even when compiled as C++.
+#include "padding_c.c"
+
+struct BigCharArray2 { // no-warning
+ char c[129];
+};
+
+// xxxexpected-warning@+1{{Excessive padding in 'struct LowAlignmentBase'}}
+struct LowAlignmentBase : public BigCharArray2 {
+ int i;
+ char c;
+};
+
+struct CorrectLowAlignmentBase : public BigCharArray2 { // no-warning
+ char c;
+ int i;
+};
+
+// xxxexpected-warning@+1{{Excessive padding in 'struct LowAlignmentBase2'}}
+struct LowAlignmentBase2 : public BigCharArray2 {
+ char c1;
+ int i;
+ char c2;
+};
+
+class PaddedA { // expected-warning{{Excessive padding in 'class PaddedA'}}
+ char c1;
+ int i;
+ char c2;
+};
+
+class VirtualPaddedA : public PaddedA { // no-warning
+ virtual void foo() {}
+};
+
+class VirtualIntSandwich { // expected-warning{{Excessive padding in 'class VirtualIntSandwich'}}
+ virtual void foo() {}
+ char c1;
+ int i;
+ char c2;
+};
+
+// constructed so as not to have tail padding
+class InnerPaddedB { // expected-warning{{Excessive padding in 'class InnerPaddedB'}}
+ char c1;
+ int i1;
+ char c2;
+ int i2;
+};
+
+class TailPaddedB { // expected-warning{{Excessive padding in 'class TailPaddedB'}}
+ char c1;
+ int i1;
+ char c2;
+};
+
+class SI : public PaddedA { // no-warning
+ char c;
+};
+
+class SI2 : public PaddedA { // xxxexpected-warning{{Excessive padding in 'class SI2'}}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class VirtualSI : virtual public PaddedA { // no-warning
+ char c;
+};
+
+// currently not checked for
+class VirtualSI2 : virtual public PaddedA { // no-warning
+ char c10;
+ int i10;
+ char c11;
+};
+
+class VtblSI : public PaddedA { // no-warning
+ virtual void foo() {}
+ char c;
+};
+
+class VtblSI2 : public PaddedA { // xxxexpected-warning{{Excessive padding in 'class VtblSI2'}}
+ virtual void foo() {}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class VtblSI3 : public VirtualPaddedA { // xxxexpected-warning{{Excessive padding in 'class VtblSI3'}}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class MI : public PaddedA, public InnerPaddedB { // no-warning
+ char c;
+};
+
+class MI2 : public PaddedA, public InnerPaddedB { // xxxexpected-warning{{Excessive padding in 'class MI2'}}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class VtblMI : public PaddedA, public InnerPaddedB { // xxxexpected-warning{{Excessive padding in 'class VtblMI'}}
+ virtual void foo() {}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class VtblMI2 : public VirtualPaddedA, public InnerPaddedB { // xxxexpected-warning{{Excessive padding in 'class VtblMI2'}}
+ char c10;
+ int i10;
+ char c11;
+};
+
+class Empty {}; // no-warning
+
+class LotsOfSpace { // expected-warning{{Excessive padding in 'class LotsOfSpace'}}
+ Empty e1;
+ int i;
+ Empty e2;
+};
+
+class EBO1 : public Empty { // xxxexpected-warning{{Excessive padding in 'class EBO1'}}
+ char c1;
+ int i;
+ char c2;
+};
+
+class EBO2 : public Empty { // xxxexpected-warning{{Excessive padding in 'class EBO2'}}
+ Empty c1;
+ int i;
+ Empty c2;
+};
+
+template <typename T>
+class TemplateSandwich { // expected-warning{{Excessive padding in 'class TemplateSandwich<int>' instantiated here}}
+ char c1;
+ T t;
+ char c2;
+};
+
+template <typename T>
+class TemplateSandwich<T *> { // expected-warning{{Excessive padding in 'class TemplateSandwich<void *>' instantiated here}}
+ char c1;
+ T *t;
+ char c2;
+};
+
+template <>
+class TemplateSandwich<long long> { // expected-warning{{Excessive padding in 'class TemplateSandwich<long long>' (}}
+ char c1;
+ long long t;
+ char c2;
+};
+
+class Holder1 { // no-warning
+ TemplateSandwich<int> t1;
+ TemplateSandwich<char> t2;
+ TemplateSandwich<void *> t3;
+};
+
+typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich2'}}
+ char c1;
+ typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich2::NestedTypedef'}}
+ char c1;
+ int i;
+ char c2;
+ } NestedTypedef;
+ NestedTypedef t;
+ char c2;
+} TypedefSandwich2;
+
+template <typename T>
+struct Foo {
+ // expected-warning@+1{{Excessive padding in 'struct Foo<int>::Nested'}}
+ struct Nested {
+ char c1;
+ T t;
+ char c2;
+ };
+};
+
+struct Holder { // no-warning
+ Foo<int>::Nested t1;
+ Foo<char>::Nested t2;
+};
+
+struct GlobalsForLambda { // no-warning
+ int i;
+ char c1;
+ char c2;
+} G;
+
+// expected-warning@+1{{Excessive padding in 'class (lambda}}
+auto lambda1 = [ c1 = G.c1, i = G.i, c2 = G.c2 ]{};
+auto lambda2 = [ i = G.i, c1 = G.c1, c2 = G.c2 ]{}; // no-warning
diff --git a/test/Analysis/padding_message.cpp b/test/Analysis/padding_message.cpp
new file mode 100644
index 0000000..f73a11a
--- /dev/null
+++ b/test/Analysis/padding_message.cpp
@@ -0,0 +1,185 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++14 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+
+// expected-warning@+1{{Excessive padding in 'struct IntSandwich' (6 padding bytes, where 2 is optimal)}}
+struct IntSandwich {
+ char c1;
+ int i;
+ char c2;
+};
+
+// expected-warning@+1{{Excessive padding in 'struct TurDuckHen' (6 padding bytes, where 2 is optimal)}}
+struct TurDuckHen {
+ char c1;
+ struct IntSandwich i;
+ char c2;
+};
+
+#pragma pack(push)
+#pragma pack(2)
+// expected-warning@+1{{Excessive padding in 'struct SmallIntSandwich' (4 padding bytes, where 0 is optimal)}}
+struct SmallIntSandwich {
+ char c1;
+ int i1;
+ char c2;
+ int i2;
+ char c3;
+ int i3;
+ char c4;
+};
+#pragma pack(pop)
+
+union SomeUnion { // no-warning
+ char c;
+ short s;
+ int i;
+};
+
+// expected-warning@+1{{Excessive padding in 'struct HoldsAUnion' (6 padding bytes, where 2 is optimal)}}
+struct HoldsAUnion {
+ char c1;
+ union SomeUnion u;
+ char c2;
+};
+
+struct SmallCharArray { // no-warning
+ char c[5];
+};
+
+struct MediumIntArray { // no-warning
+ int i[5];
+};
+
+// expected-warning@+1{{Excessive padding in 'struct StructSandwich' (6 padding bytes, where 2 is optimal)}}
+struct StructSandwich {
+ struct SmallCharArray s;
+ struct MediumIntArray m;
+ struct SmallCharArray s2;
+};
+
+// expected-warning@+1{{Excessive padding in 'TypedefSandwich' (6 padding bytes, where 2 is optimal)}}
+typedef struct {
+ char c1;
+ int i;
+ char c2;
+} TypedefSandwich;
+
+// expected-warning@+1{{Excessive padding in 'struct StructAttrAlign' (10 padding bytes, where 2 is optimal)}}
+struct StructAttrAlign {
+ char c1;
+ int i;
+ char c2;
+} __attribute__((aligned(8)));
+
+// expected-warning@+1{{Excessive padding in 'struct OverlyAlignedChar' (8185 padding bytes, where 4089 is optimal)}}
+struct OverlyAlignedChar {
+ char c1;
+ int x;
+ char c2;
+ char c __attribute__((aligned(4096)));
+};
+
+// expected-warning@+1{{Excessive padding in 'struct HoldsOverlyAlignedChar' (8190 padding bytes, where 4094 is optimal)}}
+struct HoldsOverlyAlignedChar {
+ char c1;
+ struct OverlyAlignedChar o;
+ char c2;
+};
+
+void internalStructFunc() {
+ // expected-warning@+1{{Excessive padding in 'struct X' (6 padding bytes, where 2 is optimal)}}
+ struct X {
+ char c1;
+ int t;
+ char c2;
+ };
+ struct X obj;
+}
+
+void typedefStructFunc() {
+ // expected-warning@+1{{Excessive padding in 'S' (6 padding bytes, where 2 is optimal)}}
+ typedef struct {
+ char c1;
+ int t;
+ char c2;
+ } S;
+ S obj;
+}
+
+// expected-warning@+1{{Excessive padding in 'struct DefaultAttrAlign' (22 padding bytes, where 6 is optimal)}}
+struct DefaultAttrAlign {
+ char c1;
+ long long i;
+ char c2;
+} __attribute__((aligned));
+
+// expected-warning@+1{{Excessive padding in 'struct SmallArrayShortSandwich' (2 padding bytes, where 0 is optimal)}}
+struct SmallArrayShortSandwich {
+ char c1;
+ short s;
+ char c2;
+} ShortArray[20];
+
+// expected-warning@+1{{Excessive padding in 'struct SmallArrayInFunc' (2 padding bytes, where 0 is optimal)}}
+struct SmallArrayInFunc {
+ char c1;
+ short s;
+ char c2;
+};
+
+void arrayHolder() {
+ struct SmallArrayInFunc Arr[15];
+}
+
+// expected-warning@+1{{Excessive padding in 'class VirtualIntSandwich' (10 padding bytes, where 2 is optimal)}}
+class VirtualIntSandwich {
+ virtual void foo() {}
+ char c1;
+ int i;
+ char c2;
+};
+
+// constructed so as not to have tail padding
+// expected-warning@+1{{Excessive padding in 'class InnerPaddedB' (6 padding bytes, where 2 is optimal)}}
+class InnerPaddedB {
+ char c1;
+ int i1;
+ char c2;
+ int i2;
+};
+
+class Empty {}; // no-warning
+
+// expected-warning@+1{{Excessive padding in 'class LotsOfSpace' (6 padding bytes, where 2 is optimal)}}
+class LotsOfSpace {
+ Empty e1;
+ int i;
+ Empty e2;
+};
+
+// expected-warning@+1{{Excessive padding in 'TypedefSandwich2' (6 padding bytes, where 2 is optimal)}}
+typedef struct {
+ char c1;
+ // expected-warning@+1{{Excessive padding in 'TypedefSandwich2::NestedTypedef' (6 padding bytes, where 2 is optimal)}}
+ typedef struct {
+ char c1;
+ int i;
+ char c2;
+ } NestedTypedef;
+ NestedTypedef t;
+ char c2;
+} TypedefSandwich2;
+
+template <typename T>
+struct Foo {
+ // expected-warning@+1{{Excessive padding in 'struct Foo<int>::Nested' (6 padding bytes, where 2 is optimal)}}
+ struct Nested {
+ char c1;
+ T t;
+ char c2;
+ };
+};
+
+struct Holder { // no-warning
+ Foo<int>::Nested t1;
+ Foo<char>::Nested t2;
+};
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index bf9424c..4fdbb69 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -211,6 +211,33 @@
clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
}
+@interface ClassWithShadowedReadWriteProperty {
+ int _f;
+}
+@property (readonly) int someProp;
+@end
+
+@interface ClassWithShadowedReadWriteProperty ()
+@property (readwrite) int someProp;
+@end
+
+@implementation ClassWithShadowedReadWriteProperty
+- (void)testSynthesisForShadowedReadWriteProperties; {
+ clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
+
+ _f = 1;
+
+ // Read of shadowed property should not invalidate receiver.
+ (void)self.someProp;
+ clang_analyzer_eval(_f == 1); // expected-warning{{TRUE}}
+
+ _f = 2;
+ // Call to getter of shadowed property should not invalidate receiver.
+ (void)[self someProp];
+ clang_analyzer_eval(_f == 2); // expected-warning{{TRUE}}
+}
+@end
+
#if !__has_feature(objc_arc)
void testOverrelease(Person *p, int coin) {
switch (coin) {
diff --git a/test/Analysis/qt_malloc.cpp b/test/Analysis/qt_malloc.cpp
new file mode 100644
index 0000000..d29835f
--- /dev/null
+++ b/test/Analysis/qt_malloc.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus -analyzer-store=region -verify %s
+// expected-no-diagnostics
+#include "Inputs/qt-simulator.h"
+
+void send(QObject *obj)
+{
+ QEvent *e1 = new QEvent(QEvent::None);
+ static_cast<QApplication *>(QCoreApplication::instance())->postEvent(obj, e1);
+ QEvent *e2 = new QEvent(QEvent::None);
+ QCoreApplication::instance()->postEvent(obj, e2);
+ QEvent *e3 = new QEvent(QEvent::None);
+ QCoreApplication::postEvent(obj, e3);
+ QEvent *e4 = new QEvent(QEvent::None);
+ QApplication::postEvent(obj, e4);
+}
diff --git a/test/Analysis/range_casts.c b/test/Analysis/range_casts.c
new file mode 100644
index 0000000..682369c
--- /dev/null
+++ b/test/Analysis/range_casts.c
@@ -0,0 +1,156 @@
+// This test checks that intersecting ranges does not cause 'system is over constrained' assertions in the case of eg: 32 bits unsigned integers getting their range from 64 bits signed integers.
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+
+void clang_analyzer_warnIfReached();
+
+void f1(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0) // because of foo range, index is in range [0; UINT_MAX]
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f2(unsigned long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo; // index equals ULONG_MAX
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // no-warning
+}
+
+void f3(unsigned long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f4(long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f5(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f6(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f7(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1 == 0) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f8(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1L == 0L)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f9(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1L == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f10(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0L)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f11(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1UL == 0L)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f12(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1UL == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f13(int foo)
+{
+ unsigned short index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f14(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ long bar = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f15(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ unsigned int tmp = index + 1;
+ if (tmp == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp
index cb7cbfd..f3b0a7b 100644
--- a/test/Analysis/reinterpret-cast.cpp
+++ b/test/Analysis/reinterpret-cast.cpp
@@ -102,4 +102,17 @@
set_x1(x);
set_x2((void *&)y);
return *x + *y; // no warning
-}
\ No newline at end of file
+}
+
+namespace PR25426 {
+ struct Base {
+ int field;
+ };
+
+ struct Derived : Base { };
+
+ void foo(int &p) {
+ Derived &d = (Derived &)(p);
+ d.field = 2;
+ }
+}
diff --git a/test/Analysis/return-ptr-range.cpp b/test/Analysis/return-ptr-range.cpp
new file mode 100644
index 0000000..0cc17b0
--- /dev/null
+++ b/test/Analysis/return-ptr-range.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.ReturnPtrRange -verify %s
+
+int arr[10];
+int *ptr;
+
+int conjure_index();
+
+int *test_element_index_lifetime() {
+ do {
+ int x = conjure_index();
+ ptr = arr + x;
+ if (x != 20)
+ return arr; // no-warning
+ } while (0);
+ return ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}}
+}
+
+int *test_element_index_lifetime_with_local_ptr() {
+ int *local_ptr;
+ do {
+ int x = conjure_index();
+ local_ptr = arr + x;
+ if (x != 20)
+ return arr; // no-warning
+ } while (0);
+ return local_ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}}
+}
diff --git a/test/Analysis/symbol-reaper.c b/test/Analysis/symbol-reaper.c
new file mode 100644
index 0000000..4051c38
--- /dev/null
+++ b/test/Analysis/symbol-reaper.c
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnOnDeadSymbol(int);
+
+int conjure_index();
+
+void test_that_expr_inspection_works() {
+ do {
+ int x = conjure_index();
+ clang_analyzer_warnOnDeadSymbol(x);
+ } while(0); // expected-warning{{SYMBOL DEAD}}
+}
+
+// These tests verify the reaping of symbols that are only referenced as
+// index values in element regions. Most of the time, depending on where
+// the element region, as Loc value, is stored, it is possible to
+// recover the index symbol in checker code, which is also demonstrated
+// in the return_ptr_range.c test file.
+
+int arr[3];
+
+int *test_element_index_lifetime_in_environment_values() {
+ int *ptr;
+ do {
+ int x = conjure_index();
+ clang_analyzer_warnOnDeadSymbol(x);
+ ptr = arr + x;
+ } while (0);
+ return ptr;
+}
+
+void test_element_index_lifetime_in_store_keys() {
+ do {
+ int x = conjure_index();
+ clang_analyzer_warnOnDeadSymbol(x);
+ arr[x] = 1;
+ if (x) {}
+ } while (0); // no-warning
+}
+
+int *ptr;
+void test_element_index_lifetime_in_store_values() {
+ do {
+ int x = conjure_index();
+ clang_analyzer_warnOnDeadSymbol(x);
+ ptr = arr + x;
+ } while (0); // no-warning
+}
+
+struct S1 {
+ int field;
+};
+struct S2 {
+ struct S1 array[5];
+} s2;
+
+void test_element_index_lifetime_with_complicated_hierarchy_of_regions() {
+ do {
+ int x = conjure_index();
+ clang_analyzer_warnOnDeadSymbol(x);
+ s2.array[x].field = 1;
+ if (x) {}
+ } while (0); // no-warning
+}
+
+// Test below checks lifetime of SymbolRegionValue in certain conditions.
+
+int **ptrptr;
+void test_region_lifetime_as_store_value(int *x) {
+ clang_analyzer_warnOnDeadSymbol((int) x);
+ *x = 1;
+ ptrptr = &x;
+ (void)0; // No-op; make sure the environment forgets things and the GC runs.
+ clang_analyzer_eval(**ptrptr); // expected-warning{{TRUE}}
+} // no-warning
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 799f37b..8dd64d1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -61,10 +61,12 @@
FileCheck count not
llc
llvm-bcanalyzer
+ llvm-lto
llvm-objdump
llvm-profdata
llvm-readobj
llvm-symbolizer
+ LTO
opt
)
endif()
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
index 32dd75a..2292fc5 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace A {
class A {
@@ -20,6 +22,9 @@
namespace C {
class C {}; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B::B' to 'const C::C &' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'B::B' to 'C::C &&' for 1st argument}}
+#endif
void func(C); // expected-note {{'C::func' declared here}} \
// expected-note {{passing argument to parameter here}}
C operator+(C,C);
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
index 7918e9f..ed6c6c0 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace Ints {
int zero = 0; // expected-note {{candidate found by name lookup is 'Ints::zero'}}
@@ -31,7 +33,11 @@
}
namespace Numbers {
- struct Number { // expected-note 2 {{candidate}}
+ struct Number { // expected-note 2 {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
explicit Number(double d) : d(d) {}
double d;
};
@@ -66,7 +72,11 @@
namespace inline_ns {
int x; // expected-note 2{{found}}
- inline namespace A { // expected-warning {{C++11}}
+ inline namespace A {
+#if __cplusplus <= 199711L // C++03 or earlier
+ // expected-warning@-2 {{inline namespaces are a C++11 feature}}
+#endif
+
int x; // expected-note 2{{found}}
int y; // expected-note 2{{found}}
}
diff --git a/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp b/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
index 1d2b525..bf8df1a 100644
--- a/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
+++ b/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// rdar4641403
namespace N {
@@ -34,7 +36,10 @@
struct S c = b;
}
{
- struct S { S() {} }; // expected-note {{candidate}}
+ struct S { S() {} }; // expected-note {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
int a = S(); // expected-error {{no viable conversion from 'S'}}
struct S c = b; // expected-error {{no viable conversion from 'struct S'}}
}
@@ -50,7 +55,10 @@
struct S c = b;
}
{
- struct S { S() {} }; // expected-note {{candidate}}
+ struct S { S() {} }; // expected-note {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
int a = S(); // expected-error {{no viable conversion from 'S'}}
struct S c = b; // expected-error {{no viable conversion from 'struct S'}}
}
diff --git a/test/CXX/class.access/class.friend/p2-cxx03.cpp b/test/CXX/class.access/class.friend/p2-cxx03.cpp
index f8cabfd..88b2ea3 100644
--- a/test/CXX/class.access/class.friend/p2-cxx03.cpp
+++ b/test/CXX/class.access/class.friend/p2-cxx03.cpp
@@ -1,7 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T>
class X0 {
- friend T; // expected-warning{{non-class friend type 'T' is a C++11 extension}}
+ friend T;
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{non-class friend type 'T' is a C++11 extension}}
+#else
+ // expected-no-diagnostics
+#endif
};
class X1 { };
diff --git a/test/CXX/class/class.mem/p13.cpp b/test/CXX/class/class.mem/p13.cpp
index 1d7b9bc..bc01fd4 100644
--- a/test/CXX/class/class.mem/p13.cpp
+++ b/test/CXX/class/class.mem/p13.cpp
@@ -58,12 +58,12 @@
};
// - every member of every anonymous union that is a member of class T.
-struct X4 {
+struct X4 { // expected-note{{previous}}
union {
int X;
union {
float Y;
- unsigned X4; // expected-error{{member 'X4' has the same name as its class}}
+ unsigned X4; // expected-error{{redeclares 'X4'}}
};
};
};
diff --git a/test/CXX/class/class.nest/p1.cpp b/test/CXX/class/class.nest/p1.cpp
index b0341da..59bf50f 100644
--- a/test/CXX/class/class.nest/p1.cpp
+++ b/test/CXX/class/class.nest/p1.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
class Outer {
int x;
@@ -7,7 +9,10 @@
// C++11 does relax this rule (see 5.1.1.10) in the first case, but we need to enforce it in C++03 mode.
class Inner {
- static char a[sizeof(x)]; // expected-error {{invalid use of non-static data member 'x'}}
+ static char a[sizeof(x)];
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{invalid use of non-static data member 'x'}}
+#endif
static char b[sizeof(sx)]; // okay
static char c[sizeof(f)]; // expected-error {{call to non-static member function without an object argument}}
};
diff --git a/test/CXX/class/class.union/class.union.anon/p1.cpp b/test/CXX/class/class.union/class.union.anon/p1.cpp
new file mode 100644
index 0000000..31c9313
--- /dev/null
+++ b/test/CXX/class/class.union/class.union.anon/p1.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -verify %s
+
+struct X {
+ int a; // expected-note {{previous}}
+ void b(); // expected-note {{previous}}
+ struct c; // expected-note {{previous}}
+ typedef int d; // expected-note {{previous}}
+
+ union {
+ int a; // expected-error {{member of anonymous union redeclares}}
+ int b; // expected-error {{member of anonymous union redeclares}}
+ int c; // expected-error {{member of anonymous union redeclares}}
+ int d; // expected-error {{member of anonymous union redeclares}}
+ int e; // expected-note {{previous}}
+ int f; // expected-note {{previous}}
+ int g; // expected-note {{previous}}
+ int h; // expected-note {{previous}}
+ };
+
+ int e; // expected-error {{duplicate member}}
+ void f(); // expected-error {{redefinition}}
+ struct g; // expected-error {{redefinition}}
+ typedef int h; // expected-error {{redefinition}}
+};
diff --git a/test/CXX/class/class.union/p8.cpp b/test/CXX/class/class.union/class.union.anon/p4.cpp
similarity index 100%
rename from test/CXX/class/class.union/p8.cpp
rename to test/CXX/class/class.union/class.union.anon/p4.cpp
diff --git a/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
index 36e17aa..4779109 100644
--- a/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
+++ b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-// REQUIRES: tls
template<typename T> concept thread_local bool VCTL = true; // expected-error {{variable concept cannot be declared 'thread_local'}}
diff --git a/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
new file mode 100644
index 0000000..38593bc
--- /dev/null
+++ b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p5.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
+
+template<typename T>
+concept bool fcpv(void) { return true; }
+
+template<typename T>
+concept bool fcpi(int i = 0) { return true; } // expected-error {{function concept cannot have any parameters}}
+
+template<typename... Ts>
+concept bool fcpp(Ts... ts) { return true; } // expected-error {{function concept cannot have any parameters}}
+
+template<typename T>
+concept bool fcpva(...) { return true; } // expected-error {{function concept cannot have any parameters}}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
index bf30ee7..021c250 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
@@ -1,10 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// We have to avoid ADL for this test.
template <unsigned N> class test {};
-class foo {}; // expected-note {{candidate}}
+class foo {}; // expected-note {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
test<0> foo(foo); // expected-note {{candidate}}
namespace Test0 {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
index 5d1e6fb..08b22c1 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
@@ -1,10 +1,15 @@
// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -std=c++98 %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
class A {
public:
explicit A();
- explicit operator int(); // expected-warning {{explicit conversion functions are a C++11 extension}}
+ explicit operator int();
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{explicit conversion functions are a C++11 extension}}
+#endif
explicit void f0(); // expected-error {{'explicit' can only be applied to a constructor or conversion function}}
@@ -12,8 +17,11 @@
};
explicit A::A() { } // expected-error {{'explicit' can only be specified inside the class definition}}
-explicit A::operator bool() { return false; } // expected-warning {{explicit conversion functions are a C++11 extension}}\
- // expected-error {{'explicit' can only be specified inside the class definition}}
+explicit A::operator bool() { return false; }
+#if __cplusplus <= 199711L // C++03 or earlier modes
+// expected-warning@-2 {{explicit conversion functions are a C++11 extension}}
+#endif
+// expected-error@-4 {{'explicit' can only be specified inside the class definition}}
class B {
friend explicit A::A(); // expected-error {{'explicit' is invalid in friend declarations}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
index 44cc5a7..0b7a902 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
@@ -1,26 +1,58 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// The auto or register specifiers can be applied only to names of objects
// declared in a block (6.3) or to function parameters (8.4).
auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
+
auto void af(); // expected-error {{illegal storage class on function}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
register int ro; // expected-error {{illegal storage class on file-scoped variable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'register' storage class specifier is deprecated}}
+#endif
+
register void rf(); // expected-error {{illegal storage class on function}}
struct S {
auto int ao; // expected-error {{storage class specified for a member declaration}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
auto void af(); // expected-error {{storage class specified for a member declaration}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
register int ro; // expected-error {{storage class specified for a member declaration}}
register void rf(); // expected-error {{storage class specified for a member declaration}}
};
void foo(auto int ap, register int rp) {
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
auto int abo;
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
auto void abf(); // expected-error {{illegal storage class on function}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+#endif
register int rbo;
+#if __cplusplus >= 201103L // C++11 or later
+// expected-warning@-2 {{'register' storage class specifier is deprecated}}
+#endif
+
register void rbf(); // expected-error {{illegal storage class on function}}
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
index 39c547b..eb75151 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
@@ -3,9 +3,9 @@
// FIXME: This is in p11 (?) in C++1y.
void f() {
- decltype(auto) a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
- if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'auto' type cannot appear in its own initializer}}
- decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'auto' type cannot appear in its own initializer}}
+ decltype(auto) a = a; // expected-error{{variable 'a' declared with 'decltype(auto)' type cannot appear in its own initializer}}
+ if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'decltype(auto)' type cannot appear in its own initializer}}
+ decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'decltype(auto)' type cannot appear in its own initializer}}
}
void g() {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
index c3dc1de..06bd72e 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
@@ -49,7 +49,7 @@
decltype(auto) (*f2)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}}
decltype(auto) *f3(); // expected-error {{cannot form pointer to 'decltype(auto)'}}
const decltype(auto) f4(); // expected-error {{'decltype(auto)' cannot be combined with other type specifiers}}
-typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}}
+typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' not allowed in typedef}}
decltype(auto) ((((((f6))))())); // ok
decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{function cannot return function type}}
decltype(auto) (S::*f8)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp
new file mode 100644
index 0000000..e3982fd
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -verify %s -std=c++11
+
+namespace N {
+ struct A;
+ template<typename T> struct B {};
+}
+template<typename T> struct C {};
+struct D {
+ template<typename T> struct A {};
+};
+struct N::A; // expected-error {{cannot have a nested name specifier}}
+
+template<typename T> struct N::B; // expected-error {{cannot have a nested name specifier}}
+template<typename T> struct N::B<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct N::B<int>;
+template struct N::B<float>;
+
+template<typename T> struct C;
+template<typename T> struct C<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct C<int>;
+template struct C<float>;
+
+template<typename T> struct D::A; // expected-error {{cannot have a nested name specifier}}
+template<typename T> struct D::A<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct D::A<int>;
+template struct D::A<float>;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index 40e7540..1940651 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
class A {}; // expected-note 4 {{previous use is here}}
enum E {};
@@ -14,7 +16,10 @@
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
- friend enum E; // expected-warning {{befriending enumeration type 'enum E' is a C++11 extension}}
+ friend enum E;
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{befriending enumeration type 'enum E' is a C++11 extension}}
+#endif
};
template <class T> struct B { // expected-note {{previous use is here}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
index cb62874..3822122 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -1,7 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct Base { };
struct Derived : Base { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
struct Unrelated { };
struct Derived2 : Base { };
struct Diamond : Derived, Derived2 { };
diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp
index 29b39cb..37c144e 100644
--- a/test/CXX/drs/dr13xx.cpp
+++ b/test/CXX/drs/dr13xx.cpp
@@ -7,9 +7,9 @@
auto a(1); // expected-error 0-1{{extension}}
auto b(1, 2); // expected-error {{multiple expressions}} expected-error 0-1{{extension}}
#if __cplusplus >= 201103L
- auto c({}); // expected-error {{parenthesized initializer list}} expected-error {{cannot deduce}}
- auto d({1}); // expected-error {{parenthesized initializer list}} expected-error {{<initializer_list>}}
- auto e({1, 2}); // expected-error {{parenthesized initializer list}} expected-error {{<initializer_list>}}
+ auto c({}); // expected-error {{parenthesized initializer list}}
+ auto d({1}); // expected-error {{parenthesized initializer list}}
+ auto e({1, 2}); // expected-error {{parenthesized initializer list}}
#endif
template<typename...Ts> void f(Ts ...ts) { // expected-error 0-1{{extension}}
auto x(ts...); // expected-error {{empty}} expected-error 0-1{{extension}}
@@ -21,9 +21,9 @@
[a(1)] {} (); // expected-error 0-1{{extension}}
[b(1, 2)] {} (); // expected-error {{multiple expressions}} expected-error 0-1{{extension}}
#if __cplusplus >= 201103L
- [c({})] {} (); // expected-error {{parenthesized initializer list}} expected-error {{cannot deduce}} expected-error 0-1{{extension}}
- [d({1})] {} (); // expected-error {{parenthesized initializer list}} expected-error {{<initializer_list>}} expected-error 0-1{{extension}}
- [e({1, 2})] {} (); // expected-error {{parenthesized initializer list}} expected-error {{<initializer_list>}} expected-error 0-1{{extension}}
+ [c({})] {} (); // expected-error {{parenthesized initializer list}} expected-error 0-1{{extension}}
+ [d({1})] {} (); // expected-error {{parenthesized initializer list}} expected-error 0-1{{extension}}
+ [e({1, 2})] {} (); // expected-error {{parenthesized initializer list}} expected-error 0-1{{extension}}
#endif
}
#endif
diff --git a/test/CXX/drs/dr15xx.cpp b/test/CXX/drs/dr15xx.cpp
index d35583f..7472be7 100644
--- a/test/CXX/drs/dr15xx.cpp
+++ b/test/CXX/drs/dr15xx.cpp
@@ -101,4 +101,75 @@
}
} // dr1589
+
+namespace dr1591 { //dr1591. Deducing array bound and element type from initializer list
+ template<class T, int N> int h(T const(&)[N]);
+ int X = h({1,2,3}); // T deduced to int, N deduced to 3
+
+ template<class T> int j(T const(&)[3]);
+ int Y = j({42}); // T deduced to int, array bound not considered
+
+ struct Aggr { int i; int j; };
+ template<int N> int k(Aggr const(&)[N]); //expected-note{{not viable}}
+ int Y0 = k({1,2,3}); //expected-error{{no matching function}}
+ int Z = k({{1},{2},{3}}); // OK, N deduced to 3
+
+ template<int M, int N> int m(int const(&)[M][N]);
+ int X0 = m({{1,2},{3,4}}); // M and N both deduced to 2
+
+ template<class T, int N> int n(T const(&)[N], T);
+ int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
+
+
+ namespace check_multi_dim_arrays {
+ template<class T, int N, int M, int O> int ***f(const T (&a)[N][M][O]); //expected-note{{deduced conflicting values}}
+ template<class T, int N, int M> int **f(const T (&a)[N][M]); //expected-note{{couldn't infer}}
+
+ template<class T, int N> int *f(const T (&a)[N]); //expected-note{{couldn't infer}}
+ int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
+ int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); //expected-error{{no matching}}
+ int **p2 = f({ {1,2,3}, {3, 4, 5} });
+ int **p22 = f({ {1,2}, {3, 4} });
+ int *p1 = f({1, 2, 3});
+ }
+ namespace check_multi_dim_arrays_rref {
+ template<class T, int N, int M, int O> int ***f(T (&&a)[N][M][O]); //expected-note{{deduced conflicting values}}
+ template<class T, int N, int M> int **f(T (&&a)[N][M]); //expected-note{{couldn't infer}}
+
+ template<class T, int N> int *f(T (&&a)[N]); //expected-note{{couldn't infer}}
+ int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
+ int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); //expected-error{{no matching}}
+ int **p2 = f({ {1,2,3}, {3, 4, 5} });
+ int **p22 = f({ {1,2}, {3, 4} });
+ int *p1 = f({1, 2, 3});
+ }
+
+ namespace check_arrays_of_init_list {
+ template<class T, int N> float *f(const std::initializer_list<T> (&)[N]);
+ template<class T, int N> double *f(const T(&)[N]);
+ double *p = f({1, 2, 3});
+ float *fp = f({{1}, {1, 2}, {1, 2, 3}});
+ }
+ namespace core_reflector_28543 {
+
+ template<class T, int N> int *f(T (&&)[N]); // #1
+ template<class T> char *f(std::initializer_list<T> &&); //#2
+ template<class T, int N, int M> int **f(T (&&)[N][M]); //#3 expected-note{{candidate}}
+ template<class T, int N> char **f(std::initializer_list<T> (&&)[N]); //#4 expected-note{{candidate}}
+
+ template<class T> short *f(T (&&)[2]); //#5
+
+ template<class T> using Arr = T[];
+
+ char *pc = f({1, 2, 3}); // OK prefer #2 via 13.3.3.2 [over.ics.rank]
+ char *pc2 = f({1, 2}); // #2 also
+ int *pi = f(Arr<int>{1, 2, 3}); // OK prefer #1
+
+ void *pv1 = f({ {1, 2, 3}, {4, 5, 6} }); // expected-error{{ambiguous}} btw 3 & 4
+ char **pcc = f({ {1}, {2, 3} }); // OK #4
+
+ short *ps = f(Arr<int>{1, 2}); // OK #5
+ }
+} // dr1591
+
#endif
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
index 377bfc9..47d1494 100644
--- a/test/CXX/drs/dr1xx.cpp
+++ b/test/CXX/drs/dr1xx.cpp
@@ -524,8 +524,13 @@
namespace dr145 { // dr145: yes
void f(bool b) {
+#if __cplusplus <= 201402L
++b; // expected-warning {{deprecated}}
b++; // expected-warning {{deprecated}}
+#else
+ ++b; // expected-error {{increment}}
+ b++; // expected-error {{increment}}
+#endif
}
}
diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp
index 2a548e2..bceea79 100644
--- a/test/CXX/drs/dr4xx.cpp
+++ b/test/CXX/drs/dr4xx.cpp
@@ -83,7 +83,7 @@
} A;
}
-namespace dr407 { // dr407: no
+namespace dr407 { // dr407: 3.8
struct S;
typedef struct S S;
void f() {
@@ -108,22 +108,22 @@
struct S s; // expected-error {{ambiguous}}
}
namespace D {
- // FIXME: This is valid.
using A::S;
- typedef struct S S; // expected-note {{here}}
- struct S s; // expected-error {{refers to a typedef}}
+ typedef struct S S;
+ struct S s;
}
namespace E {
- // FIXME: The standard doesn't say whether this is valid.
+ // The standard doesn't say whether this is valid. We interpret
+ // DR407 as meaning "if lookup finds both a tag and a typedef with the
+ // same type, then it's OK in an elaborated-type-specifier".
typedef A::S S;
using A::S;
struct S s;
}
namespace F {
- typedef A::S S; // expected-note {{here}}
+ typedef A::S S;
}
- // FIXME: The standard doesn't say what to do in these cases, but
- // our behavior should not depend on the order of the using-directives.
+ // The standard doesn't say what to do in these cases either.
namespace G {
using namespace A;
using namespace F;
@@ -132,7 +132,7 @@
namespace H {
using namespace F;
using namespace A;
- struct S s; // expected-error {{refers to a typedef}}
+ struct S s;
}
}
}
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index 0cf67e6..96d3494 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -148,8 +148,7 @@
template<typename T> void b2(volatile T * const *);
template<typename T> void b2(volatile T * const S::*);
template<typename T> void b2(volatile T * const S::* const *);
- // FIXME: This diagnostic isn't very good. The problem is not substitution failure.
- template<typename T> void b2a(volatile T *S::* const *); // expected-note {{substitution failure}}
+ template<typename T> void b2a(volatile T *S::* const *); // expected-note {{candidate template ignored: deduced type 'volatile int *dr522::S::*const *' of 1st parameter does not match adjusted type 'int *dr522::S::**' of argument}}
template<typename T> struct Base {};
struct Derived : Base<int> {};
@@ -519,23 +518,12 @@
}
namespace dr547 { // dr547: yes
- // When targeting the MS x86 ABI, the type of a member function includes a
- // __thiscall qualifier. This is non-conforming, but we still implement
- // the intent of dr547
-#if defined(_M_IX86) || (defined(__MINGW32__) && !defined(__MINGW64__))
-#define THISCALL __thiscall
-#else
-#define THISCALL
-#endif
-
template<typename T> struct X;
- template<typename T> struct X<THISCALL T() const> {};
+ template<typename T> struct X<T() const> {};
template<typename T, typename C> X<T> f(T C::*) { return X<T>(); }
struct S { void f() const; };
- X<THISCALL void() const> x = f(&S::f);
-
-#undef THISCALL
+ X<void() const> x = f(&S::f);
}
namespace dr548 { // dr548: dup 482
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 2adefd9..c519ecb 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -601,11 +601,11 @@
typedef __INTPTR_TYPE__ intptr_t;
constexpr intptr_t f(intptr_t x) {
- return (((x) >> 21) * 8); // expected-note{{subexpression not valid in a constant expression}}
+ return (((x) >> 21) * 8);
}
extern "C" int foo;
constexpr intptr_t i = f((intptr_t)&foo - 10); // expected-error{{constexpr variable 'i' must be initialized by a constant expression}} \
- // expected-note{{in call to 'f((char*)&foo + -10)'}}
+ // expected-note{{reinterpret_cast}}
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
index 1228c74..63e51a7 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -48,7 +48,8 @@
auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type '<overloaded function}}
-auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}} expected-warning {{will change meaning in a future version of Clang}}
+auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}}
+auto bad_init_7 = [a{{1}}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from nested initializer list}}
template<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
template void pack_1<>(); // expected-note {{instantiation of}}
@@ -61,7 +62,7 @@
using T = decltype(c);
using T = const int &;
};
-auto b = [a{0}] {}; // expected-error {{include <initializer_list>}} expected-warning {{will change meaning in a future version of Clang}}
+auto b = [a{0}] {}; // OK, per N3922
struct S { S(); S(S&&); };
template<typename T> struct remove_reference { typedef T type; };
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 3f70ca7..22ea018 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple=x86_64-linux-gnu %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -triple=x86_64-linux-gnu %s -DCPP11ONLY
// C++11 [temp.arg.nontype]p1:
//
@@ -6,6 +7,8 @@
// be one of:
// -- an integral constant expression; or
// -- the name of a non-type template-parameter ; or
+#ifndef CPP11ONLY
+
namespace non_type_tmpl_param {
template <int N> struct X0 { X0(); };
template <int N> X0<N>::X0() { }
@@ -95,3 +98,14 @@
int* iptr = &i;
X0<iptr> x0b; // expected-error{{non-type template argument for template parameter of pointer type 'int *' must have its address taken}}
}
+#endif // CPP11ONLY
+
+namespace default_args {
+#ifdef CPP11ONLY
+namespace lambdas {
+template<int I = ([] { return 5; }())> //expected-error 2{{constant expression}} expected-note{{constant expression}}
+int f();
+}
+#endif // CPP11ONLY
+
+}
\ No newline at end of file
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
index 9fc4a58..86b2690 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Test instantiation of static data members declared out-of-line.
@@ -15,6 +17,9 @@
};
struct CannotInit { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
int &returnInt() { return X<int>::value; }
float &returnFloat() { return X<float>::value; }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index b0305dd..215f48d 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T>
struct X0 {
@@ -13,6 +15,9 @@
};
struct X2 { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
int& get_int() { return X0<int>::value; }
X1& get_X1() { return X0<X1>::value; }
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
index 5556f35..bfe08a6 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
@@ -1,11 +1,24 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<class X, class Y, class Z> X f(Y,Z); // expected-note {{candidate template ignored: couldn't infer template argument 'X'}}
void g() {
- f<int,char*,double>("aa",3.0); // expected-warning{{conversion from string literal to 'char *' is deprecated}}
- f<int,char*>("aa",3.0); // Z is deduced to be double \
- // expected-warning{{conversion from string literal to 'char *' is deprecated}}
+ f<int,char*,double>("aa",3.0);
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{conversion from string literal to 'char *' is deprecated}}
+#else
+ // expected-warning@-4{{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
+
+ f<int,char*>("aa",3.0); // Z is deduced to be double
+#if __cplusplus <= 199711L
+ // expected-warning@-2{{conversion from string literal to 'char *' is deprecated}}
+#else
+ // expected-warning@-4{{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
+
f<int>("aa",3.0); // Y is deduced to be char*, and
// Z is deduced to be double
f("aa",3.0); // expected-error{{no matching}}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
index 295f080..f46ea2e 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
@@ -139,7 +139,7 @@
}
namespace PR9233 {
- template<typename T> void f(const T **q); // expected-note{{candidate template ignored: substitution failure [with T = int]}}
+ template<typename T> void f(const T **q); // expected-note{{candidate template ignored: deduced type 'const int **' of 1st parameter does not match adjusted type 'int **' of argument [with T = int]}}
void g(int **p) {
f(p); // expected-error{{no matching function for call to 'f'}}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
index 782057d..b807a0f 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
@@ -55,7 +55,7 @@
}
namespace DeduceWithDefaultArgs {
- template<template<typename...> class Container> void f(Container<int>); // expected-note {{substitution failure [with Container = X]}}
+ template<template<typename...> class Container> void f(Container<int>); // expected-note {{deduced type 'X<[...], (default) int>' of 1st parameter does not match adjusted type 'X<[...], double>' of argument [with Container = X]}}
template<typename, typename = int> struct X {};
void g() {
// OK, use default argument for the second template parameter.
diff --git a/test/CXX/temp/temp.param/p3.cpp b/test/CXX/temp/temp.param/p3.cpp
index dc40c4b..c3c9339 100644
--- a/test/CXX/temp/temp.param/p3.cpp
+++ b/test/CXX/temp/temp.param/p3.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// A type-parameter defines its identifier to be a type-name (if
// declared with class or typename) or template-name (if declared with
@@ -16,6 +18,10 @@
// type-parameter (because its identifier is the name of an already
// existing class) is taken as a type-parameter. For example,
class T { /* ... */ }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
int i;
template<class T, T i> struct X2 {
diff --git a/test/CXX/temp/temp.res/temp.local/p3.cpp b/test/CXX/temp/temp.res/temp.local/p3.cpp
index d5e3786..63c40fb 100644
--- a/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -14,8 +14,7 @@
t->Derived::Base<T>::f();
t->Base<T>::f();
t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \
- // expected-error{{no member named 'f' in 'X0'}} \
- // expected-error{{'Base' is not a class, namespace, or enumeration}}
+ // expected-error{{no member named 'f' in 'X0'}}
}
};
diff --git a/test/CXX/temp/temp.res/temp.local/p6.cpp b/test/CXX/temp/temp.res/temp.local/p6.cpp
index eccbb89..843b455 100644
--- a/test/CXX/temp/temp.res/temp.local/p6.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p6.cpp
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y
+namespace N {}
+
template<typename T, // expected-note {{declared here}}
typename T> struct X {}; // expected-error {{declaration of 'T' shadows template parameter}}
-template<typename T> struct Y { // expected-note 15{{declared here}}
+template<typename T> struct Y { // expected-note 17{{declared here}}
template<typename T> struct A {}; // expected-error {{declaration of 'T' shadows template parameter}}
struct B {
@@ -50,10 +52,78 @@
void d() {
void T(); // expected-error {{declaration of 'T' shadows template parameter}}
}
+ void e() {
+ namespace T = N; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ // FIXME: These diagnostics are poorly worded. Lookup for the elaborated type
+ // specifier finds the template parameter in this case, which is ill-formed
+ // because it's not a struct.
+ void f() {
+ struct T *p; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
friend struct T; // expected-error {{declaration of 'T' shadows template parameter}}
};
+template<int T> struct Z { // expected-note 15{{declared here}}
+ template<typename T> struct A {}; // expected-error {{declaration of 'T' shadows template parameter}}
+
+ struct B {
+ template<typename> struct T {}; // FIXME: desired-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct C {
+ template<typename> void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct D {
+ struct T {}; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct E {
+ typedef int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct F {
+ using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct G {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct H {
+ static int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct I {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct J {
+ enum T { e }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct K {
+ enum E { T }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+
+ void a() {
+ extern int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void b() {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void c() {
+ try {}
+ catch (int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void d() {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void e() {
+ namespace T = N; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+
+ // These cases are valid when 'T' is a non-type template parameter, as T
+ // names an injected struct ::T, which doesn't shadow the template parameter.
+ void f() {
+ struct T *p;
+ }
+ friend struct T;
+};
+
template<typename T> // expected-note {{declared here}}
void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
index b426339..5a77d27 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct C { };
@@ -49,6 +51,9 @@
// Explicitly instantiate members of a class template
struct Incomplete; // expected-note{{forward declaration}}
struct NonDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
NonDefaultConstructible(int); // expected-note{{candidate constructor}}
};
diff --git a/test/CodeGen/2007-04-14-FNoBuiltin.c b/test/CodeGen/2007-04-14-FNoBuiltin.c
index 4d194b1..b95f41c 100644
--- a/test/CodeGen/2007-04-14-FNoBuiltin.c
+++ b/test/CodeGen/2007-04-14-FNoBuiltin.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin-printf -o - | FileCheck %s
// Check that -fno-builtin is honored.
extern int printf(const char*, ...);
diff --git a/test/CodeGen/3dnow-builtins.c b/test/CodeGen/3dnow-builtins.c
index 367c132..d534349 100644
--- a/test/CodeGen/3dnow-builtins.c
+++ b/test/CodeGen/3dnow-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnow -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnow -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnowa -emit-llvm -o - -Werror | FileCheck %s
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -10,126 +8,108 @@
__m64 test_m_pavgusb(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pavgusb
// CHECK: @llvm.x86.3dnow.pavgusb
- // CHECK-ASM: pavgusb %mm{{.*}}, %mm{{.*}}
return _m_pavgusb(m1, m2);
}
__m64 test_m_pf2id(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pf2id
// CHECK: @llvm.x86.3dnow.pf2id
- // CHECK-ASM: pf2id %mm{{.*}}, %mm{{.*}}
return _m_pf2id(m);
}
__m64 test_m_pfacc(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfacc
// CHECK: @llvm.x86.3dnow.pfacc
- // CHECK-ASM: pfacc %mm{{.*}}, %mm{{.*}}
return _m_pfacc(m1, m2);
}
__m64 test_m_pfadd(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfadd
// CHECK: @llvm.x86.3dnow.pfadd
- // CHECK-ASM: pfadd %mm{{.*}}, %mm{{.*}}
return _m_pfadd(m1, m2);
}
__m64 test_m_pfcmpeq(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfcmpeq
// CHECK: @llvm.x86.3dnow.pfcmpeq
- // CHECK-ASM: pfcmpeq %mm{{.*}}, %mm{{.*}}
return _m_pfcmpeq(m1, m2);
}
__m64 test_m_pfcmpge(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfcmpge
// CHECK: @llvm.x86.3dnow.pfcmpge
- // CHECK-ASM: pfcmpge %mm{{.*}}, %mm{{.*}}
return _m_pfcmpge(m1, m2);
}
__m64 test_m_pfcmpgt(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfcmpgt
// CHECK: @llvm.x86.3dnow.pfcmpgt
- // CHECK-ASM: pfcmpgt %mm{{.*}}, %mm{{.*}}
return _m_pfcmpgt(m1, m2);
}
__m64 test_m_pfmax(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfmax
// CHECK: @llvm.x86.3dnow.pfmax
- // CHECK-ASM: pfmax %mm{{.*}}, %mm{{.*}}
return _m_pfmax(m1, m2);
}
__m64 test_m_pfmin(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfmin
// CHECK: @llvm.x86.3dnow.pfmin
- // CHECK-ASM: pfmin %mm{{.*}}, %mm{{.*}}
return _m_pfmin(m1, m2);
}
__m64 test_m_pfmul(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfmul
// CHECK: @llvm.x86.3dnow.pfmul
- // CHECK-ASM: pfmul %mm{{.*}}, %mm{{.*}}
return _m_pfmul(m1, m2);
}
__m64 test_m_pfrcp(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pfrcp
// CHECK: @llvm.x86.3dnow.pfrcp
- // CHECK-ASM: pfrcp %mm{{.*}}, %mm{{.*}}
return _m_pfrcp(m);
}
__m64 test_m_pfrcpit1(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfrcpit1
// CHECK: @llvm.x86.3dnow.pfrcpit1
- // CHECK-ASM: pfrcpit1 %mm{{.*}}, %mm{{.*}}
return _m_pfrcpit1(m1, m2);
}
__m64 test_m_pfrcpit2(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfrcpit2
// CHECK: @llvm.x86.3dnow.pfrcpit2
- // CHECK-ASM: pfrcpit2 %mm{{.*}}, %mm{{.*}}
return _m_pfrcpit2(m1, m2);
}
__m64 test_m_pfrsqrt(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pfrsqrt
// CHECK: @llvm.x86.3dnow.pfrsqrt
- // CHECK-ASM: pfrsqrt %mm{{.*}}, %mm{{.*}}
return _m_pfrsqrt(m);
}
__m64 test_m_pfrsqrtit1(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfrsqrtit1
// CHECK: @llvm.x86.3dnow.pfrsqit1
- // CHECK-ASM: pfrsqit1 %mm{{.*}}, %mm{{.*}}
return _m_pfrsqrtit1(m1, m2);
}
__m64 test_m_pfsub(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfsub
// CHECK: @llvm.x86.3dnow.pfsub
- // CHECK-ASM: pfsub %mm{{.*}}, %mm{{.*}}
return _m_pfsub(m1, m2);
}
__m64 test_m_pfsubr(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfsubr
// CHECK: @llvm.x86.3dnow.pfsubr
- // CHECK-ASM: pfsubr %mm{{.*}}, %mm{{.*}}
return _m_pfsubr(m1, m2);
}
__m64 test_m_pi2fd(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pi2fd
// CHECK: @llvm.x86.3dnow.pi2fd
- // CHECK-ASM: pi2fd %mm{{.*}}, %mm{{.*}}
return _m_pi2fd(m);
}
@@ -142,41 +122,35 @@
__m64 test_m_pf2iw(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pf2iw
// CHECK: @llvm.x86.3dnowa.pf2iw
- // CHECK-ASM: pf2iw %mm{{.*}}, %mm{{.*}}
return _m_pf2iw(m);
}
__m64 test_m_pfnacc(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfnacc
// CHECK: @llvm.x86.3dnowa.pfnacc
- // CHECK-ASM: pfnacc %mm{{.*}}, %mm{{.*}}
return _m_pfnacc(m1, m2);
}
__m64 test_m_pfpnacc(__m64 m1, __m64 m2) {
// CHECK-LABEL: define i64 @test_m_pfpnacc
// CHECK: @llvm.x86.3dnowa.pfpnacc
- // CHECK-ASM: pfpnacc %mm{{.*}}, %mm{{.*}}
return _m_pfpnacc(m1, m2);
}
__m64 test_m_pi2fw(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pi2fw
// CHECK: @llvm.x86.3dnowa.pi2fw
- // CHECK-ASM: pi2fw %mm{{.*}}, %mm{{.*}}
return _m_pi2fw(m);
}
__m64 test_m_pswapdsf(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pswapdsf
// CHECK: @llvm.x86.3dnowa.pswapd
- // CHECK-ASM: pswapd %mm{{.*}}, %mm{{.*}}
return _m_pswapdsf(m);
}
__m64 test_m_pswapdsi(__m64 m) {
// CHECK-LABEL: define i64 @test_m_pswapdsi
// CHECK: @llvm.x86.3dnowa.pswapd
- // CHECK-ASM: pswapd %mm{{.*}}, %mm{{.*}}
return _m_pswapdsi(m);
}
diff --git a/test/CodeGen/aarch64-poly64.c b/test/CodeGen/aarch64-poly64.c
index a14162c..6ea3a2c 100644
--- a/test/CodeGen/aarch64-poly64.c
+++ b/test/CodeGen/aarch64-poly64.c
@@ -1,3 +1,6 @@
+// FIXME: This is a front-end test that depends on LLVM optimizations (-O3).
+// It should be split into separate files for front/middle/back-end testing.
+
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK \
@@ -77,7 +80,7 @@
poly64x2_t test_vcopyq_lane_p64(poly64x2_t a, poly64x1_t b) {
// CHECK-LABEL: test_vcopyq_lane_p64
return vcopyq_lane_p64(a, 1, b, 0);
- // CHECK: ins {{v[0-9]+}}.d[1], {{v[0-9]+}}.d[0]
+ // CHECK: zip1 v0.2d, v0.2d, v1.2d
}
poly64x2_t test_vcopyq_laneq_p64(poly64x2_t a, poly64x2_t b) {
diff --git a/test/CodeGen/aarch64-v8.1a-neon-intrinsics.c b/test/CodeGen/aarch64-v8.1a-neon-intrinsics.c
new file mode 100644
index 0000000..ad5d5dd
--- /dev/null
+++ b/test/CodeGen/aarch64-v8.1a-neon-intrinsics.c
@@ -0,0 +1,198 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon \
+// RUN: -target-feature +v8.1a -S -emit-llvm -o - %s | FileCheck %s
+
+ #include <arm_neon.h>
+
+// CHECK-LABEL: test_vqrdmlah_laneq_s16
+int16x4_t test_vqrdmlah_laneq_s16(int16x4_t a, int16x4_t b, int16x8_t v) {
+// CHECK: shufflevector <8 x i16> {{%.*}}, <8 x i16> {{%.*}}, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK: call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlah_laneq_s16(a, b, v, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlah_laneq_s32
+int32x2_t test_vqrdmlah_laneq_s32(int32x2_t a, int32x2_t b, int32x4_t v) {
+// CHECK: shufflevector <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <2 x i32> <i32 3, i32 3>
+// CHECK: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK: call <2 x i32> @llvm.aarch64.neon.sqadd.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlah_laneq_s32(a, b, v, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_laneq_s16
+int16x8_t test_vqrdmlahq_laneq_s16(int16x8_t a, int16x8_t b, int16x8_t v) {
+// CHECK: shufflevector <8 x i16> {{%.*}}, <8 x i16> {{%.*}}, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK: call <8 x i16> @llvm.aarch64.neon.sqadd.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlahq_laneq_s16(a, b, v, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_laneq_s32
+int32x4_t test_vqrdmlahq_laneq_s32(int32x4_t a, int32x4_t b, int32x4_t v) {
+// CHECK: shufflevector <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK: call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlahq_laneq_s32(a, b, v, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlahh_s16
+int16_t test_vqrdmlahh_s16(int16_t a, int16_t b, int16_t c) {
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[add:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[add]], i64 0
+ return vqrdmlahh_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlahs_s32
+int32_t test_vqrdmlahs_s32(int32_t a, int32_t b, int32_t c) {
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqadd.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlahs_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlahh_lane_s16
+int16_t test_vqrdmlahh_lane_s16(int16_t a, int16_t b, int16x4_t c) {
+// CHECK: extractelement <4 x i16> {{%.*}}, i32 3
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[add:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[add]], i64 0
+ return vqrdmlahh_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlahs_lane_s32
+int32_t test_vqrdmlahs_lane_s32(int32_t a, int32_t b, int32x2_t c) {
+// CHECK: extractelement <2 x i32> {{%.*}}, i32 1
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqadd.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlahs_lane_s32(a, b, c, 1);
+}
+
+// CHECK-LABEL: test_vqrdmlahh_laneq_s16
+int16_t test_vqrdmlahh_laneq_s16(int16_t a, int16_t b, int16x8_t c) {
+// CHECK: extractelement <8 x i16> {{%.*}}, i32 7
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[add:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[add]], i64 0
+ return vqrdmlahh_laneq_s16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlahs_laneq_s32
+int32_t test_vqrdmlahs_laneq_s32(int32_t a, int32_t b, int32x4_t c) {
+// CHECK: extractelement <4 x i32> {{%.*}}, i32 3
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqadd.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlahs_laneq_s32(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_laneq_s16
+int16x4_t test_vqrdmlsh_laneq_s16(int16x4_t a, int16x4_t b, int16x8_t v) {
+// CHECK: shufflevector <8 x i16> {{%.*}}, <8 x i16> {{%.*}}, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK: call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlsh_laneq_s16(a, b, v, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_laneq_s32
+int32x2_t test_vqrdmlsh_laneq_s32(int32x2_t a, int32x2_t b, int32x4_t v) {
+// CHECK: shufflevector <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <2 x i32> <i32 3, i32 3>
+// CHECK: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK: call <2 x i32> @llvm.aarch64.neon.sqsub.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlsh_laneq_s32(a, b, v, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_laneq_s16
+int16x8_t test_vqrdmlshq_laneq_s16(int16x8_t a, int16x8_t b, int16x8_t v) {
+// CHECK: shufflevector <8 x i16> {{%.*}}, <8 x i16> {{%.*}}, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK: call <8 x i16> @llvm.aarch64.neon.sqsub.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlshq_laneq_s16(a, b, v, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_laneq_s32
+int32x4_t test_vqrdmlshq_laneq_s32(int32x4_t a, int32x4_t b, int32x4_t v) {
+// CHECK: shufflevector <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK: call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlshq_laneq_s32(a, b, v, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlshh_s16
+int16_t test_vqrdmlshh_s16(int16_t a, int16_t b, int16_t c) {
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[sub:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[sub]], i64 0
+ return vqrdmlshh_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlshs_s32
+int32_t test_vqrdmlshs_s32(int32_t a, int32_t b, int32_t c) {
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqsub.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlshs_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlshh_lane_s16
+int16_t test_vqrdmlshh_lane_s16(int16_t a, int16_t b, int16x4_t c) {
+// CHECK: extractelement <4 x i16> {{%.*}}, i32 3
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[sub:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[sub]], i64 0
+ return vqrdmlshh_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlshs_lane_s32
+int32_t test_vqrdmlshs_lane_s32(int32_t a, int32_t b, int32x2_t c) {
+// CHECK: extractelement <2 x i32> {{%.*}}, i32 1
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqsub.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlshs_lane_s32(a, b, c, 1);
+}
+
+// CHECK-LABEL: test_vqrdmlshh_laneq_s16
+int16_t test_vqrdmlshh_laneq_s16(int16_t a, int16_t b, int16x8_t c) {
+// CHECK: extractelement <8 x i16> {{%.*}}, i32 7
+// CHECK: [[insb:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insc:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[mul:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[insb]], <4 x i16> [[insc]])
+// CHECK: extractelement <4 x i16> [[mul]], i64 0
+// CHECK: [[insa:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[insmul:%.*]] = insertelement <4 x i16> undef, i16 {{%.*}}, i64 0
+// CHECK: [[sub:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> [[insa]], <4 x i16> [[insmul]])
+// CHECK: extractelement <4 x i16> [[sub]], i64 0
+ return vqrdmlshh_laneq_s16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vqrdmlshs_laneq_s32
+int32_t test_vqrdmlshs_laneq_s32(int32_t a, int32_t b, int32x4_t c) {
+// CHECK: extractelement <4 x i32> {{%.*}}, i32 3
+// CHECK: call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 {{%.*}}, i32 {{%.*}})
+// CHECK: call i32 @llvm.aarch64.neon.sqsub.i32(i32 {{%.*}}, i32 {{%.*}})
+ return vqrdmlshs_laneq_s32(a, b, c, 3);
+}
diff --git a/test/CodeGen/arm-abi-vector.c b/test/CodeGen/arm-abi-vector.c
index 9920332..8d113d6 100644
--- a/test/CodeGen/arm-abi-vector.c
+++ b/test/CodeGen/arm-abi-vector.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi aapcs -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi apcs-gnu -emit-llvm -o - %s | FileCheck -check-prefix=APCS-GNU %s
+// RUN: %clang_cc1 -triple arm-linux-androideabi -emit-llvm -o - %s | FileCheck -check-prefix=ANDROID %s
#include <stdarg.h>
@@ -28,6 +29,14 @@
// APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <2 x i32>*
// APCS-GNU: [[VEC:%.*]] = load <2 x i32>, <2 x i32>* [[AP_CAST]], align 4
// APCS-GNU: store <2 x i32> [[VEC]], <2 x i32>* [[VAR]], align 8
+// ANDROID: varargs_vec_2i
+// ANDROID: [[VAR:%.*]] = alloca <2 x i32>, align 8
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8
+// ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <2 x i32>*
+// ANDROID: [[VEC:%.*]] = load <2 x i32>, <2 x i32>* [[AP_CAST]], align 8
+// ANDROID: store <2 x i32> [[VEC]], <2 x i32>* [[VAR]], align 8
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -42,6 +51,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
// APCS-GNU: test_2i
// APCS-GNU: call double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
+// ANDROID: test_2i
+// ANDROID: call double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
return varargs_vec_2i(3, *in);
}
@@ -54,6 +65,10 @@
// APCS-GNU: alloca <3 x i8>, align 4
// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4
// APCS-GNU: bitcast i8* [[AP]] to <3 x i8>*
+// ANDROID: varargs_vec_3c
+// ANDROID: alloca <3 x i8>, align 4
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4
+// ANDROID: bitcast i8* [[AP]] to <3 x i8>*
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -68,6 +83,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}})
// APCS-GNU: test_3c
// APCS-GNU: call double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}})
+// ANDROID: test_3c
+// ANDROID: call double (i32, ...) @varargs_vec_3c(i32 3, <3 x i8> {{%.*}})
return varargs_vec_3c(3, *in);
}
@@ -87,6 +104,14 @@
// APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <5 x i8>*
// APCS-GNU: [[VEC:%.*]] = load <5 x i8>, <5 x i8>* [[AP_CAST]], align 4
// APCS-GNU: store <5 x i8> [[VEC]], <5 x i8>* [[VAR]], align 8
+// ANDROID: varargs_vec_5c
+// ANDROID: [[VAR:%.*]] = alloca <5 x i8>, align 8
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8
+// ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i8>*
+// ANDROID: [[VEC:%.*]] = load <5 x i8>, <5 x i8>* [[AP_CAST]], align 8
+// ANDROID: store <5 x i8> [[VEC]], <5 x i8>* [[VAR]], align 8
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -101,6 +126,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
// APCS-GNU: test_5c
// APCS-GNU: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+// ANDROID: test_5c
+// ANDROID: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
return varargs_vec_5c(5, *in);
}
@@ -120,6 +147,14 @@
// APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <9 x i8>*
// APCS-GNU: [[VEC:%.*]] = load <9 x i8>, <9 x i8>* [[AP_CAST]], align 4
// APCS-GNU: store <9 x i8> [[VEC]], <9 x i8>* [[VAR]], align 16
+// ANDROID: varargs_vec_9c
+// ANDROID: [[VAR:%.*]] = alloca <9 x i8>, align 16
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16
+// ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <9 x i8>*
+// ANDROID: [[T0:%.*]] = load <9 x i8>, <9 x i8>* [[AP_CAST]], align 8
+// ANDROID: store <9 x i8> [[T0]], <9 x i8>* [[VAR]], align 16
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -134,6 +169,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
// APCS-GNU: test_9c
// APCS-GNU: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+// ANDROID: test_9c
+// ANDROID: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
return varargs_vec_9c(9, *in);
}
@@ -146,6 +183,10 @@
// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4
// APCS-GNU: [[VAR:%.*]] = bitcast i8* [[AP]] to <19 x i8>**
// APCS-GNU: [[VAR2:%.*]] = load <19 x i8>*, <19 x i8>** [[VAR]]
+// ANDROID: varargs_vec_19c
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4
+// ANDROID: [[VAR:%.*]] = bitcast i8* [[AP]] to <19 x i8>**
+// ANDROID: [[VAR2:%.*]] = load <19 x i8>*, <19 x i8>** [[VAR]]
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -160,6 +201,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
// APCS-GNU: test_19c
// APCS-GNU: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+// ANDROID: test_19c
+// ANDROID: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
return varargs_vec_19c(19, *in);
}
@@ -176,6 +219,12 @@
// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 8
// APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <3 x i16>*
// APCS-GNU: [[VEC:%.*]] = load <3 x i16>, <3 x i16>* [[AP_CAST]], align 4
+// ANDROID: varargs_vec_3s
+// ANDROID: alloca <3 x i16>, align 8
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8
+// ANDROID: bitcast i8* [[AP_ALIGN]] to <3 x i16>*
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -190,6 +239,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
// APCS-GNU: test_3s
// APCS-GNU: call double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+// ANDROID: test_3s
+// ANDROID: call double (i32, ...) @varargs_vec_3s(i32 3, <3 x i16> {{%.*}})
return varargs_vec_3s(3, *in);
}
@@ -208,6 +259,14 @@
// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 16
// APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <5 x i16>*
// APCS-GNU: [[VEC:%.*]] = load <5 x i16>, <5 x i16>* [[AP_CAST]], align 4
+// ANDROID: varargs_vec_5s
+// ANDROID: [[VAR_ALIGN:%.*]] = alloca <5 x i16>, align 16
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16
+// ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i16>*
+// ANDROID: [[VEC:%.*]] = load <5 x i16>, <5 x i16>* [[AP_CAST]], align 8
+// ANDROID: store <5 x i16> [[VEC]], <5 x i16>* [[VAR_ALIGN]], align 16
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -222,6 +281,8 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
// APCS-GNU: test_5s
// APCS-GNU: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+// ANDROID: test_5s
+// ANDROID: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
return varargs_vec_5s(5, *in);
}
@@ -243,6 +304,11 @@
// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* {{%.*}}, i32 16
// APCS-GNU: bitcast %struct.StructWithVec* [[VAR_ALIGN]] to i8*
// APCS-GNU: call void @llvm.memcpy
+// ANDROID: varargs_struct
+// ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16
+// ANDROID: bitcast i8* [[AP_ALIGN]] to %struct.StructWithVec*
va_list ap;
double sum = fixed;
va_start(ap, fixed);
@@ -257,5 +323,7 @@
// CHECK: call arm_aapcscc double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}})
// APCS-GNU: test_struct
// APCS-GNU: call double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}})
+// ANDROID: test_struct
+// ANDROID: call double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}})
return varargs_struct(3, *d);
}
diff --git a/test/CodeGen/arm-target-features.c b/test/CodeGen/arm-target-features.c
index 1629c94..7829edf 100644
--- a/test/CodeGen/arm-target-features.c
+++ b/test/CodeGen/arm-target-features.c
@@ -22,9 +22,11 @@
// RUN: %clang_cc1 -triple thumbv7s-apple-ios7.0 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a35 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple armv8-linux-gnueabi -target-cpu cortex-a53 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a72 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m1 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// CHECK-BASIC-V8: "target-features"="+crc,+crypto,+dsp,+fp-armv8,+hwdiv,+hwdiv-arm,+neon"
diff --git a/test/CodeGen/arm-v8.1a-neon-intrinsics.c b/test/CodeGen/arm-v8.1a-neon-intrinsics.c
new file mode 100644
index 0000000..7888831
--- /dev/null
+++ b/test/CodeGen/arm-v8.1a-neon-intrinsics.c
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -triple armv8.1a-linux-gnu -target-feature +neon \
+// RUN: -S -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
+
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon \
+// RUN: -target-feature +v8.1a -S -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
+
+// REQUIRES: arm-registered-target,aarch64-registered-target
+
+#include <arm_neon.h>
+
+// CHECK-LABEL: test_vqrdmlah_s16
+int16x4_t test_vqrdmlah_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqadds.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlah_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlah_s32
+int32x2_t test_vqrdmlah_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqadds.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqadd.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlah_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_s16
+int16x8_t test_vqrdmlahq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqadds.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqadd.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlahq_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_s32
+int32x4_t test_vqrdmlahq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlahq_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlah_lane_s16
+int16x4_t test_vqrdmlah_lane_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+// CHECK-ARM: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqadds.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlah_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlah_lane_s32
+int32x2_t test_vqrdmlah_lane_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+// CHECK-ARM: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> <i32 1, i32 1>
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqadds.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> <i32 1, i32 1>
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqadd.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlah_lane_s32(a, b, c, 1);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_lane_s16
+int16x8_t test_vqrdmlahq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t c) {
+// CHECK-ARM: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqadds.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqadd.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlahq_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlahq_lane_s32
+int32x4_t test_vqrdmlahq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t c) {
+// CHECK-ARM: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlahq_lane_s32(a, b, c, 1);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_s16
+int16x4_t test_vqrdmlsh_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqsubs.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlsh_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_s32
+int32x2_t test_vqrdmlsh_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqsubs.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqsub.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlsh_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_s16
+int16x8_t test_vqrdmlshq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqsubs.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqsub.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlshq_s16(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_s32
+int32x4_t test_vqrdmlshq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlshq_s32(a, b, c);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_lane_s16
+int16x4_t test_vqrdmlsh_lane_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
+// CHECK-ARM: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-ARM: call <4 x i16> @llvm.arm.neon.vqsubs.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+// CHECK-AARCH64: call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> {{%.*}}, <4 x i16> {{%.*}})
+ return vqrdmlsh_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlsh_lane_s32
+int32x2_t test_vqrdmlsh_lane_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
+// CHECK-ARM: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> <i32 1, i32 1>
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-ARM: call <2 x i32> @llvm.arm.neon.vqsubs.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> <i32 1, i32 1>
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+// CHECK-AARCH64: call <2 x i32> @llvm.aarch64.neon.sqsub.v2i32(<2 x i32> {{%.*}}, <2 x i32> {{%.*}})
+ return vqrdmlsh_lane_s32(a, b, c, 1);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_lane_s16
+int16x8_t test_vqrdmlshq_lane_s16(int16x8_t a, int16x8_t b, int16x4_t c) {
+// CHECK-ARM: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-ARM: call <8 x i16> @llvm.arm.neon.vqsubs.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+// CHECK-AARCH64: call <8 x i16> @llvm.aarch64.neon.sqsub.v8i16(<8 x i16> {{%.*}}, <8 x i16> {{%.*}})
+ return vqrdmlshq_lane_s16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vqrdmlshq_lane_s32
+int32x4_t test_vqrdmlshq_lane_s32(int32x4_t a, int32x4_t b, int32x2_t c) {
+// CHECK-ARM: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-ARM: call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+
+// CHECK-AARCH64: shufflevector <2 x i32> {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+// CHECK-AARCH64: call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> {{%.*}}, <4 x i32> {{%.*}})
+ return vqrdmlshq_lane_s32(a, b, c, 1);
+}
diff --git a/test/CodeGen/arm_acle.c b/test/CodeGen/arm_acle.c
index a2eb900..0884394 100644
--- a/test/CodeGen/arm_acle.c
+++ b/test/CodeGen/arm_acle.c
@@ -186,27 +186,53 @@
// ARM-LABEL: test_rev16
// ARM: llvm.bswap
-// ARM: lshr
-// ARM: shl
+// ARM: lshr {{.*}}, 16
+// ARM: shl {{.*}}, 16
// ARM: or
uint32_t test_rev16(uint32_t t) {
return __rev16(t);
}
// ARM-LABEL: test_rev16l
-// ARM: llvm.bswap
-// ARM: lshr
-// ARM: shl
-// ARM: or
+// AArch32: llvm.bswap
+// AArch32: lshr {{.*}}, 16
+// AArch32: shl {{.*}}, 16
+// AArch32: or
+// AArch64: [[T1:%.*]] = lshr i64 [[IN:%.*]], 32
+// AArch64: [[T2:%.*]] = trunc i64 [[T1]] to i32
+// AArch64: [[T3:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[T2]])
+// AArch64: [[T4:%.*]] = lshr i32 [[T3]], 16
+// AArch64: [[T5:%.*]] = shl i32 [[T3]], 16
+// AArch64: [[T6:%.*]] = or i32 [[T5]], [[T4]]
+// AArch64: [[T7:%.*]] = zext i32 [[T6]] to i64
+// AArch64: [[T8:%.*]] = shl nuw i64 [[T7]], 32
+// AArch64: [[T9:%.*]] = trunc i64 [[IN]] to i32
+// AArch64: [[T10:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[T9]])
+// AArch64: [[T11:%.*]] = lshr i32 [[T10]], 16
+// AArch64: [[T12:%.*]] = shl i32 [[T10]], 16
+// AArch64: [[T13:%.*]] = or i32 [[T12]], [[T11]]
+// AArch64: [[T14:%.*]] = zext i32 [[T13]] to i64
+// AArch64: [[T15:%.*]] = or i64 [[T8]], [[T14]]
long test_rev16l(long t) {
return __rev16l(t);
}
// ARM-LABEL: test_rev16ll
-// ARM: llvm.bswap
-// ARM: lshr
-// ARM: shl
-// ARM: or
+// ARM: [[T1:%.*]] = lshr i64 [[IN:%.*]], 32
+// ARM: [[T2:%.*]] = trunc i64 [[T1]] to i32
+// ARM: [[T3:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[T2]])
+// ARM: [[T4:%.*]] = lshr i32 [[T3]], 16
+// ARM: [[T5:%.*]] = shl i32 [[T3]], 16
+// ARM: [[T6:%.*]] = or i32 [[T5]], [[T4]]
+// ARM: [[T7:%.*]] = zext i32 [[T6]] to i64
+// ARM: [[T8:%.*]] = shl nuw i64 [[T7]], 32
+// ARM: [[T9:%.*]] = trunc i64 [[IN]] to i32
+// ARM: [[T10:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[T9]])
+// ARM: [[T11:%.*]] = lshr i32 [[T10]], 16
+// ARM: [[T12:%.*]] = shl i32 [[T10]], 16
+// ARM: [[T13:%.*]] = or i32 [[T12]], [[T11]]
+// ARM: [[T14:%.*]] = zext i32 [[T13]] to i64
+// ARM: [[T15:%.*]] = or i64 [[T8]], [[T14]]
uint64_t test_rev16ll(uint64_t t) {
return __rev16ll(t);
}
diff --git a/test/CodeGen/asm-unicode.S b/test/CodeGen/asm-unicode.S
new file mode 100644
index 0000000..f4edbe9
--- /dev/null
+++ b/test/CodeGen/asm-unicode.S
@@ -0,0 +1,12 @@
+// RUN: %clang -S %s -o - | FileCheck %s
+.macro my_macro, trace=1, uaccess=1
+.if \uaccess
+// CHECK: .if \uaccess
+// CHECK-NOT: .if 곎ss
+// CHECK: my_macro trace=1
+ my_macro trace=1
+.endif
+.endm
+
+foo:
+ my_macro trace=0
diff --git a/test/CodeGen/atomic-ops-libcall.c b/test/CodeGen/atomic-ops-libcall.c
index 5b9ba46..0093a8c 100644
--- a/test/CodeGen/atomic-ops-libcall.c
+++ b/test/CodeGen/atomic-ops-libcall.c
@@ -74,36 +74,43 @@
int test_atomic_add_fetch(int *p) {
// CHECK: test_atomic_add_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_add_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_add_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: {{%[^ ]*}} = add i32 [[CALL]], 55
return __atomic_add_fetch(p, 55, memory_order_seq_cst);
}
int test_atomic_sub_fetch(int *p) {
// CHECK: test_atomic_sub_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_sub_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_sub_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: {{%[^ ]*}} = add i32 [[CALL]], -55
return __atomic_sub_fetch(p, 55, memory_order_seq_cst);
}
int test_atomic_and_fetch(int *p) {
// CHECK: test_atomic_and_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_and_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_and_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: {{%[^ ]*}} = and i32 [[CALL]], 55
return __atomic_and_fetch(p, 55, memory_order_seq_cst);
}
int test_atomic_or_fetch(int *p) {
// CHECK: test_atomic_or_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_or_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_or_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: {{%[^ ]*}} = or i32 [[CALL]], 55
return __atomic_or_fetch(p, 55, memory_order_seq_cst);
}
int test_atomic_xor_fetch(int *p) {
// CHECK: test_atomic_xor_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_xor_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_xor_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: {{%[^ ]*}} = xor i32 [[CALL]], 55
return __atomic_xor_fetch(p, 55, memory_order_seq_cst);
}
int test_atomic_nand_fetch(int *p) {
// CHECK: test_atomic_nand_fetch
- // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_nand_fetch_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_nand_4(i8* {{%[0-9]+}}, i32 55, i32 5)
+ // CHECK: [[OR:%[^ ]*]] = or i32 [[CALL]], -56
+ // CHECK: {{%[^ ]*}} = xor i32 [[OR]], 55
return __atomic_nand_fetch(p, 55, memory_order_seq_cst);
}
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
index 353f77c..1ebb2ba 100644
--- a/test/CodeGen/atomic-ops.c
+++ b/test/CodeGen/atomic-ops.c
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -triple=i686-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -ffake-address-space-map -triple=i686-apple-darwin9 | FileCheck %s
// REQUIRES: x86-registered-target
// Also test serialization of atomic operations here, to avoid duplicating the
// test.
-// RUN: %clang_cc1 %s -emit-pch -o %t -ffreestanding -triple=i686-apple-darwin9
-// RUN: %clang_cc1 %s -include-pch %t -ffreestanding -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-pch -o %t -ffreestanding -ffake-address-space-map -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -include-pch %t -ffreestanding -ffake-address-space-map -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s
#ifndef ALREADY_INCLUDED
#define ALREADY_INCLUDED
@@ -155,6 +155,14 @@
return atomic_compare_exchange_strong(i, &cmp, 1);
}
+#define _AS1 __attribute__((address_space(1)))
+_Bool fi4d(_Atomic(int) *i, int _AS1 *ptr2) {
+ // CHECK-LABEL: @fi4d(
+ // CHECK: [[EXPECTED:%[.0-9A-Z_a-z]+]] = load i32, i32 addrspace(1)* %{{[0-9]+}}
+ // CHECK: cmpxchg i32* %{{[0-9]+}}, i32 [[EXPECTED]], i32 %{{[0-9]+}} acquire acquire
+ return __c11_atomic_compare_exchange_strong(i, ptr2, 1, memory_order_acquire, memory_order_acquire);
+}
+
float ff1(_Atomic(float) *d) {
// CHECK-LABEL: @ff1
// CHECK: load atomic i32, i32* {{.*}} monotonic
diff --git a/test/CodeGen/attr-disable-tail-calls.c b/test/CodeGen/attr-disable-tail-calls.c
index 8141349..d47b14f 100644
--- a/test/CodeGen/attr-disable-tail-calls.c
+++ b/test/CodeGen/attr-disable-tail-calls.c
@@ -1,11 +1,19 @@
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -mdisable-tail-calls -o - | FileCheck %s -check-prefix=CHECK -check-prefix=DISABLE
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECK -check-prefix=ENABLE
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -mdisable-tail-calls -o - | FileCheck %s -check-prefix=DISABLE
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s -check-prefix=ENABLE
-// CHECK: define i32 @f1() [[ATTR:#[0-9]+]] {
+// DISABLE: define i32 @f1() [[ATTRTRUE:#[0-9]+]] {
+// DISABLE: define i32 @f2() [[ATTRTRUE]] {
+// ENABLE: define i32 @f1() [[ATTRFALSE:#[0-9]+]] {
+// ENABLE: define i32 @f2() [[ATTRTRUE:#[0-9]+]] {
int f1() {
return 0;
}
-// DISABLE: attributes [[ATTR]] = { {{.*}} "disable-tail-calls"="true" {{.*}} }
-// ENABLE: attributes [[ATTR]] = { {{.*}} "disable-tail-calls"="false" {{.*}} }
+int f2() __attribute__((disable_tail_calls)) {
+ return 0;
+}
+
+// DISABLE: attributes [[ATTRTRUE]] = { {{.*}}"disable-tail-calls"="true"{{.*}} }
+// ENABLE: attributes [[ATTRFALSE]] = { {{.*}}"disable-tail-calls"="false"{{.*}} }
+// ENABLE: attributes [[ATTRTRUE]] = { {{.*}}"disable-tail-calls"="true"{{.*}} }
diff --git a/test/CodeGen/attr-minsize.cpp b/test/CodeGen/attr-minsize.cpp
index 0f07725..1e5c634 100644
--- a/test/CodeGen/attr-minsize.cpp
+++ b/test/CodeGen/attr-minsize.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -Oz -emit-llvm %s -o - | FileCheck %s -check-prefix=Oz
-// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
-// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
-// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
-// RUN: %clang_cc1 -O3 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
-// RUN: %clang_cc1 -Os -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -Oz -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=Oz
+// RUN: %clang_cc1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -O1 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -O2 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -O3 -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// RUN: %clang_cc1 -Os -disable-llvm-optzns -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// Check that we set the minsize attribute on each function
// when Oz optimization level is set.
diff --git a/test/CodeGen/attr-x86-interrupt.c b/test/CodeGen/attr-x86-interrupt.c
new file mode 100644
index 0000000..dcc8ab6
--- /dev/null
+++ b/test/CodeGen/attr-x86-interrupt.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_LINUX
+// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_WIN
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_WIN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+
+#ifdef __x86_64__
+typedef __UINT64_TYPE__ uword;
+#else
+typedef __UINT32_TYPE__ uword;
+#endif
+
+__attribute__((interrupt)) void foo7(int *a, uword b) {}
+__attribute__((interrupt)) void foo8(int *a) {}
+// X86_64_LINUX: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i64)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_64_LINUX: define x86_intrcc void @foo7(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_LINUX: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_LINUX: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i32)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_LINUX: define x86_intrcc void @foo7(i32* %{{.+}}, i32 %{{.+}})
+// X86_LINUX: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_64_WIN: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i64)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_64_WIN: define x86_intrcc void @foo7(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_WIN: define x86_intrcc void @foo8(i32* %{{.+}})
+// X86_WIN: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32*, i32)* @foo7 to i8*), i8* bitcast (void (i32*)* @foo8 to i8*)], section "llvm.metadata"
+// X86_WIN: define x86_intrcc void @foo7(i32* %{{.+}}, i32 %{{.+}})
+// X86_WIN: define x86_intrcc void @foo8(i32* %{{.+}})
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index 3f710c1..89981bb 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -1,9 +1,5 @@
-// REQUIRES: x86-registered-target
-
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Werror | FileCheck %s
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx2 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx2 -fno-signed-char -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -12,210 +8,172 @@
__m256i test_mm256_mpsadbw_epu8(__m256i x, __m256i y) {
// CHECK: @llvm.x86.avx2.mpsadbw({{.*}}, {{.*}}, i8 3)
- // CHECK-ASM: vmpsadbw $3, %ymm{{.*}}
return _mm256_mpsadbw_epu8(x, y, 3);
}
__m256i test_mm256_sad_epu8(__m256i x, __m256i y) {
// CHECK: @llvm.x86.avx2.psad.bw
- // CHECK-ASM: vpsadbw %ymm{{.*}}
return _mm256_sad_epu8(x, y);
}
__m256i test_mm256_abs_epi8(__m256i a) {
// CHECK: @llvm.x86.avx2.pabs.b
- // CHECK-ASM: vpabsb %ymm{{.*}}
return _mm256_abs_epi8(a);
}
__m256i test_mm256_abs_epi16(__m256i a) {
// CHECK: @llvm.x86.avx2.pabs.w
- // CHECK-ASM: vpabsw %ymm{{.*}}
return _mm256_abs_epi16(a);
}
__m256i test_mm256_abs_epi32(__m256i a) {
// CHECK: @llvm.x86.avx2.pabs.d
- // CHECK-ASM: vpabsd %ymm{{.*}}
return _mm256_abs_epi32(a);
}
__m256i test_mm256_packs_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.packsswb
- // CHECK-ASM: vpacksswb %ymm{{.*}}
return _mm256_packs_epi16(a, b);
}
__m256i test_mm256_packs_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.packssdw
- // CHECK-ASM: vpackssdw %ymm{{.*}}
return _mm256_packs_epi32(a, b);
}
__m256i test_mm256_packs_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.packuswb
- // CHECK-ASM: vpackuswb %ymm{{.*}}
return _mm256_packus_epi16(a, b);
}
__m256i test_mm256_packs_epu32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.packusdw
- // CHECK-ASM: vpackusdw %ymm{{.*}}
return _mm256_packus_epi32(a, b);
}
__m256i test_mm256_add_epi8(__m256i a, __m256i b) {
// CHECK: add <32 x i8>
- // CHECK-ASM: vpaddb %ymm{{.*}}
return _mm256_add_epi8(a, b);
}
__m256i test_mm256_add_epi16(__m256i a, __m256i b) {
// CHECK: add <16 x i16>
- // CHECK-ASM: vpaddw %ymm{{.*}}
return _mm256_add_epi16(a, b);
}
__m256i test_mm256_add_epi32(__m256i a, __m256i b) {
// CHECK: add <8 x i32>
- // CHECK-ASM: vpaddd %ymm{{.*}}
return _mm256_add_epi32(a, b);
}
__m256i test_mm256_add_epi64(__m256i a, __m256i b) {
// CHECK: add <4 x i64>
- // CHECK-ASM: vpaddq {{.*}}, %ymm{{.*}}
return _mm256_add_epi64(a, b);
}
__m256i test_mm256_adds_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.padds.b
- // CHECK-ASM: vpaddsb %ymm{{.*}}
return _mm256_adds_epi8(a, b);
}
__m256i test_mm256_adds_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.padds.w
- // CHECK-ASM: vpaddsw %ymm{{.*}}
return _mm256_adds_epi16(a, b);
}
__m256i test_mm256_adds_epu8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.paddus.b
- // CHECK-ASM: vpaddusb %ymm{{.*}}
return _mm256_adds_epu8(a, b);
}
__m256i test_mm256_adds_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.paddus.w
- // CHECK-ASM: vpaddusw %ymm{{.*}}
return _mm256_adds_epu16(a, b);
}
__m256i test_mm256_alignr_epi8(__m256i a, __m256i b) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 32, i32 33, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 48, i32 49>
- // CHECK-ASM: vpalignr $2, %ymm{{.*}}
return _mm256_alignr_epi8(a, b, 2);
}
__m256i test2_mm256_alignr_epi8(__m256i a, __m256i b) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> zeroinitializer, <32 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 32, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 48>
- // CHECK-ASM: vpsrldq $1, %ymm{{.*}}
return _mm256_alignr_epi8(a, b, 17);
}
__m256i test_mm256_sub_epi8(__m256i a, __m256i b) {
// CHECK: sub <32 x i8>
- // CHECK-ASM: vpsubb %ymm{{.*}}
return _mm256_sub_epi8(a, b);
}
__m256i test_mm256_sub_epi16(__m256i a, __m256i b) {
// CHECK: sub <16 x i16>
- // CHECK-ASM: vpsubw %ymm{{.*}}
return _mm256_sub_epi16(a, b);
}
__m256i test_mm256_sub_epi32(__m256i a, __m256i b) {
// CHECK: sub <8 x i32>
- // CHECK-ASM: vpsubd %ymm{{.*}}
return _mm256_sub_epi32(a, b);
}
__m256i test_mm256_sub_epi64(__m256i a, __m256i b) {
// CHECK: sub <4 x i64>
- // CHECK-ASM: vpsubq {{.*}}, %ymm{{.*}}
return _mm256_sub_epi64(a, b);
}
__m256i test_mm256_subs_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psubs.b
- // CHECK-ASM: vpsubsb %ymm{{.*}}
return _mm256_subs_epi8(a, b);
}
__m256i test_mm256_subs_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psubs.w
- // CHECK-ASM: vpsubsw %ymm{{.*}}
return _mm256_subs_epi16(a, b);
}
__m256i test_mm256_subs_epu8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psubus.b
- // CHECK-ASM: vpsubusb %ymm{{.*}}
return _mm256_subs_epu8(a, b);
}
__m256i test_mm256_subs_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psubus.w
- // CHECK-ASM: vpsubusw %ymm{{.*}}
return _mm256_subs_epu16(a, b);
}
__m256i test_mm256_and_si256(__m256i a, __m256i b) {
// CHECK: and <4 x i64>
- // CHECK-ASM: vandps {{.*}}, %ymm{{.*}}
return _mm256_and_si256(a, b);
}
__m256i test_mm256_andnot_si256(__m256i a, __m256i b) {
// CHECK: xor <4 x i64>
// CHECK: and <4 x i64>
-
- // Note that, at -O0, we generate the expansion instead of matching vpandn.
- // CHECK-ASM: vpcmpeqd [[ALLONES:%ymm[0-9]+]], [[ALLONES]], [[ALLONES]]
- // CHECK-ASM-NEXT: vpxor [[ALLONES]], %ymm{{.*}}, [[NOT:%ymm[0-9]+]]
- // CHECK-ASM-NEXT: vandps {{.*}}, [[NOT]], %ymm{{.*}}
return _mm256_andnot_si256(a, b);
}
__m256i test_mm256_or_si256(__m256i a, __m256i b) {
// CHECK: or <4 x i64>
- // CHECK-ASM: vorps {{.*}}, %ymm{{.*}}
return _mm256_or_si256(a, b);
}
__m256i test_mm256_xor_si256(__m256i a, __m256i b) {
// CHECK: xor <4 x i64>
- // CHECK-ASM: vxorps {{.*}}, %ymm{{.*}}
return _mm256_xor_si256(a, b);
}
__m256i test_mm256_avg_epu8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pavg.b
- // CHECK-ASM: vpavgb %ymm{{.*}}
return _mm256_avg_epu8(a, b);
}
__m256i test_mm256_avg_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pavg.w
- // CHECK-ASM: vpavgw %ymm{{.*}}
return _mm256_avg_epu16(a, b);
}
__m256i test_mm256_blendv_epi8(__m256i a, __m256i b, __m256i m) {
// CHECK: @llvm.x86.avx2.pblendvb
- // CHECK-ASM: vpblendvb %ymm{{.*}}
return _mm256_blendv_epi8(a, b, m);
}
@@ -226,511 +184,426 @@
// CHECK-LABEL: test_mm256_blend_epi16
// CHECK-NOT: @llvm.x86.avx2.pblendw
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 0, i32 17, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 25, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
- // CHECK-ASM: vpblendw $2, %ymm{{.*}}
return _mm256_blend_epi16(a, b, 2);
}
__m256i test_mm256_cmpeq_epi8(__m256i a, __m256i b) {
// CHECK: icmp eq <32 x i8>
- // CHECK-ASM: vpcmpeqb %ymm{{.*}}
return _mm256_cmpeq_epi8(a, b);
}
__m256i test_mm256_cmpeq_epi16(__m256i a, __m256i b) {
// CHECK: icmp eq <16 x i16>
- // CHECK-ASM: vpcmpeqw %ymm{{.*}}
return _mm256_cmpeq_epi16(a, b);
}
__m256i test_mm256_cmpeq_epi32(__m256i a, __m256i b) {
// CHECK: icmp eq <8 x i32>
- // CHECK-ASM: vpcmpeqd %ymm{{.*}}
return _mm256_cmpeq_epi32(a, b);
}
__m256i test_mm256_cmpeq_epi64(__m256i a, __m256i b) {
// CHECK: icmp eq <4 x i64>
- // CHECK-ASM: vpcmpeqq %ymm{{.*}}
return _mm256_cmpeq_epi64(a, b);
}
__m256i test_mm256_cmpgt_epi8(__m256i a, __m256i b) {
// CHECK: icmp sgt <32 x i8>
- // CHECK-ASM: vpcmpgtb %ymm{{.*}}
return _mm256_cmpgt_epi8(a, b);
}
__m256i test_mm256_cmpgt_epi16(__m256i a, __m256i b) {
// CHECK: icmp sgt <16 x i16>
- // CHECK-ASM: vpcmpgtw %ymm{{.*}}
return _mm256_cmpgt_epi16(a, b);
}
__m256i test_mm256_cmpgt_epi32(__m256i a, __m256i b) {
// CHECK: icmp sgt <8 x i32>
- // CHECK-ASM: vpcmpgtd %ymm{{.*}}
return _mm256_cmpgt_epi32(a, b);
}
__m256i test_mm256_cmpgt_epi64(__m256i a, __m256i b) {
// CHECK: icmp sgt <4 x i64>
- // CHECK-ASM: vpcmpgtq %ymm{{.*}}
return _mm256_cmpgt_epi64(a, b);
}
__m256i test_mm256_hadd_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phadd.w
- // CHECK-ASM: vphaddw %ymm{{.*}}
return _mm256_hadd_epi16(a, b);
}
__m256i test_mm256_hadd_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phadd.d
- // CHECK-ASM: vphaddd %ymm{{.*}}
return _mm256_hadd_epi32(a, b);
}
__m256i test_mm256_hadds_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phadd.sw
- // CHECK-ASM: vphaddsw %ymm{{.*}}
return _mm256_hadds_epi16(a, b);
}
__m256i test_mm256_hsub_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phsub.w
- // CHECK-ASM: vphsubw %ymm{{.*}}
return _mm256_hsub_epi16(a, b);
}
__m256i test_mm256_hsub_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phsub.d
- // CHECK-ASM: vphsubd %ymm{{.*}}
return _mm256_hsub_epi32(a, b);
}
__m256i test_mm256_hsubs_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.phsub.sw
- // CHECK-ASM: vphsubsw %ymm{{.*}}
return _mm256_hsubs_epi16(a, b);
}
__m256i test_mm256_maddubs_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmadd.ub.sw
- // CHECK-ASM: vpmaddubsw %ymm{{.*}}
return _mm256_maddubs_epi16(a, b);
}
__m256i test_mm256_madd_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmadd.wd
- // CHECK-ASM: vpmaddwd %ymm{{.*}}
return _mm256_madd_epi16(a, b);
}
__m256i test_mm256_max_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxs.b
- // CHECK-ASM: vpmaxsb %ymm{{.*}}
return _mm256_max_epi8(a, b);
}
__m256i test_mm256_max_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxs.w
- // CHECK-ASM: vpmaxsw %ymm{{.*}}
return _mm256_max_epi16(a, b);
}
__m256i test_mm256_max_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxs.d
- // CHECK-ASM: vpmaxsd %ymm{{.*}}
return _mm256_max_epi32(a, b);
}
__m256i test_mm256_max_epu8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxu.b
- // CHECK-ASM: vpmaxub %ymm{{.*}}
return _mm256_max_epu8(a, b);
}
__m256i test_mm256_max_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxu.w
- // CHECK-ASM: vpmaxuw %ymm{{.*}}
return _mm256_max_epu16(a, b);
}
__m256i test_mm256_max_epu32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmaxu.d
- // CHECK-ASM: vpmaxud %ymm{{.*}}
return _mm256_max_epu32(a, b);
}
__m256i test_mm256_min_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmins.b
- // CHECK-ASM: vpminsb %ymm{{.*}}
return _mm256_min_epi8(a, b);
}
__m256i test_mm256_min_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmins.w
- // CHECK-ASM: vpminsw %ymm{{.*}}
return _mm256_min_epi16(a, b);
}
__m256i test_mm256_min_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmins.d
- // CHECK-ASM: vpminsd %ymm{{.*}}
return _mm256_min_epi32(a, b);
}
__m256i test_mm256_min_epu8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pminu.b
- // CHECK-ASM: vpminub %ymm{{.*}}
return _mm256_min_epu8(a, b);
}
__m256i test_mm256_min_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pminu.w
- // CHECK-ASM: vpminuw %ymm{{.*}}
return _mm256_min_epu16(a, b);
}
__m256i test_mm256_min_epu32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pminu.d
- // CHECK-ASM: vpminud %ymm{{.*}}
return _mm256_min_epu32(a, b);
}
int test_mm256_movemask_epi8(__m256i a) {
// CHECK: @llvm.x86.avx2.pmovmskb
- // CHECK-ASM: vpmovmskb %ymm{{.*}}
return _mm256_movemask_epi8(a);
}
__m256i test_mm256_cvtepi8_epi16(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxbw
- // CHECK-ASM: vpmovsxbw %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi8_epi16(a);
}
__m256i test_mm256_cvtepi8_epi32(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxbd
- // CHECK-ASM: vpmovsxbd %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi8_epi32(a);
}
__m256i test_mm256_cvtepi8_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxbq
- // CHECK-ASM: vpmovsxbq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi8_epi64(a);
}
__m256i test_mm256_cvtepi16_epi32(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxwd
- // CHECK-ASM: vpmovsxwd %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi16_epi32(a);
}
__m256i test_mm256_cvtepi16_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxwq
- // CHECK-ASM: vpmovsxwq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi16_epi64(a);
}
__m256i test_mm256_cvtepi32_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovsxdq
- // CHECK-ASM: vpmovsxdq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepi32_epi64(a);
}
__m256i test_mm256_cvtepu8_epi16(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxbw
- // CHECK-ASM: vpmovzxbw %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu8_epi16(a);
}
__m256i test_mm256_cvtepu8_epi32(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxbd
- // CHECK-ASM: vpmovzxbd %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu8_epi32(a);
}
__m256i test_mm256_cvtepu8_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxbq
- // CHECK-ASM: vpmovzxbq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu8_epi64(a);
}
__m256i test_mm256_cvtepu16_epi32(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxwd
- // CHECK-ASM: vpmovzxwd %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu16_epi32(a);
}
__m256i test_mm256_cvtepu16_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxwq
- // CHECK-ASM: vpmovzxwq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu16_epi64(a);
}
__m256i test_mm256_cvtepu32_epi64(__m128i a) {
// CHECK: @llvm.x86.avx2.pmovzxdq
- // CHECK-ASM: vpmovzxdq %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtepu32_epi64(a);
}
__m256i test_mm256_mul_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmul.dq
- // CHECK-ASM: vpmuldq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mul_epi32(a, b);
}
__m256i test_mm256_mulhrs_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmul.hr.sw
- // CHECK-ASM: vpmulhrsw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mulhrs_epi16(a, b);
}
__m256i test_mm256_mulhi_epu16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmulhu.w
- // CHECK-ASM: vpmulhuw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mulhi_epu16(a, b);
}
__m256i test_mm256_mulhi_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmulh.w
- // CHECK-ASM: vpmulhw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mulhi_epi16(a, b);
}
__m256i test_mm256_mullo_epi16(__m256i a, __m256i b) {
// CHECK: mul <16 x i16>
- // CHECK-ASM: vpmullw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mullo_epi16(a, b);
}
__m256i test_mm256_mullo_epi32(__m256i a, __m256i b) {
// CHECK: mul <8 x i32>
- // CHECK-ASM: vpmulld %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mullo_epi32(a, b);
}
__m256i test_mm256_mul_epu32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pmulu.dq
- // CHECK-ASM: vpmuludq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_mul_epu32(a, b);
}
__m256i test_mm256_shuffle_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.pshuf.b
- // CHECK-ASM: vpshufb %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_shuffle_epi8(a, b);
}
__m256i test_mm256_shuffle_epi32(__m256i a) {
// CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 3, i32 3, i32 0, i32 0, i32 7, i32 7, i32 4, i32 4>
- // CHECK-ASM: vpshufd $15, %ymm{{.*}}, %ymm{{.*}}
return _mm256_shuffle_epi32(a, 15);
}
__m256i test_mm256_shufflehi_epi16(__m256i a) {
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 7, i32 6, i32 6, i32 5, i32 8, i32 9, i32 10, i32 11, i32 15, i32 14, i32 14, i32 13>
- // CHECK-ASM: vpshufhw $107, %ymm{{.*}}, %ymm{{.*}}
return _mm256_shufflehi_epi16(a, 107);
}
__m256i test_mm256_shufflelo_epi16(__m256i a) {
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 3, i32 0, i32 1, i32 1, i32 4, i32 5, i32 6, i32 7, i32 11, i32 8, i32 9, i32 9, i32 12, i32 13, i32 14, i32 15>
- // CHECK-ASM: vpshuflw $83, %ymm{{.*}}, %ymm{{.*}}
return _mm256_shufflelo_epi16(a, 83);
}
__m256i test_mm256_sign_epi8(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psign.b
- // CHECK-ASM: vpsignb %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sign_epi8(a, b);
}
__m256i test_mm256_sign_epi16(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psign.w
- // CHECK-ASM: vpsignw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sign_epi16(a, b);
}
__m256i test_mm256_sign_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psign.d
- // CHECK-ASM: vpsignd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sign_epi32(a, b);
}
__m256i test_mm256_slli_si256(__m256i a) {
// CHECK: shufflevector <32 x i8> zeroinitializer, <32 x i8> %{{.*}}, <32 x i32> <i32 13, i32 14, i32 15, i32 32, i32 33, i32 34, i32 35, i32 36, i32 37, i32 38, i32 39, i32 40, i32 41, i32 42, i32 43, i32 44, i32 29, i32 30, i32 31, i32 48, i32 49, i32 50, i32 51, i32 52, i32 53, i32 54, i32 55, i32 56, i32 57, i32 58, i32 59, i32 60>
- // CHECK-ASM: vpslldq $3, %ymm{{.*}}, %ymm{{.*}}
return _mm256_slli_si256(a, 3);
}
__m256i test_mm256_bslli_epi128(__m256i a) {
// CHECK: shufflevector <32 x i8> zeroinitializer, <32 x i8> %{{.*}}, <32 x i32> <i32 13, i32 14, i32 15, i32 32, i32 33, i32 34, i32 35, i32 36, i32 37, i32 38, i32 39, i32 40, i32 41, i32 42, i32 43, i32 44, i32 29, i32 30, i32 31, i32 48, i32 49, i32 50, i32 51, i32 52, i32 53, i32 54, i32 55, i32 56, i32 57, i32 58, i32 59, i32 60>
- // CHECK-ASM: vpslldq $3, %ymm{{.*}}, %ymm{{.*}}
return _mm256_bslli_epi128(a, 3);
}
__m256i test_mm256_slli_epi16(__m256i a) {
// CHECK: @llvm.x86.avx2.pslli.w
- // CHECK-ASM: vpsllw {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_slli_epi16(a, 3);
}
__m256i test_mm256_sll_epi16(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psll.w
- // CHECK-ASM: vpsllw %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sll_epi16(a, b);
}
__m256i test_mm256_slli_epi32(__m256i a) {
// CHECK: @llvm.x86.avx2.pslli.d
- // CHECK-ASM: vpslld {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_slli_epi32(a, 3);
}
__m256i test_mm256_sll_epi32(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psll.d
- // CHECK-ASM: vpslld %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sll_epi32(a, b);
}
__m256i test_mm256_slli_epi64(__m256i a) {
// CHECK: @llvm.x86.avx2.pslli.q
- // CHECK-ASM: vpsllq %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_slli_epi64(a, 3);
}
__m256i test_mm256_sll_epi64(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psll.q
- // CHECK-ASM: vpsllq %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sll_epi64(a, b);
}
__m256i test_mm256_srai_epi16(__m256i a) {
// CHECK: @llvm.x86.avx2.psrai.w
- // CHECK-ASM: vpsraw {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srai_epi16(a, 3);
}
__m256i test_mm256_sra_epi16(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psra.w
- // CHECK-ASM: vpsraw %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sra_epi16(a, b);
}
__m256i test_mm256_srai_epi32(__m256i a) {
// CHECK: @llvm.x86.avx2.psrai.d
- // CHECK-ASM: vpsrad {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srai_epi32(a, 3);
}
__m256i test_mm256_sra_epi32(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psra.d
- // CHECK-ASM: vpsrad %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sra_epi32(a, b);
}
__m256i test_mm256_srli_si256(__m256i a) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> zeroinitializer, <32 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 32, i32 33, i32 34, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 48, i32 49, i32 50>
- // CHECK-ASM: vpsrldq $3, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srli_si256(a, 3);
}
__m256i test_mm256_bsrli_epi128(__m256i a) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> zeroinitializer, <32 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 32, i32 33, i32 34, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 48, i32 49, i32 50>
- // CHECK-ASM: vpsrldq $3, %ymm{{.*}}, %ymm{{.*}}
return _mm256_bsrli_epi128(a, 3);
}
__m256i test_mm256_srli_epi16(__m256i a) {
// CHECK: @llvm.x86.avx2.psrli.w
- // CHECK-ASM: vpsrlw {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srli_epi16(a, 3);
}
__m256i test_mm256_srl_epi16(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrl.w
- // CHECK-ASM: vpsrlw %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srl_epi16(a, b);
}
__m256i test_mm256_srli_epi32(__m256i a) {
// CHECK: @llvm.x86.avx2.psrli.d
- // CHECK-ASM: vpsrld {{\$3|%xmm[0-9]+}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srli_epi32(a, 3);
}
__m256i test_mm256_srl_epi32(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrl.d
- // CHECK-ASM: vpsrld %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srl_epi32(a, b);
}
__m256i test_mm256_srli_epi64(__m256i a) {
// CHECK: @llvm.x86.avx2.psrli.q
- // CHECK-ASM: vpsrlq %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srli_epi64(a, 3);
}
__m256i test_mm256_srl_epi64(__m256i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrl.q
- // CHECK-ASM: vpsrlq %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srl_epi64(a, b);
}
__m256i test_mm256_unpackhi_epi8(__m256i a, __m256i b) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 8, i32 40, i32 9, i32 41, i32 10, i32 42, i32 11, i32 43, i32 12, i32 44, i32 13, i32 45, i32 14, i32 46, i32 15, i32 47, i32 24, i32 56, i32 25, i32 57, i32 26, i32 58, i32 27, i32 59, i32 28, i32 60, i32 29, i32 61, i32 30, i32 62, i32 31, i32 63>
- // CHECK-ASM: vpunpckhbw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpackhi_epi8(a, b);
}
__m256i test_mm256_unpackhi_epi16(__m256i a, __m256i b) {
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 4, i32 20, i32 5, i32 21, i32 6, i32 22, i32 7, i32 23, i32 12, i32 28, i32 13, i32 29, i32 14, i32 30, i32 15, i32 31>
- // CHECK-ASM: vpunpckhwd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpackhi_epi16(a, b);
}
__m256i test_mm256_unpackhi_epi32(__m256i a, __m256i b) {
// CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 2, i32 10, i32 3, i32 11, i32 6, i32 14, i32 7, i32 15>
- // CHECK-ASM: vpunpckhdq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpackhi_epi32(a, b);
}
__m256i test_mm256_unpackhi_epi64(__m256i a, __m256i b) {
// CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <4 x i32> <i32 1, i32 5, i32 3, i32 7>
- // CHECK-ASM: vpunpckhqdq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpackhi_epi64(a, b);
}
__m256i test_mm256_unpacklo_epi8(__m256i a, __m256i b) {
// CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 0, i32 32, i32 1, i32 33, i32 2, i32 34, i32 3, i32 35, i32 4, i32 36, i32 5, i32 37, i32 6, i32 38, i32 7, i32 39, i32 16, i32 48, i32 17, i32 49, i32 18, i32 50, i32 19, i32 51, i32 20, i32 52, i32 21, i32 53, i32 22, i32 54, i32 23, i32 55>
- // CHECK-ASM: vpunpcklbw %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpacklo_epi8(a, b);
}
__m256i test_mm256_unpacklo_epi16(__m256i a, __m256i b) {
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 0, i32 16, i32 1, i32 17, i32 2, i32 18, i32 3, i32 19, i32 8, i32 24, i32 9, i32 25, i32 10, i32 26, i32 11, i32 27>
- // CHECK-ASM: vpunpcklwd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpacklo_epi16(a, b);
}
__m256i test_mm256_unpacklo_epi32(__m256i a, __m256i b) {
// CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 4, i32 12, i32 5, i32 13>
- // CHECK-ASM: vpunpckldq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpacklo_epi32(a, b);
}
__m256i test_mm256_unpacklo_epi64(__m256i a, __m256i b) {
// CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
- // CHECK-ASM: vpunpcklqdq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_unpacklo_epi64(a, b);
}
__m256i test_mm256_stream_load_si256(__m256i const *a) {
// CHECK: @llvm.x86.avx2.movntdqa
- // CHECK-ASM: vmovntdqa (%rdi), %ymm{{.*}}
return _mm256_stream_load_si256(a);
}
@@ -738,13 +611,12 @@
// CHECK-LABEL: test_mm_broadcastss_ps
// CHECK-NOT: @llvm.x86.avx2.vbroadcast.ss.ps
// CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> zeroinitializer
- // CHECK-ASM: vbroadcastss %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastss_ps(a);
}
__m128d test_mm_broadcastsd_pd(__m128d a) {
+ // CHECK-LABEL: test_mm_broadcastsd_pd
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> zeroinitializer
- // CHECK-ASM: vmovddup %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastsd_pd(a);
}
@@ -752,7 +624,6 @@
// CHECK-LABEL: test_mm256_broadcastss_ps
// CHECK-NOT: @llvm.x86.avx2.vbroadcast.ss.ps.256
// CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> zeroinitializer
- // CHECK-ASM: vbroadcastss %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastss_ps(a);
}
@@ -760,13 +631,11 @@
// CHECK-LABEL: test_mm256_broadcastsd_pd
// CHECK-NOT: @llvm.x86.avx2.vbroadcast.sd.pd.256
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> zeroinitializer
- // CHECK-ASM: vbroadcastsd %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastsd_pd(a);
}
__m256i test_mm256_broadcastsi128_si256(__m128i a) {
// CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
- // CHECK-ASM: vinserti128 $1, %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_broadcastsi128_si256(a);
}
@@ -774,7 +643,6 @@
// CHECK-LABEL: test_mm_blend_epi32
// CHECK-NOT: @llvm.x86.avx2.pblendd.128
// CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> <i32 4, i32 1, i32 6, i32 3>
- // CHECK-ASM: vpblendd $10, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_blend_epi32(a, b, 0x35);
}
@@ -782,7 +650,6 @@
// CHECK-LABEL: test_mm256_blend_epi32
// CHECK-NOT: @llvm.x86.avx2.pblendd.256
// CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 8, i32 1, i32 10, i32 3, i32 12, i32 13, i32 6, i32 7>
- // CHECK-ASM: vpblendd $202, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_blend_epi32(a, b, 0x35);
}
@@ -790,7 +657,6 @@
// CHECK-LABEL: test_mm256_broadcastb_epi8
// CHECK-NOT: @llvm.x86.avx2.pbroadcastb.256
// CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <32 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastb %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastb_epi8(a);
}
@@ -798,7 +664,6 @@
// CHECK-LABEL: test_mm256_broadcastw_epi16
// CHECK-NOT: @llvm.x86.avx2.pbroadcastw.256
// CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <16 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastw %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastw_epi16(a);
}
@@ -806,7 +671,6 @@
// CHECK-LABEL: test_mm256_broadcastd_epi32
// CHECK-NOT: @llvm.x86.avx2.pbroadcastd.256
// CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <8 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastd %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastd_epi32(a);
}
@@ -814,7 +678,6 @@
// CHECK-LABEL: test_mm256_broadcastq_epi64
// CHECK-NOT: @llvm.x86.avx2.pbroadcastq.256
// CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastq %xmm{{.*}}, %ymm{{.*}}
return _mm256_broadcastq_epi64(a);
}
@@ -822,7 +685,6 @@
// CHECK-LABEL: test_mm_broadcastb_epi8
// CHECK-NOT: @llvm.x86.avx2.pbroadcastb.128
// CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastb %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastb_epi8(a);
}
@@ -830,7 +692,6 @@
// CHECK-LABEL: test_mm_broadcastw_epi16
// CHECK-NOT: @llvm.x86.avx2.pbroadcastw.128
// CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastw %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastw_epi16(a);
}
@@ -838,7 +699,6 @@
// CHECK-LABEL: test_mm_broadcastd_epi32
// CHECK-NOT: @llvm.x86.avx2.pbroadcastd.128
// CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastd %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastd_epi32(a);
}
@@ -846,53 +706,43 @@
// CHECK-LABEL: test_mm_broadcastq_epi64
// CHECK-NOT: @llvm.x86.avx2.pbroadcastq.128
// CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <2 x i32> zeroinitializer
- // CHECK-ASM: vpbroadcastq %xmm{{.*}}, %xmm{{.*}}
return _mm_broadcastq_epi64(a);
}
__m256i test_mm256_permutevar8x32_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.permd
- // CHECK-ASM: vpermd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permutevar8x32_epi32(a, b);
}
__m256d test_mm256_permute4x64_pd(__m256d a) {
// CHECK: shufflevector{{.*}}<i32 1, i32 2, i32 1, i32 0>
- // CHECK-ASM: vpermpd $25, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permute4x64_pd(a, 25);
}
-__m256 test_mm256_permutevar8x32_ps(__m256 a, __m256 b) {
+__m256 test_mm256_permutevar8x32_ps(__m256 a, __m256i b) {
// CHECK: @llvm.x86.avx2.permps
- // CHECK-ASM: vpermps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permutevar8x32_ps(a, b);
}
__m256i test_mm256_permute4x64_epi64(__m256i a) {
// CHECK: shufflevector{{.*}}<i32 3, i32 0, i32 2, i32 0>
- // CHECK-ASM: vpermq $35, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permute4x64_epi64(a, 35);
}
__m256i test_mm256_permute2x128_si256(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.vperm2i128
- // CHECK-ASM: vperm2i128 $49, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permute2x128_si256(a, b, 0x31);
}
__m128i test_mm256_extracti128_si256_0(__m256i a) {
// CHECK-LABEL: @test_mm256_extracti128_si256_0
// CHECK: shufflevector{{.*}}<i32 0, i32 1>
-
- // Note that we just match an XMM copy: vextracti128 $0 is a little overkill.
- // CHECK-ASM: vmovdqa {{.*}}, %xmm0
return _mm256_extracti128_si256(a, 0);
}
__m128i test_mm256_extracti128_si256_1(__m256i a) {
// CHECK-LABEL: @test_mm256_extracti128_si256_1
// CHECK: shufflevector{{.*}}<i32 2, i32 3>
- // CHECK-ASM: vextracti128 $1, %ymm{{.*}}, %xmm{{.*}}
return _mm256_extracti128_si256(a, 1);
}
@@ -900,23 +750,18 @@
__m128i test_mm256_extracti128_si256_2(__m256i a) {
// CHECK-LABEL: @test_mm256_extracti128_si256_2
// CHECK: shufflevector{{.*}}<i32 0, i32 1>
-
- // Same as extracti128 $0.
- // CHECK-ASM: vmovdqa {{.*}}, %xmm0
return _mm256_extracti128_si256(a, 2);
}
__m256i test_mm256_inserti128_si256_0(__m256i a, __m128i b) {
// CHECK-LABEL: @test_mm256_inserti128_si256_0
// CHECK: shufflevector{{.*}}<i32 4, i32 5, i32 2, i32 3>
- // CHECK-ASM: vpblendd $240, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_inserti128_si256(a, b, 0);
}
__m256i test_mm256_inserti128_si256_1(__m256i a, __m128i b) {
// CHECK-LABEL: @test_mm256_inserti128_si256_1
// CHECK: shufflevector{{.*}}<i32 0, i32 1, i32 4, i32 5>
- // CHECK-ASM: vinserti128 $1, %xmm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_inserti128_si256(a, b, 1);
}
@@ -924,322 +769,271 @@
__m256i test_mm256_inserti128_si256_2(__m256i a, __m128i b) {
// CHECK-LABEL: @test_mm256_inserti128_si256_2
// CHECK: shufflevector{{.*}}<i32 4, i32 5, i32 2, i32 3>
- // CHECK-ASM: vpblendd $240, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_inserti128_si256(a, b, 2);
}
__m256i test_mm256_maskload_epi32(int const *a, __m256i m) {
// CHECK: @llvm.x86.avx2.maskload.d.256
- // CHECK-ASM: vpmaskmovd (%rdi), %ymm{{.*}}, %ymm{{.*}}
return _mm256_maskload_epi32(a, m);
}
__m256i test_mm256_maskload_epi64(long long const *a, __m256i m) {
// CHECK: @llvm.x86.avx2.maskload.q.256
- // CHECK-ASM: vpmaskmovq (%rdi), %ymm{{.*}}, %ymm{{.*}}
return _mm256_maskload_epi64(a, m);
}
__m128i test_mm_maskload_epi32(int const *a, __m128i m) {
// CHECK: @llvm.x86.avx2.maskload.d
- // CHECK-ASM: vpmaskmovd (%rdi), %xmm{{.*}}, %xmm{{.*}}
return _mm_maskload_epi32(a, m);
}
__m128i test_mm_maskload_epi64(long long const *a, __m128i m) {
// CHECK: @llvm.x86.avx2.maskload.q
- // CHECK-ASM: vpmaskmovq (%rdi), %xmm{{.*}}, %xmm{{.*}}
return _mm_maskload_epi64(a, m);
}
void test_mm256_maskstore_epi32(int *a, __m256i m, __m256i b) {
// CHECK: @llvm.x86.avx2.maskstore.d.256
- // CHECK-ASM: vpmaskmovd %ymm{{.*}}, %ymm{{.*}}, (%r{{.*}})
_mm256_maskstore_epi32(a, m, b);
}
void test_mm256_maskstore_epi64(long long *a, __m256i m, __m256i b) {
// CHECK: @llvm.x86.avx2.maskstore.q.256
- // CHECK-ASM: vpmaskmovq %ymm{{.*}}, %ymm{{.*}}, (%r{{.*}})
_mm256_maskstore_epi64(a, m, b);
}
void test_mm_maskstore_epi32(int *a, __m128i m, __m128i b) {
// CHECK: @llvm.x86.avx2.maskstore.d
- // CHECK-ASM: vpmaskmovd %xmm{{.*}}, %xmm{{.*}}, (%r{{.*}})
_mm_maskstore_epi32(a, m, b);
}
void test_mm_maskstore_epi64(long long *a, __m128i m, __m128i b) {
// CHECK: @llvm.x86.avx2.maskstore.q
- // CHECK-ASM: vpmaskmovq %xmm{{.*}}, %xmm{{.*}}, (%r{{.*}})
_mm_maskstore_epi64(a, m, b);
}
__m256i test_mm256_sllv_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psllv.d.256
- // CHECK-ASM: vpsllvd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sllv_epi32(a, b);
}
__m128i test_mm_sllv_epi32(__m128i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psllv.d
- // CHECK-ASM: vpsllvd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sllv_epi32(a, b);
}
__m256i test_mm256_sllv_epi64(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psllv.q.256
- // CHECK-ASM: vpsllvq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_sllv_epi64(a, b);
}
__m128i test_mm_sllv_epi64(__m128i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psllv.q
- // CHECK-ASM: vpsllvq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sllv_epi64(a, b);
}
__m256i test_mm256_srav_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psrav.d.256
- // CHECK-ASM: vpsravd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srav_epi32(a, b);
}
__m128i test_mm_srav_epi32(__m128i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrav.d
- // CHECK-ASM: vpsravd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_srav_epi32(a, b);
}
__m256i test_mm256_srlv_epi32(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psrlv.d.256
- // CHECK-ASM: vpsrlvd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srlv_epi32(a, b);
}
__m128i test_mm_srlv_epi32(__m128i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrlv.d
- // CHECK-ASM: vpsrlvd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_srlv_epi32(a, b);
}
__m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
// CHECK: @llvm.x86.avx2.psrlv.q.256
- // CHECK-ASM: vpsrlvq %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_srlv_epi64(a, b);
}
__m128i test_mm_srlv_epi64(__m128i a, __m128i b) {
// CHECK: @llvm.x86.avx2.psrlv.q
- // CHECK-ASM: vpsrlvq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_srlv_epi64(a, b);
}
__m128d test_mm_mask_i32gather_pd(__m128d a, double const *b, __m128i c,
__m128d d) {
// CHECK: @llvm.x86.avx2.gather.d.pd
- // CHECK-ASM: vgatherdpd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i32gather_pd(a, b, c, d, 2);
}
__m256d test_mm256_mask_i32gather_pd(__m256d a, double const *b, __m128i c,
__m256d d) {
// CHECK: @llvm.x86.avx2.gather.d.pd.256
- // CHECK-ASM: vgatherdpd %ymm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i32gather_pd(a, b, c, d, 2);
}
__m128d test_mm_mask_i64gather_pd(__m128d a, double const *b, __m128i c,
__m128d d) {
// CHECK: @llvm.x86.avx2.gather.q.pd
- // CHECK-ASM: vgatherqpd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i64gather_pd(a, b, c, d, 2);
}
__m256d test_mm256_mask_i64gather_pd(__m256d a, double const *b, __m256i c,
__m256d d) {
// CHECK: @llvm.x86.avx2.gather.q.pd.256
- // CHECK-ASM: vgatherqpd %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i64gather_pd(a, b, c, d, 2);
}
__m128 test_mm_mask_i32gather_ps(__m128 a, float const *b, __m128i c,
__m128 d) {
// CHECK: @llvm.x86.avx2.gather.d.ps
- // CHECK-ASM: vgatherdps %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i32gather_ps(a, b, c, d, 2);
}
__m256 test_mm256_mask_i32gather_ps(__m256 a, float const *b, __m256i c,
__m256 d) {
// CHECK: @llvm.x86.avx2.gather.d.ps.256
- // CHECK-ASM: vgatherdps %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i32gather_ps(a, b, c, d, 2);
}
__m128 test_mm_mask_i64gather_ps(__m128 a, float const *b, __m128i c,
__m128 d) {
// CHECK: @llvm.x86.avx2.gather.q.ps
- // CHECK-ASM: vgatherqps %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i64gather_ps(a, b, c, d, 2);
}
__m128 test_mm256_mask_i64gather_ps(__m128 a, float const *b, __m256i c,
__m128 d) {
// CHECK: @llvm.x86.avx2.gather.q.ps.256
- // CHECK-ASM: vgatherqps %xmm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %xmm{{.*}}
return _mm256_mask_i64gather_ps(a, b, c, d, 2);
}
__m128i test_mm_mask_i32gather_epi32(__m128i a, int const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.d.d
- // CHECK-ASM: vpgatherdd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i32gather_epi32(a, b, c, d, 2);
}
__m256i test_mm256_mask_i32gather_epi32(__m256i a, int const *b, __m256i c,
__m256i d) {
// CHECK: @llvm.x86.avx2.gather.d.d.256
- // CHECK-ASM: vpgatherdd %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i32gather_epi32(a, b, c, d, 2);
}
__m128i test_mm_mask_i64gather_epi32(__m128i a, int const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.q.d
- // CHECK-ASM: vpgatherqd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i64gather_epi32(a, b, c, d, 2);
}
__m128i test_mm256_mask_i64gather_epi32(__m128i a, int const *b, __m256i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.q.d.256
- // CHECK-ASM: vpgatherqd %xmm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %xmm{{.*}}
return _mm256_mask_i64gather_epi32(a, b, c, d, 2);
}
__m128i test_mm_mask_i32gather_epi64(__m128i a, long long const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.d.q
- // CHECK-ASM: vpgatherdq %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i32gather_epi64(a, b, c, d, 2);
}
__m256i test_mm256_mask_i32gather_epi64(__m256i a, long long const *b, __m128i c,
__m256i d) {
// CHECK: @llvm.x86.avx2.gather.d.q.256
- // CHECK-ASM: vpgatherdq %ymm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i32gather_epi64(a, b, c, d, 2);
}
__m128i test_mm_mask_i64gather_epi64(__m128i a, long long const *b, __m128i c,
__m128i d) {
// CHECK: @llvm.x86.avx2.gather.q.q
- // CHECK-ASM: vpgatherqq %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_mask_i64gather_epi64(a, b, c, d, 2);
}
__m256i test_mm256_mask_i64gather_epi64(__m256i a, long long const *b, __m256i c,
__m256i d) {
// CHECK: @llvm.x86.avx2.gather.q.q.256
- // CHECK-ASM: vpgatherqq %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_mask_i64gather_epi64(a, b, c, d, 2);
}
__m128d test_mm_i32gather_pd(double const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.pd
- // CHECK-ASM: vgatherdpd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i32gather_pd(b, c, 2);
}
__m256d test_mm256_i32gather_pd(double const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.pd.256
- // CHECK-ASM: vgatherdpd %ymm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %ymm{{.*}}
return _mm256_i32gather_pd(b, c, 2);
}
__m128d test_mm_i64gather_pd(double const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.q.pd
- // CHECK-ASM: vgatherqpd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i64gather_pd(b, c, 2);
}
__m256d test_mm256_i64gather_pd(double const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.pd.256
- // CHECK-ASM: vgatherqpd %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_i64gather_pd(b, c, 2);
}
__m128 test_mm_i32gather_ps(float const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.ps
- // CHECK-ASM: vgatherdps %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i32gather_ps(b, c, 2);
}
__m256 test_mm256_i32gather_ps(float const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.d.ps.256
- // CHECK-ASM: vgatherdps %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_i32gather_ps(b, c, 2);
}
__m128 test_mm_i64gather_ps(float const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.q.ps
- // CHECK-ASM: vgatherqps %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i64gather_ps(b, c, 2);
}
__m128 test_mm256_i64gather_ps(float const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.ps.256
- // CHECK-ASM: vgatherqps %xmm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %xmm{{.*}}
return _mm256_i64gather_ps(b, c, 2);
}
__m128i test_mm_i32gather_epi32(int const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.d
- // CHECK-ASM: vpgatherdd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i32gather_epi32(b, c, 2);
}
__m256i test_mm256_i32gather_epi32(int const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.d.d.256
- // CHECK-ASM: vpgatherdd %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_i32gather_epi32(b, c, 2);
}
__m128i test_mm_i64gather_epi32(int const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.q.d
- // CHECK-ASM: vpgatherqd %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i64gather_epi32(b, c, 2);
}
__m128i test_mm256_i64gather_epi32(int const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.d.256
- // CHECK-ASM: vpgatherqd %xmm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %xmm{{.*}}
return _mm256_i64gather_epi32(b, c, 2);
}
__m128i test_mm_i32gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.q
- // CHECK-ASM: vpgatherdq %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i32gather_epi64(b, c, 2);
}
__m256i test_mm256_i32gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.d.q.256
- // CHECK-ASM: vpgatherdq %ymm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %ymm{{.*}}
return _mm256_i32gather_epi64(b, c, 2);
}
__m128i test_mm_i64gather_epi64(long long const *b, __m128i c) {
// CHECK: @llvm.x86.avx2.gather.q.q
- // CHECK-ASM: vpgatherqq %xmm{{.*}}, (%r{{.*}},%xmm{{.*}},2), %xmm{{.*}}
return _mm_i64gather_epi64(b, c, 2);
}
__m256i test_mm256_i64gather_epi64(long long const *b, __m256i c) {
// CHECK: @llvm.x86.avx2.gather.q.q.256
- // CHECK-ASM: vpgatherqq %ymm{{.*}}, (%r{{.*}},%ymm{{.*}},2), %ymm{{.*}}
return _mm256_i64gather_epi64(b, c, 2);
}
diff --git a/test/CodeGen/avx512cdintrin.c b/test/CodeGen/avx512cdintrin.c
index 1c8b19e..625a3d2 100644
--- a/test/CodeGen/avx512cdintrin.c
+++ b/test/CodeGen/avx512cdintrin.c
@@ -1,67 +1,67 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx512cd -emit-llvm -o - -Werror | FileCheck %s
-
-// Don't include mm_malloc.h, it's system specific.
-#define __MM_MALLOC_H
-
-#include <immintrin.h>
-
-__m512i test_mm512_conflict_epi64(__m512i __A) {
- // CHECK-LABEL: @test_mm512_conflict_epi64
- // CHECK: @llvm.x86.avx512.mask.conflict.q.512
- return _mm512_conflict_epi64(__A);
-}
-__m512i test_mm512_mask_conflict_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_mask_conflict_epi64
- // CHECK: @llvm.x86.avx512.mask.conflict.q.512
- return _mm512_mask_conflict_epi64(__W,__U,__A);
-}
-__m512i test_mm512_maskz_conflict_epi64(__mmask8 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_maskz_conflict_epi64
- // CHECK: @llvm.x86.avx512.mask.conflict.q.512
- return _mm512_maskz_conflict_epi64(__U,__A);
-}
-__m512i test_mm512_conflict_epi32(__m512i __A) {
- // CHECK-LABEL: @test_mm512_conflict_epi32
- // CHECK: @llvm.x86.avx512.mask.conflict.d.512
- return _mm512_conflict_epi32(__A);
-}
-__m512i test_mm512_mask_conflict_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_mask_conflict_epi32
- // CHECK: @llvm.x86.avx512.mask.conflict.d.512
- return _mm512_mask_conflict_epi32(__W,__U,__A);
-}
-__m512i test_mm512_maskz_conflict_epi32(__mmask16 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_maskz_conflict_epi32
- // CHECK: @llvm.x86.avx512.mask.conflict.d.512
- return _mm512_maskz_conflict_epi32(__U,__A);
-}
-__m512i test_mm512_lzcnt_epi32(__m512i __A) {
- // CHECK-LABEL: @test_mm512_lzcnt_epi32
- // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
- return _mm512_lzcnt_epi32(__A);
-}
-__m512i test_mm512_mask_lzcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_mask_lzcnt_epi32
- // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
- return _mm512_mask_lzcnt_epi32(__W,__U,__A);
-}
-__m512i test_mm512_maskz_lzcnt_epi32(__mmask16 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_maskz_lzcnt_epi32
- // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
- return _mm512_maskz_lzcnt_epi32(__U,__A);
-}
-__m512i test_mm512_lzcnt_epi64(__m512i __A) {
- // CHECK-LABEL: @test_mm512_lzcnt_epi64
- // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
- return _mm512_lzcnt_epi64(__A);
-}
-__m512i test_mm512_mask_lzcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_mask_lzcnt_epi64
- // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
- return _mm512_mask_lzcnt_epi64(__W,__U,__A);
-}
-__m512i test_mm512_maskz_lzcnt_epi64(__mmask8 __U, __m512i __A) {
- // CHECK-LABEL: @test_mm512_maskz_lzcnt_epi64
- // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
- return _mm512_maskz_lzcnt_epi64(__U,__A);
-}
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx512cd -emit-llvm -o - -Werror | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+__m512i test_mm512_conflict_epi64(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_conflict_epi64
+ // CHECK: @llvm.x86.avx512.mask.conflict.q.512
+ return _mm512_conflict_epi64(__A);
+}
+__m512i test_mm512_mask_conflict_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_conflict_epi64
+ // CHECK: @llvm.x86.avx512.mask.conflict.q.512
+ return _mm512_mask_conflict_epi64(__W,__U,__A);
+}
+__m512i test_mm512_maskz_conflict_epi64(__mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_conflict_epi64
+ // CHECK: @llvm.x86.avx512.mask.conflict.q.512
+ return _mm512_maskz_conflict_epi64(__U,__A);
+}
+__m512i test_mm512_conflict_epi32(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_conflict_epi32
+ // CHECK: @llvm.x86.avx512.mask.conflict.d.512
+ return _mm512_conflict_epi32(__A);
+}
+__m512i test_mm512_mask_conflict_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_conflict_epi32
+ // CHECK: @llvm.x86.avx512.mask.conflict.d.512
+ return _mm512_mask_conflict_epi32(__W,__U,__A);
+}
+__m512i test_mm512_maskz_conflict_epi32(__mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_conflict_epi32
+ // CHECK: @llvm.x86.avx512.mask.conflict.d.512
+ return _mm512_maskz_conflict_epi32(__U,__A);
+}
+__m512i test_mm512_lzcnt_epi32(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_lzcnt_epi32
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
+ return _mm512_lzcnt_epi32(__A);
+}
+__m512i test_mm512_mask_lzcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_lzcnt_epi32
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
+ return _mm512_mask_lzcnt_epi32(__W,__U,__A);
+}
+__m512i test_mm512_maskz_lzcnt_epi32(__mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_lzcnt_epi32
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.d.512
+ return _mm512_maskz_lzcnt_epi32(__U,__A);
+}
+__m512i test_mm512_lzcnt_epi64(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_lzcnt_epi64
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
+ return _mm512_lzcnt_epi64(__A);
+}
+__m512i test_mm512_mask_lzcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_lzcnt_epi64
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
+ return _mm512_mask_lzcnt_epi64(__W,__U,__A);
+}
+__m512i test_mm512_maskz_lzcnt_epi64(__mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_lzcnt_epi64
+ // CHECK: @llvm.x86.avx512.mask.lzcnt.q.512
+ return _mm512_maskz_lzcnt_epi64(__U,__A);
+}
diff --git a/test/CodeGen/avx512er-builtins.c b/test/CodeGen/avx512er-builtins.c
index fe8b20d..7c6b050 100644
--- a/test/CodeGen/avx512er-builtins.c
+++ b/test/CodeGen/avx512er-builtins.c
@@ -12,14 +12,14 @@
}
__m512d test_mm512_mask_rsqrt28_round_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_rsqrt28_round_pd
- // check: @llvm.x86.avx512.rsqrt28.pd
+ // CHECK-LABEL: @test_mm512_mask_rsqrt28_round_pd
+ // CHECK: @llvm.x86.avx512.rsqrt28.pd
return _mm512_mask_rsqrt28_round_pd(s, m, a, _MM_FROUND_TO_NEAREST_INT);
}
__m512d test_mm512_maskz_rsqrt28_round_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_rsqrt28_round_pd
- // check: @llvm.x86.avx512.rsqrt28.pd
+ // CHECK-LABEL: @test_mm512_maskz_rsqrt28_round_pd
+ // CHECK: @llvm.x86.avx512.rsqrt28.pd
return _mm512_maskz_rsqrt28_round_pd(m, a, _MM_FROUND_TO_NEAREST_INT);
}
@@ -30,14 +30,14 @@
}
__m512d test_mm512_mask_rsqrt28_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_rsqrt28_pd
- // check: @llvm.x86.avx512.rsqrt28.pd
+ // CHECK-LABEL: @test_mm512_mask_rsqrt28_pd
+ // CHECK: @llvm.x86.avx512.rsqrt28.pd
return _mm512_mask_rsqrt28_pd(s, m, a);
}
__m512d test_mm512_maskz_rsqrt28_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_rsqrt28_pd
- // check: @llvm.x86.avx512.rsqrt28.pd
+ // CHECK-LABEL: @test_mm512_maskz_rsqrt28_pd
+ // CHECK: @llvm.x86.avx512.rsqrt28.pd
return _mm512_maskz_rsqrt28_pd(m, a);
}
@@ -78,38 +78,38 @@
}
__m128 test_mm_rsqrt28_round_ss(__m128 a, __m128 b) {
- // check-label: @test_mm_rsqrt28_round_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_rsqrt28_round_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_rsqrt28_round_ss(a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_mask_rsqrt28_round_ss(__m128 s, __mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_mask_rsqrt28_round_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_mask_rsqrt28_round_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_mask_rsqrt28_round_ss(s, m, a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_maskz_rsqrt28_round_ss(__mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_maskz_rsqrt28_round_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_maskz_rsqrt28_round_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_maskz_rsqrt28_round_ss(m, a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_rsqrt28_ss(__m128 a, __m128 b) {
- // check-label: @test_mm_rsqrt28_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_rsqrt28_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_rsqrt28_ss(a, b);
}
__m128 test_mm_mask_rsqrt28_ss(__m128 s, __mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_mask_rsqrt28_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_mask_rsqrt28_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_mask_rsqrt28_ss(s, m, a, b);
}
__m128 test_mm_maskz_rsqrt28_ss(__mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_maskz_rsqrt28_ss
- // check: @llvm.x86.avx512.rsqrt28.ss
+ // CHECK-LABEL: @test_mm_maskz_rsqrt28_ss
+ // CHECK: @llvm.x86.avx512.rsqrt28.ss
return _mm_maskz_rsqrt28_ss(m, a, b);
}
@@ -138,14 +138,14 @@
}
__m512d test_mm512_mask_rcp28_round_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_rcp28_round_pd
- // check: @llvm.x86.avx512.rcp28.pd
+ // CHECK-LABEL: @test_mm512_mask_rcp28_round_pd
+ // CHECK: @llvm.x86.avx512.rcp28.pd
return _mm512_mask_rcp28_round_pd(s, m, a, _MM_FROUND_TO_NEAREST_INT);
}
__m512d test_mm512_maskz_rcp28_round_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_rcp28_round_pd
- // check: @llvm.x86.avx512.rcp28.pd
+ // CHECK-LABEL: @test_mm512_maskz_rcp28_round_pd
+ // CHECK: @llvm.x86.avx512.rcp28.pd
return _mm512_maskz_rcp28_round_pd(m, a, _MM_FROUND_TO_NEAREST_INT);
}
@@ -156,14 +156,14 @@
}
__m512d test_mm512_mask_rcp28_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_rcp28_pd
- // check: @llvm.x86.avx512.rcp28.pd
+ // CHECK-LABEL: @test_mm512_mask_rcp28_pd
+ // CHECK: @llvm.x86.avx512.rcp28.pd
return _mm512_mask_rcp28_pd(s, m, a);
}
__m512d test_mm512_maskz_rcp28_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_rcp28_pd
- // check: @llvm.x86.avx512.rcp28.pd
+ // CHECK-LABEL: @test_mm512_maskz_rcp28_pd
+ // CHECK: @llvm.x86.avx512.rcp28.pd
return _mm512_maskz_rcp28_pd(m, a);
}
@@ -204,38 +204,38 @@
}
__m128 test_mm_rcp28_round_ss(__m128 a, __m128 b) {
- // check-label: @test_mm_rcp28_round_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_rcp28_round_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_rcp28_round_ss(a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_mask_rcp28_round_ss(__m128 s, __mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_mask_rcp28_round_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_mask_rcp28_round_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_mask_rcp28_round_ss(s, m, a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_maskz_rcp28_round_ss(__mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_maskz_rcp28_round_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_maskz_rcp28_round_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_maskz_rcp28_round_ss(m, a, b, _MM_FROUND_TO_NEAREST_INT);
}
__m128 test_mm_rcp28_ss(__m128 a, __m128 b) {
- // check-label: @test_mm_rcp28_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_rcp28_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_rcp28_ss(a, b);
}
__m128 test_mm_mask_rcp28_ss(__m128 s, __mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_mask_rcp28_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_mask_rcp28_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_mask_rcp28_ss(s, m, a, b);
}
__m128 test_mm_maskz_rcp28_ss(__mmask16 m, __m128 a, __m128 b) {
- // check-label: @test_mm_maskz_rcp28_ss
- // check: @llvm.x86.avx512.rcp28.ss
+ // CHECK-LABEL: @test_mm_maskz_rcp28_ss
+ // CHECK: @llvm.x86.avx512.rcp28.ss
return _mm_maskz_rcp28_ss(m, a, b);
}
@@ -282,14 +282,14 @@
}
__m512d test_mm512_mask_exp2a23_round_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_exp2a23_round_pd
- // check: @llvm.x86.avx512.exp2.pd
+ // CHECK-LABEL: @test_mm512_mask_exp2a23_round_pd
+ // CHECK: @llvm.x86.avx512.exp2.pd
return _mm512_mask_exp2a23_round_pd(s, m, a, _MM_FROUND_TO_NEAREST_INT);
}
__m512d test_mm512_maskz_exp2a23_round_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_exp2a23_round_pd
- // check: @llvm.x86.avx512.exp2.pd
+ // CHECK-LABEL: @test_mm512_maskz_exp2a23_round_pd
+ // CHECK: @llvm.x86.avx512.exp2.pd
return _mm512_maskz_exp2a23_round_pd(m, a, _MM_FROUND_TO_NEAREST_INT);
}
@@ -300,14 +300,14 @@
}
__m512d test_mm512_mask_exp2a23_pd(__m512d s, __mmask8 m, __m512d a) {
- // check-label: @test_mm512_mask_exp2a23_pd
- // check: @llvm.x86.avx512.exp2.pd
+ // CHECK-LABEL: @test_mm512_mask_exp2a23_pd
+ // CHECK: @llvm.x86.avx512.exp2.pd
return _mm512_mask_exp2a23_pd(s, m, a);
}
__m512d test_mm512_maskz_exp2a23_pd(__mmask8 m, __m512d a) {
- // check-label: @test_mm512_maskz_exp2a23_pd
- // check: @llvm.x86.avx512.exp2.pd
+ // CHECK-LABEL: @test_mm512_maskz_exp2a23_pd
+ // CHECK: @llvm.x86.avx512.exp2.pd
return _mm512_maskz_exp2a23_pd(m, a);
}
diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c
index be56a8f..c1f4c0e 100644
--- a/test/CodeGen/avx512f-builtins.c
+++ b/test/CodeGen/avx512f-builtins.c
@@ -772,8 +772,8 @@
}
__mmask16 test_mm512_cmp_ps_mask(__m512 a, __m512 b) {
- // check-label: @test_mm512_cmp_ps_mask
- // check: @llvm.x86.avx512.mask.cmp.ps.512
+ // CHECK-LABEL: @test_mm512_cmp_ps_mask
+ // CHECKn: @llvm.x86.avx512.mask.cmp.ps.512
return _mm512_cmp_ps_mask(a, b, 0);
}
@@ -796,8 +796,8 @@
}
__mmask8 test_mm512_cmp_pd_mask(__m512d a, __m512d b) {
- // check-label: @test_mm512_cmp_pd_mask
- // check: @llvm.x86.avx512.mask.cmp.pd.512
+ // CHECK-LABEL: @test_mm512_cmp_pd_mask
+ // CHECK: @llvm.x86.avx512.mask.cmp.pd.512
return _mm512_cmp_pd_mask(a, b, 0);
}
diff --git a/test/CodeGen/avx512vl-builtins.c b/test/CodeGen/avx512vl-builtins.c
index 9d6237e..445513c 100644
--- a/test/CodeGen/avx512vl-builtins.c
+++ b/test/CodeGen/avx512vl-builtins.c
@@ -5,102 +5,6 @@
#include <immintrin.h>
-__mmask8 test_mm256_cmpeq_epi32_mask(__m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_cmpeq_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256
- return (__mmask8)_mm256_cmpeq_epi32_mask(__a, __b);
-}
-
-__mmask8 test_mm256_mask_cmpeq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_mask_cmpeq_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256
- return (__mmask8)_mm256_mask_cmpeq_epi32_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm_cmpeq_epi32_mask(__m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_cmpeq_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128
- return (__mmask8)_mm_cmpeq_epi32_mask(__a, __b);
-}
-
-__mmask8 test_mm_mask_cmpeq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_mask_cmpeq_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128
- return (__mmask8)_mm_mask_cmpeq_epi32_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm256_cmpeq_epi64_mask(__m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_cmpeq_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256
- return (__mmask8)_mm256_cmpeq_epi64_mask(__a, __b);
-}
-
-__mmask8 test_mm256_mask_cmpeq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_mask_cmpeq_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256
- return (__mmask8)_mm256_mask_cmpeq_epi64_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm_cmpeq_epi64_mask(__m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_cmpeq_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128
- return (__mmask8)_mm_cmpeq_epi64_mask(__a, __b);
-}
-
-__mmask8 test_mm_mask_cmpeq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_mask_cmpeq_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128
- return (__mmask8)_mm_mask_cmpeq_epi64_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm256_cmpgt_epi32_mask(__m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_cmpgt_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.256
- return (__mmask8)_mm256_cmpgt_epi32_mask(__a, __b);
-}
-
-__mmask8 test_mm256_mask_cmpgt_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_mask_cmpgt_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.256
- return (__mmask8)_mm256_mask_cmpgt_epi32_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm_cmpgt_epi32_mask(__m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_cmpgt_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.128
- return (__mmask8)_mm_cmpgt_epi32_mask(__a, __b);
-}
-
-__mmask8 test_mm_mask_cmpgt_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_mask_cmpgt_epi32_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.128
- return (__mmask8)_mm_mask_cmpgt_epi32_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm256_cmpgt_epi64_mask(__m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_cmpgt_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.256
- return (__mmask8)_mm256_cmpgt_epi64_mask(__a, __b);
-}
-
-__mmask8 test_mm256_mask_cmpgt_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {
- // CHECK-LABEL: @test_mm256_mask_cmpgt_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.256
- return (__mmask8)_mm256_mask_cmpgt_epi64_mask(__u, __a, __b);
-}
-
-__mmask8 test_mm_cmpgt_epi64_mask(__m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_cmpgt_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.128
- return (__mmask8)_mm_cmpgt_epi64_mask(__a, __b);
-}
-
-__mmask8 test_mm_mask_cmpgt_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {
- // CHECK-LABEL: @test_mm_mask_cmpgt_epi64_mask
- // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.128
- return (__mmask8)_mm_mask_cmpgt_epi64_mask(__u, __a, __b);
-}
-
__mmask8 test_mm_cmpeq_epu32_mask(__m128i __a, __m128i __b) {
// CHECK-LABEL: @test_mm_cmpeq_epu32_mask
// CHECK: @llvm.x86.avx512.mask.ucmp.d.128(<4 x i32> {{.*}}, <4 x i32> {{.*}}, i32 0, i8 -1)
diff --git a/test/CodeGen/builtins-ppc-vsx.c b/test/CodeGen/builtins-ppc-vsx.c
index 9a40d30..15f98b5 100644
--- a/test/CodeGen/builtins-ppc-vsx.c
+++ b/test/CodeGen/builtins-ppc-vsx.c
@@ -845,4 +845,51 @@
// CHECK: xor <2 x i64>
// CHECK-LE: xor <2 x i64>
+ res_vsll = vec_cts(vd, 0);
+// CHECK: fmul <2 x double>
+// CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptosi <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_cts(vd, 31);
+// CHECK: fmul <2 x double>
+// CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptosi <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_ctu(vd, 0);
+// CHECK: fmul <2 x double>
+// CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptoui <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_ctu(vd, 31);
+// CHECK: fmul <2 x double>
+// CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptoui <2 x double> %{{.*}} to <2 x i64>
+
+ res_vd = vec_ctf(vsll, 0);
+// CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vsll, 31);
+// CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vull, 0);
+// CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vull, 31);
+// CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
}
diff --git a/test/CodeGen/c-strings.c b/test/CodeGen/c-strings.c
index 974eeea..4e14d98 100644
--- a/test/CodeGen/c-strings.c
+++ b/test/CodeGen/c-strings.c
@@ -15,6 +15,11 @@
// MSABI: @f4.x = internal global %struct.s { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01??_C@_05CJBACGMB@hello?$AA@", i32 0, i32 0) }
// CHECK: @x = global [3 x i8] c"ola", align [[ALIGN]]
+// XFAIL: hexagon
+// Hexagon aligns arrays of size 8+ bytes to a 64-bit boundary, which
+// fails the check for "@f3.x = ... align [ALIGN]", since ALIGN is derived
+// from the alignment of a single i8, which is still 1.
+
#if defined(__s390x__)
unsigned char align = 2;
#else
diff --git a/test/CodeGen/c-unicode.c b/test/CodeGen/c-unicode.c
new file mode 100644
index 0000000..13d4bbf
--- /dev/null
+++ b/test/CodeGen/c-unicode.c
@@ -0,0 +1,8 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang --target=x86_64--linug-gnu -S %s -o - | FileCheck %s -check-prefix=ALLOWED
+// RUN: not %clang --target=x86_64--linux-gnu -std=c89 -S %s -o - 2>&1 | FileCheck %s -check-prefix=DENIED
+int \uaccess = 0;
+// ALLOWED: "곎ss":
+// ALLOWED-NOT: "\uaccess":
+// DENIED: warning: universal character names are only valid in C99 or C++; treating as '\' followed by identifier [-Wunicode]
+// DENIED: error: expected identifier or '('
diff --git a/test/CodeGen/captured-statements.c b/test/CodeGen/captured-statements.c
index 53632ac..607ec8e 100644
--- a/test/CodeGen/captured-statements.c
+++ b/test/CodeGen/captured-statements.c
@@ -21,7 +21,7 @@
// CHECK-1: %struct.anon = type { i32* }
// CHECK-1: {{.+}} global float 3.0
//
- // CHECK-1: test1
+ // CHECK-1: @test1(
// CHECK-1: alloca %struct.anon
// CHECK-1: getelementptr inbounds %struct.anon, %struct.anon*
// CHECK-1: store i32* %i
@@ -43,7 +43,7 @@
for (i = 0; i < x; i++)
foo();
}
- // CHECK-2: test2
+ // CHECK-2: @test2(
// CHECK-2-NOT: %i
// CHECK-2: call void @[[HelperName:__captured_stmt[\.0-9]+]]
}
@@ -60,7 +60,7 @@
{
arr[2] = vla_arr[size - 1];
}
- // CHECK-3: test3
+ // CHECK-3: @test3(
// CHECK-3: alloca [5 x i32]
// CHECK-3: call void @__captured_stmt
}
diff --git a/test/CodeGen/cfi-icall-cross-dso.c b/test/CodeGen/cfi-icall-cross-dso.c
new file mode 100644
index 0000000..9337b18
--- /dev/null
+++ b/test/CodeGen/cfi-icall-cross-dso.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -O1 -fsanitize=cfi-icall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -O1 -fsanitize=cfi-icall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
+
+void caller(void (*f)()) {
+ f();
+}
+
+static void g(void) {}
+void h(void);
+
+typedef void (*Fn)(void);
+Fn g1() {
+ return &g;
+}
+Fn h1() {
+ return &h;
+}
+
+inline void foo() {}
+void bar() { foo(); }
+
+// ITANIUM: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"_ZTSFvE"), !nosanitize
+// ITANIUM: call void @__cfi_slowpath(i64 6588678392271548388, i8* %{{.*}}) {{.*}}, !nosanitize
+
+// MS: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"?6AX@Z"), !nosanitize
+// MS: call void @__cfi_slowpath(i64 4195979634929632483, i8* %{{.*}}) {{.*}}, !nosanitize
+
+// ITANIUM: define available_externally void @foo()
+// MS: define linkonce_odr void @foo()
+
+// Check that we emit both string and hash based bit set entries for static void g(),
+// and don't emit them for the declaration of h().
+
+// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
+// CHECK: !{!"{{.*}}", void ()* @g, i64 0}
+// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
+// CHECK: !{i64 {{.*}}, void ()* @g, i64 0}
+// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
+
+// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
+// ITANIUM: !{!"_ZTSFvE", void ()* @bar, i64 0}
+// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
+// ITANIUM: !{i64 6588678392271548388, void ()* @bar, i64 0}
+// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
+
+// MS: !{!"?6AX@Z", void ()* @foo, i64 0}
+// MS: !{i64 4195979634929632483, void ()* @foo, i64 0}
+
+// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1}
diff --git a/test/CodeGen/debug-info-scope.c b/test/CodeGen/debug-info-scope.c
index af4b49b..a25f117 100644
--- a/test/CodeGen/debug-info-scope.c
+++ b/test/CodeGen/debug-info-scope.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -dwarf-version=4 -debug-info-kind=limited -emit-llvm < %s | FileCheck %s
-// RUN: %clang_cc1 -dwarf-version=4 -debug-info-kind=line-tables-only -emit-llvm < %s | FileCheck --check-prefix=GMLT %s
+// RUN: %clang_cc1 -dwarf-version=4 -debug-info-kind=limited -disable-llvm-passes -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -dwarf-version=4 -debug-info-kind=line-tables-only -disable-llvm-passes -emit-llvm < %s | FileCheck --check-prefix=GMLT %s
// Two variables with same name in separate scope.
// Radar 8330217.
int main() {
@@ -8,8 +8,6 @@
// CHECK: !DILocalVariable(name: "i"
// CHECK-NEXT: !DILexicalBlock(
-// GMLT-NOT: !DILexicalBlock
-// GMLT: !DILexicalBlockFile({{.*}}, discriminator: 1)
// Make sure we don't have any more lexical blocks because we don't need them in
// -gmlt.
// GMLT-NOT: !DILexicalBlock
diff --git a/test/CodeGen/dwarf-version.c b/test/CodeGen/dwarf-version.c
index eadce21..2171ed6 100644
--- a/test/CodeGen/dwarf-version.c
+++ b/test/CodeGen/dwarf-version.c
@@ -1,6 +1,7 @@
// RUN: %clang -target x86_64-linux-gnu -gdwarf-2 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
// RUN: %clang -target x86_64-linux-gnu -gdwarf-3 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER3
// RUN: %clang -target x86_64-linux-gnu -gdwarf-4 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
+// RUN: %clang -target x86_64-linux-gnu -gdwarf-5 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
// RUN: %clang -target x86_64-linux-gnu -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
// RUN: %clang -target x86_64-linux-gnu -gdwarf -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
// RUN: %clang -target x86_64-apple-darwin -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER2
@@ -18,6 +19,7 @@
// VER2: !{i32 2, !"Dwarf Version", i32 2}
// VER3: !{i32 2, !"Dwarf Version", i32 3}
// VER4: !{i32 2, !"Dwarf Version", i32 4}
+// VER5: !{i32 2, !"Dwarf Version", i32 5}
// NODWARF-NOT: !"Dwarf Version"
// CODEVIEW: !{i32 2, !"CodeView", i32 1}
diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c
index 03c04e6..f0ed223 100644
--- a/test/CodeGen/exceptions-seh-finally.c
+++ b/test/CodeGen/exceptions-seh-finally.c
@@ -25,12 +25,8 @@
// CHECK: [[lpad]]
// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK: invoke void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
-// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]]
-// CHECK: cleanupret %[[pad]] unwind to caller
-//
-// CHECK: [[end]]
-// CHECK: cleanupendpad %[[pad]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
+// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}})
// CHECK: call void @cleanup()
@@ -95,12 +91,8 @@
// CHECK: [[lpad]]
// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK: invoke void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
-// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]]
-// CHECK: cleanupret %[[pad]] unwind to caller
-//
-// CHECK: [[end]]
-// CHECK: cleanupendpad %[[pad]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
+// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer)
// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
@@ -141,12 +133,8 @@
//
// CHECK: [[lpad]]
// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
-// CHECK: invoke void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
-// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]]
-// CHECK: cleanupret %[[pad]] unwind to caller
-//
-// CHECK: [[end]]
-// CHECK: cleanupendpad %[[pad]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
+// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
// CHECK: call void @abort()
@@ -189,12 +177,8 @@
//
// CHECK: [[lpad]]
// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
-// CHECK: invoke void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
-// CHECK-NEXT: to label %{{.*}} unwind label %[[end:[^ ]*]]
-// CHECK: cleanupret %[[pad]] unwind to caller
-//
-// CHECK: [[end]]
-// CHECK: cleanupendpad %[[pad]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
+// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
// CHECK: ret void
@@ -231,24 +215,15 @@
// CHECK: [[lpad1]]
// CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad
// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})
-// CHECK-NEXT: to label %[[innercleanupretbb:[^ ]*]] unwind label %[[innerend:[^ ]*]]
+// CHECK-NEXT: label %[[innercleanupretbb:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
//
// CHECK: [[innercleanupretbb]]
-// CHECK-NEXT: cleanupret %[[innerpad]] unwind label %[[lpad2]]
-//
-// CHECK: [[innerend]]
-// CHECK-NEXT: cleanupendpad %[[innerpad]] unwind label %[[lpad2:[^ ]*]]
+// CHECK-NEXT: cleanupret from %[[innerpad]] unwind label %[[lpad2]]
//
// CHECK: [[lpad2]]
// CHECK-NEXT: %[[outerpad:[^ ]*]] = cleanuppad
-// CHECK: invoke void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
-// CHECK-NEXT: to label %[[outercleanupretbb:[^ ]*]] unwind label %[[outerend:[^ ]*]]
-//
-// CHECK: [[outercleanupretbb]]
-// CHECK-NEXT: cleanupret %[[outerpad]] unwind to caller
-//
-// CHECK: [[outerend]]
-// CHECK-NEXT: cleanupendpad %[[outerpad]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
+// CHECK-NEXT: cleanupret from %[[outerpad]] unwind to caller
// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
// CHECK: ret void
diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c
index 2895edb..a0b1956 100644
--- a/test/CodeGen/exceptions-seh-leave.c
+++ b/test/CodeGen/exceptions-seh-leave.c
@@ -160,20 +160,17 @@
// CHECK-NEXT: cleanuppad
// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]])
-// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[cleanupend:[^ ]*]]
+// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]
// CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]]
// CHECK: [[g2_lpad]]
-// CHECK: catchpad [i8* null]
+// CHECK: catchpad {{.*}} [i8* null]
// CHECK: catchret
// CHECK: br label %[[trycont]]
// CHECK: [[trycont]]
// CHECK-NEXT: ret i32 1
-// CHECK: [[cleanupend]]
-// CHECK-NEXT: cleanupendpad {{.*}} unwind label %[[g2_lpad]]
-
// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
// CHECK: call void @g()
// CHECK: unreachable
@@ -203,14 +200,14 @@
// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
// CHECK: [[g1_lpad]]
-// CHECK: catchpad [i8* null]
+// CHECK: catchpad {{.*}} [i8* null]
// CHECK: catchret {{.*}} to label %[[except:[^ ]*]]
// CHECK: [[except]]
// CHECK: invoke void @g()
// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
// CHECK: [[g2_lpad]]
-// CHECK: catchpad [i8* null]
+// CHECK: catchpad {{.*}} [i8* null]
// CHECK: catchret
// CHECK: br label %[[trycont4:[^ ]*]]
@@ -280,7 +277,7 @@
// CHECK: [[g2_lpad]]
// CHECK: cleanuppad
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]])
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]])
// CHECK: cleanupret {{.*}} unwind to caller
// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer)
@@ -323,21 +320,18 @@
// CHECK-NEXT: ret i32 1
// CHECK: [[g1_lpad]]
-// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad []
+// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []
// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
-// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[endcleanup:[^ ]*]]
+// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]
// CHECK: [[finally_cont2]]
-// CHECK: cleanupret %[[padtoken]] unwind label %[[g2_lpad]]
-
-// CHECK: [[endcleanup]]
-// CHECK-NEXT: cleanupendpad %[[padtoken]] unwind label %[[g2_lpad]]
+// CHECK: cleanupret from %[[padtoken]] unwind label %[[g2_lpad]]
// CHECK: [[g2_lpad]]
-// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad []
+// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []
// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
-// CHECK: cleanupret %[[padtoken]] unwind to caller
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
+// CHECK: cleanupret from %[[padtoken]] unwind to caller
// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
// CHECK: ret void
diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c
index 1a50ed0..b027bd8 100644
--- a/test/CodeGen/exceptions-seh.c
+++ b/test/CodeGen/exceptions-seh.c
@@ -34,12 +34,9 @@
// CHECK: to label %{{.*}} unwind label %[[catchpad:[^ ]*]]
//
// CHECK: [[catchpad]]
-// X64: %[[padtoken:[^ ]*]] = catchpad [i8* null]
-// X86: %[[padtoken:[^ ]*]] = catchpad [i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*)]
-// CHECK-NEXT: to label %[[exceptret:[^ ]*]] unwind label
-//
-// CHECK: [[exceptret]]
-// CHECK: catchret %[[padtoken]] to label %[[except:[^ ]*]]
+// X64: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [i8* null]
+// X86: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*)]
+// CHECK-NEXT: catchret from %[[padtoken]] to label %[[except:[^ ]*]]
//
// CHECK: [[except]]
// CHECK: store i32 -42, i32* %[[success:[^ ]*]]
@@ -85,14 +82,15 @@
// CHECK: store i32 42, i32* %[[r]]
// CHECK: invoke void @j() #[[NOINLINE]]
//
-// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*)]
+// CHECK: catchpad within %{{[^ ]*}} [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*)]
// CHECK: store i32 13, i32* %[[r]]
//
// CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]]
// CHECK: ret i32 %[[rv]]
// X64-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer)
-// X64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer, i32 0)
+// X64: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer)
+// X64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0)
//
// X86-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"()
// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
@@ -121,37 +119,37 @@
// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
// CHECK: store i32 42, i32* %[[r:[^ ,]*]]
// CHECK: invoke void @j() #[[NOINLINE]]
-// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cpad_inner:[^ ]*]]
+// CHECK: to label %[[cont:[^ ]*]] unwind label %[[cswitch_inner:[^ ]*]]
+//
+// CHECK: [[cswitch_inner]]
+// CHECK: %[[cs_inner:[^ ]*]] = catchswitch within none [label %[[cpad_inner:[^ ]*]]] unwind label %[[cswitch_outer:[^ ]*]]
+//
+// CHECK: [[cswitch_outer]]
+// CHECK: %[[cs_outer:[^ ]*]] = catchswitch within none [label %[[cpad_outer:[^ ]*]]] unwind to caller
+//
+// CHECK: [[cpad_outer]]
+// CHECK: catchpad within %{{[^ ]*}} [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)]
+// CHECK-NEXT: catchret {{.*}} to label %[[except_outer:[^ ]*]]
+//
+// CHECK: [[except_outer]]
+// CHECK: store i32 456, i32* %[[r]]
+// CHECK: br label %[[outer_try_cont:[^ ]*]]
+//
+// CHECK: [[outer_try_cont]]
+// CHECK: %[[r_load:[^ ]*]] = load i32, i32* %[[r]]
+// CHECK: ret i32 %[[r_load]]
//
// CHECK: [[cpad_inner]]
-// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)]
-// CHECK-NEXT: to label %[[exceptret_inner:[^ ]*]] unwind label %[[cpad_outer:[^ ]*]]
-//
-// CHECK: [[exceptret_inner]]
-// CHECK: catchret {{.*}} to label %[[except_inner:[^ ]*]]
+// CHECK: catchpad within %[[cs_inner]] [i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)]
+// CHECK-NEXT: catchret {{.*}} to label %[[except_inner:[^ ]*]]
//
// CHECK: [[except_inner]]
// CHECK: store i32 123, i32* %[[r]]
// CHECK: br label %[[inner_try_cont:[^ ]*]]
//
// CHECK: [[inner_try_cont]]
-// CHECK: br label %[[outer_try_cont:[^ ]*]]
-//
-// CHECK: [[cpad_outer]]
-// CHECK: catchpad [i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)]
-// CHECK-NEXT: to label %[[exceptret_outer:[^ ]*]] unwind label
-//
-// CHECK: [[exceptret_outer]]
-// CHECK: catchret {{.*}} to label %[[except_outer:[^ ]*]]
-//
-// CHECK: [[except_outer]]
-// CHECK: store i32 456, i32* %[[r]]
// CHECK: br label %[[outer_try_cont]]
//
-// CHECK: [[outer_try_cont]]
-// CHECK: %[[r_load:[^ ]*]] = load i32, i32* %[[r]]
-// CHECK: ret i32 %[[r_load]]
-//
// CHECK: [[cont]]
// CHECK: store i32 0, i32* %[[r]]
// CHECK: br label %[[inner_try_cont]]
@@ -193,14 +191,10 @@
// CHECK: ret i32
//
// CHECK: [[cleanuppad]]
-// CHECK: %[[padtoken:[^ ]*]] = cleanuppad []
+// CHECK: %[[padtoken:[^ ]*]] = cleanuppad within none []
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK: invoke void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
-// CHECK: to label %[[cleanupcont:[^ ]*]] unwind label %[[cleanupend:[^ ]*]]
-// CHECK: [[cleanupcont]]
-// CHECK: cleanupret %[[padtoken]] unwind to caller
-// CHECK: [[cleanupend]]
-// CHECK: cleanupendpad %[[padtoken]] unwind to caller
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
+// CHECK: cleanupret from %[[padtoken]] unwind to caller
// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} %abnormal_termination, i8* %frame_pointer)
// CHECK: call i8* @llvm.localrecover(i8* bitcast (i32 (i32)* @basic_finally to i8*), i8* %frame_pointer, i32 0)
@@ -278,7 +272,7 @@
// CHECK: %[[code_slot:[^ ]*]] = alloca i32
// CHECK: invoke void @try_body(i32 0, i32 0, i32* null)
// CHECK: %[[pad:[^ ]*]] = catchpad
-// CHECK: catchret %[[pad]]
+// CHECK: catchret from %[[pad]]
// X64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]])
// X64: store i32 %[[code]], i32* %[[code_slot]]
// CHECK: %[[ret1:[^ ]*]] = load i32, i32* %[[code_slot]]
diff --git a/test/CodeGen/f16c-builtins.c b/test/CodeGen/f16c-builtins.c
index 79314a8..f9cfa0d 100644
--- a/test/CodeGen/f16c-builtins.c
+++ b/test/CodeGen/f16c-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +f16c -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +f16c -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -8,25 +6,25 @@
#include <x86intrin.h>
__m128 test_mm_cvtph_ps(__m128i a) {
+ // CHECK-LABEL: test_mm_cvtph_ps
// CHECK: @llvm.x86.vcvtph2ps.128
- // CHECK-ASM: vcvtph2ps %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtph_ps(a);
}
__m256 test_mm256_cvtph_ps(__m128i a) {
+ // CHECK-LABEL: test_mm256_cvtph_ps
// CHECK: @llvm.x86.vcvtph2ps.256
- // CHECK-ASM: vcvtph2ps %xmm{{.*}}, %ymm{{.*}}
return _mm256_cvtph_ps(a);
}
__m128i test_mm_cvtps_ph(__m128 a) {
+ // CHECK-LABEL: test_mm_cvtps_ph
// CHECK: @llvm.x86.vcvtps2ph.128
- // CHECK-ASM: vcvtps2ph $0, %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtps_ph(a, 0);
}
__m128i test_mm256_cvtps_ph(__m256 a) {
+ // CHECK-LABEL: test_mm256_cvtps_ph
// CHECK: @llvm.x86.vcvtps2ph.256
- // CHECK-ASM: vcvtps2ph $0, %ymm{{.*}}, %xmm{{.*}}
return _mm256_cvtps_ph(a, 0);
}
diff --git a/test/CodeGen/fma4-builtins.c b/test/CodeGen/fma4-builtins.c
index 27cd093..69cbcd8 100644
--- a/test/CodeGen/fma4-builtins.c
+++ b/test/CodeGen/fma4-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +fma4 -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +fma4 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -8,193 +6,193 @@
#include <x86intrin.h>
__m128 test_mm_macc_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_macc_ps
// CHECK: @llvm.x86.fma.vfmadd.ps
- // CHECK-ASM: vfmaddps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_ps(a, b, c);
}
__m128d test_mm_macc_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_macc_pd
// CHECK: @llvm.x86.fma.vfmadd.pd
- // CHECK-ASM: vfmaddpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_pd(a, b, c);
}
__m128 test_mm_macc_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_macc_ss
// CHECK: @llvm.x86.fma.vfmadd.ss
- // CHECK-ASM: vfmaddss %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_ss(a, b, c);
}
__m128d test_mm_macc_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_macc_sd
// CHECK: @llvm.x86.fma.vfmadd.sd
- // CHECK-ASM: vfmaddsd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_sd(a, b, c);
}
__m128 test_mm_msub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_msub_ps
// CHECK: @llvm.x86.fma.vfmsub.ps
- // CHECK-ASM: vfmsubps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msub_ps(a, b, c);
}
__m128d test_mm_msub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_msub_pd
// CHECK: @llvm.x86.fma.vfmsub.pd
- // CHECK-ASM: vfmsubpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msub_pd(a, b, c);
}
__m128 test_mm_msub_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_msub_ss
// CHECK: @llvm.x86.fma.vfmsub.ss
- // CHECK-ASM: vfmsubss %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msub_ss(a, b, c);
}
__m128d test_mm_msub_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_msub_sd
// CHECK: @llvm.x86.fma.vfmsub.sd
- // CHECK-ASM: vfmsubsd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msub_sd(a, b, c);
}
__m128 test_mm_nmacc_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_nmacc_ps
// CHECK: @llvm.x86.fma.vfnmadd.ps
- // CHECK-ASM: vfnmaddps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmacc_ps(a, b, c);
}
__m128d test_mm_nmacc_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_nmacc_pd
// CHECK: @llvm.x86.fma.vfnmadd.pd
- // CHECK-ASM: vfnmaddpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmacc_pd(a, b, c);
}
__m128 test_mm_nmacc_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_nmacc_ss
// CHECK: @llvm.x86.fma.vfnmadd.ss
- // CHECK-ASM: vfnmaddss %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmacc_ss(a, b, c);
}
__m128d test_mm_nmacc_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_nmacc_sd
// CHECK: @llvm.x86.fma.vfnmadd.sd
- // CHECK-ASM: vfnmaddsd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmacc_sd(a, b, c);
}
__m128 test_mm_nmsub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_nmsub_ps
// CHECK: @llvm.x86.fma.vfnmsub.ps
- // CHECK-ASM: vfnmsubps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmsub_ps(a, b, c);
}
__m128d test_mm_nmsub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_nmsub_pd
// CHECK: @llvm.x86.fma.vfnmsub.pd
- // CHECK-ASM: vfnmsubpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmsub_pd(a, b, c);
}
__m128 test_mm_nmsub_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_nmsub_ss
// CHECK: @llvm.x86.fma.vfnmsub.ss
- // CHECK-ASM: vfnmsubss %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmsub_ss(a, b, c);
}
__m128d test_mm_nmsub_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_nmsub_sd
// CHECK: @llvm.x86.fma.vfnmsub.sd
- // CHECK-ASM: vfnmsubsd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_nmsub_sd(a, b, c);
}
__m128 test_mm_maddsub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_maddsub_ps
// CHECK: @llvm.x86.fma.vfmaddsub.ps
- // CHECK-ASM: vfmaddsubps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maddsub_ps(a, b, c);
}
__m128d test_mm_maddsub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_maddsub_pd
// CHECK: @llvm.x86.fma.vfmaddsub.pd
- // CHECK-ASM: vfmaddsubpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maddsub_pd(a, b, c);
}
__m128 test_mm_msubadd_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK-LABEL: test_mm_msubadd_ps
// CHECK: @llvm.x86.fma.vfmsubadd.ps
- // CHECK-ASM: vfmsubaddps %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msubadd_ps(a, b, c);
}
__m128d test_mm_msubadd_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK-LABEL: test_mm_msubadd_pd
// CHECK: @llvm.x86.fma.vfmsubadd.pd
- // CHECK-ASM: vfmsubaddpd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_msubadd_pd(a, b, c);
}
__m256 test_mm256_macc_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_macc_ps
// CHECK: @llvm.x86.fma.vfmadd.ps.256
- // CHECK-ASM: vfmaddps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_macc_ps(a, b, c);
}
__m256d test_mm256_macc_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_macc_pd
// CHECK: @llvm.x86.fma.vfmadd.pd.256
- // CHECK-ASM: vfmaddpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_macc_pd(a, b, c);
}
__m256 test_mm256_msub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_msub_ps
// CHECK: @llvm.x86.fma.vfmsub.ps.256
- // CHECK-ASM: vfmsubps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_msub_ps(a, b, c);
}
__m256d test_mm256_msub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_msub_pd
// CHECK: @llvm.x86.fma.vfmsub.pd.256
- // CHECK-ASM: vfmsubpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_msub_pd(a, b, c);
}
__m256 test_mm256_nmacc_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_nmacc_ps
// CHECK: @llvm.x86.fma.vfnmadd.ps.256
- // CHECK-ASM: vfnmaddps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_nmacc_ps(a, b, c);
}
__m256d test_mm256_nmacc_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_nmacc_pd
// CHECK: @llvm.x86.fma.vfnmadd.pd.256
- // CHECK-ASM: vfnmaddpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_nmacc_pd(a, b, c);
}
__m256 test_mm256_nmsub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_nmsub_ps
// CHECK: @llvm.x86.fma.vfnmsub.ps.256
- // CHECK-ASM: vfnmsubps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_nmsub_ps(a, b, c);
}
__m256d test_mm256_nmsub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_nmsub_pd
// CHECK: @llvm.x86.fma.vfnmsub.pd.256
- // CHECK-ASM: vfnmsubpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_nmsub_pd(a, b, c);
}
__m256 test_mm256_maddsub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_maddsub_ps
// CHECK: @llvm.x86.fma.vfmaddsub.ps.256
- // CHECK-ASM: vfmaddsubps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_maddsub_ps(a, b, c);
}
__m256d test_mm256_maddsub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_maddsub_pd
// CHECK: @llvm.x86.fma.vfmaddsub.pd.256
- // CHECK-ASM: vfmaddsubpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_maddsub_pd(a, b, c);
}
__m256 test_mm256_msubadd_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK-LABEL: test_mm256_msubadd_ps
// CHECK: @llvm.x86.fma.vfmsubadd.ps.256
- // CHECK-ASM: vfmsubaddps %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_msubadd_ps(a, b, c);
}
__m256d test_mm256_msubadd_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK-LABEL: test_mm256_msubadd_pd
// CHECK: @llvm.x86.fma.vfmsubadd.pd.256
- // CHECK-ASM: vfmsubaddpd %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_msubadd_pd(a, b, c);
}
diff --git a/test/CodeGen/fp-contract-pragma.cpp b/test/CodeGen/fp-contract-pragma.cpp
index b4e24b9..1c5921a 100644
--- a/test/CodeGen/fp-contract-pragma.cpp
+++ b/test/CodeGen/fp-contract-pragma.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
-// Is FP_CONTRACT is honored in a simple case?
+// Is FP_CONTRACT honored in a simple case?
float fp_contract_1(float a, float b, float c) {
// CHECK: _Z13fp_contract_1fff
// CHECK: tail call float @llvm.fmuladd
@@ -19,7 +19,7 @@
return a * b + c;
}
-// Does FP_CONTRACT survive template instatiation?
+// Does FP_CONTRACT survive template instantiation?
class Foo {};
Foo operator+(Foo, Foo);
@@ -62,3 +62,15 @@
return a * b + c;
}
+// If the multiply has multiple uses, don't produce fmuladd.
+// This used to assert (PR25719):
+// https://llvm.org/bugs/show_bug.cgi?id=25719
+
+float fp_contract_7(float a, float b, float c) {
+// CHECK: _Z13fp_contract_7fff
+// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
+// CHECK-NEXT: fsub float %[[M]], %c
+ #pragma STDC FP_CONTRACT ON
+ return (a = 2 * b) - c;
+}
+
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 177ad84..8f682a7 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -Os -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -Os -std=c99 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-optzns -Os -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-optzns -Os -std=c99 -o - %s | FileCheck %s
// CHECK: define signext i8 @f0(i32 %x) [[NUW:#[0-9]+]]
// CHECK: define zeroext i8 @f1(i32 %x) [[NUW]]
// CHECK: define void @f2(i8 signext %x) [[NUW]]
@@ -56,31 +56,11 @@
return arg ? 0 : f10_t();
}
-// CHECK: define void @f13() [[NUW]]
+// CHECK: define void @f13() [[NUW_OS_RN:#[0-9]+]]
void f13(void) __attribute__((pure)) __attribute__((const));
void f13(void){}
-// Ensure that these get inlined: rdar://6853279
-// CHECK-LABEL: define void @f14
-// CHECK-NOT: @ai_
-// CHECK: call void @f14_end
-static __inline__ __attribute__((always_inline))
-int ai_1() { return 4; }
-
-static __inline__ __attribute__((always_inline))
-struct {
- int a, b, c, d, e;
-} ai_2() { while (1) {} }
-
-void f14(int a) {
- extern void f14_end(void);
- if (a)
- ai_2();
- ai_1();
- f14_end();
-}
-
// <rdar://problem/7102668> [irgen] clang isn't setting the optsize bit on functions
// CHECK-LABEL: define void @f15
// CHECK: [[NUW]]
@@ -128,10 +108,11 @@
_setjmp(0);
}
-// CHECK: attributes [[NUW]] = { nounwind optsize readnone{{.*}} }
-// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize readnone{{.*}} }
-// CHECK: attributes [[ALIGN]] = { nounwind optsize readnone alignstack=16{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} }
+// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} }
+// CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} }
+// CHECK: attributes [[ALIGN]] = { nounwind optsize alignstack=16{{.*}} }
// CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
-// CHECK: attributes [[NR]] = { noreturn nounwind optsize }
+// CHECK: attributes [[NR]] = { noreturn optsize }
// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone }
-// CHECK: attributes [[RT_CALL]] = { nounwind optsize returns_twice }
+// CHECK: attributes [[RT_CALL]] = { optsize returns_twice }
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index a2b4920..5d08672 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -1,5 +1,16 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+struct I { int k[3]; };
+struct M { struct I o[2]; };
+struct M v1[1] = { [0].o[0 ... 1].k[0 ... 1] = 4, 5 };
+unsigned v2[2][3] = {[0 ... 1][0 ... 1] = 2222, 3333};
+
+// CHECK-DAG: %struct.M = type { [2 x %struct.I] }
+// CHECK-DAG: %struct.I = type { [3 x i32] }
+
+// CHECK: [1 x %struct.M] [%struct.M { [2 x %struct.I] [%struct.I { [3 x i32] [i32 4, i32 4, i32 0] }, %struct.I { [3 x i32] [i32 4, i32 4, i32 5] }] }],
+// CHECK: [2 x [3 x i32]] {{[[][[]}}3 x i32] [i32 2222, i32 2222, i32 0], [3 x i32] [i32 2222, i32 2222, i32 3333]],
+
void f1() {
// Scalars in braces.
int a = { 1 };
diff --git a/test/CodeGen/libcalls-complex.c b/test/CodeGen/libcalls-complex.c
index 22c97b6..43b7055 100644
--- a/test/CodeGen/libcalls-complex.c
+++ b/test/CodeGen/libcalls-complex.c
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fno-builtin -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
+// RUN: %clang_cc1 -fno-builtin-crealf -fno-builtin-creal -fno-builtin-creall \
+// RUN: -fno-builtin-cimagf -fno-builtin-cimag -fno-builtin-cimagl -emit-llvm \
+// RUN: -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-NO %s
extern float crealf(float _Complex);
diff --git a/test/CodeGen/libcalls-fno-builtin.c b/test/CodeGen/libcalls-fno-builtin.c
index e7f3ef7..bc6a430 100644
--- a/test/CodeGen/libcalls-fno-builtin.c
+++ b/test/CodeGen/libcalls-fno-builtin.c
@@ -1,4 +1,11 @@
// RUN: %clang_cc1 -S -O3 -fno-builtin -o - %s | FileCheck %s
+// RUN: %clang_cc1 -S -O3 -fno-builtin-ceil -fno-builtin-copysign -fno-builtin-cos \
+// RUN: -fno-builtin-fabs -fno-builtin-floor -fno-builtin-strcat -fno-builtin-strncat \
+// RUN: -fno-builtin-strchr -fno-builtin-strrchr -fno-builtin-strcmp -fno-builtin-strncmp \
+// RUN: -fno-builtin-strcpy -fno-builtin-stpcpy -fno-builtin-strncpy -fno-builtin-strlen \
+// RUN: -fno-builtin-strpbrk -fno-builtin-strspn -fno-builtin-strtod -fno-builtin-strtof \
+// RUN: -fno-builtin-strtold -fno-builtin-strtol -fno-builtin-strtoll -fno-builtin-strtoul \
+// RUN: -fno-builtin-strtoull -o - %s | FileCheck %s
// rdar://10551066
typedef __SIZE_TYPE__ size_t;
diff --git a/test/CodeGen/linker-option.c b/test/CodeGen/linker-option.c
new file mode 100644
index 0000000..b1b2ec4
--- /dev/null
+++ b/test/CodeGen/linker-option.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
+
+// CHECK: !llvm.module.flags = !{{{.*}}}
+// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
+// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// CHECK: ![[msvcrt]] = !{!"/include:foo"}
+
+int f();
diff --git a/test/CodeGen/mips-interrupt-attr.c b/test/CodeGen/mips-interrupt-attr.c
new file mode 100644
index 0000000..df70b12
--- /dev/null
+++ b/test/CodeGen/mips-interrupt-attr.c
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple mipsel-unknown-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK
+
+void __attribute__ ((interrupt("vector=sw0")))
+isr_sw0 (void)
+{
+ // CHECK: define void @isr_sw0() [[SW0:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=sw1")))
+isr_sw1 (void)
+{
+ // CHECK: define void @isr_sw1() [[SW1:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw0")))
+isr_hw0 (void)
+{
+ // CHECK: define void @isr_hw0() [[HW0:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw1")))
+isr_hw1 (void)
+{
+ // CHECK: define void @isr_hw1() [[HW1:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw2")))
+isr_hw2 (void)
+{
+ // CHECK: define void @isr_hw2() [[HW2:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw3")))
+isr_hw3 (void)
+{
+ // CHECK: define void @isr_hw3() [[HW3:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw4")))
+isr_hw4 (void)
+{
+ // CHECK: define void @isr_hw4() [[HW4:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt("vector=hw5")))
+isr_hw5 (void)
+{
+ // CHECK: define void @isr_hw5() [[HW5:#[0-9]+]]
+}
+
+void __attribute__ ((interrupt))
+isr_eic (void)
+{
+ // CHECK: define void @isr_eic() [[EIC:#[0-9]+]]
+}
+// CHECK: attributes [[SW0]] = { {{.*}} "interrupt"="sw0" {{.*}} }
+// CHECK: attributes [[SW1]] = { {{.*}} "interrupt"="sw1" {{.*}} }
+// CHECK: attributes [[HW0]] = { {{.*}} "interrupt"="hw0" {{.*}} }
+// CHECK: attributes [[HW1]] = { {{.*}} "interrupt"="hw1" {{.*}} }
+// CHECK: attributes [[HW2]] = { {{.*}} "interrupt"="hw2" {{.*}} }
+// CHECK: attributes [[HW3]] = { {{.*}} "interrupt"="hw3" {{.*}} }
+// CHECK: attributes [[HW4]] = { {{.*}} "interrupt"="hw4" {{.*}} }
+// CHECK: attributes [[HW5]] = { {{.*}} "interrupt"="hw5" {{.*}} }
+// CHECK: attributes [[EIC]] = { {{.*}} "interrupt"="eic" {{.*}} }
diff --git a/test/CodeGen/mmx-builtins.c b/test/CodeGen/mmx-builtins.c
index 1620fe0..44d1ea4 100644
--- a/test/CodeGen/mmx-builtins.c
+++ b/test/CodeGen/mmx-builtins.c
@@ -1,464 +1,608 @@
-// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -S -o - | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -fno-signed-char -S -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -emit-llvm -o - -Werror | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s
-// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
-// on win32 since we don't generally know how to find errno.h.
+// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
-#include <tmmintrin.h>
+#include <x86intrin.h>
-__m64 test1(__m64 a, __m64 b) {
- // CHECK: phaddw
- return _mm_hadd_pi16(a, b);
-}
-
-__m64 test2(__m64 a, __m64 b) {
- // CHECK: phaddd
- return _mm_hadd_pi32(a, b);
-}
-
-__m64 test3(__m64 a, __m64 b) {
- // CHECK: phaddsw
- return _mm_hadds_pi16(a, b);
-}
-
-__m64 test4(__m64 a, __m64 b) {
- // CHECK: phsubw
- return _mm_hsub_pi16(a, b);
-}
-
-__m64 test5(__m64 a, __m64 b) {
- // CHECK: phsubd
- return _mm_hsub_pi32(a, b);
-}
-
-__m64 test6(__m64 a, __m64 b) {
- // CHECK: phsubsw
- return _mm_hsubs_pi16(a, b);
-}
-
-__m64 test7(__m64 a, __m64 b) {
- // CHECK: pmaddubsw
- return _mm_maddubs_pi16(a, b);
-}
-
-__m64 test8(__m64 a, __m64 b) {
- // CHECK: pmulhrsw
- return _mm_mulhrs_pi16(a, b);
-}
-
-__m64 test9(__m64 a, __m64 b) {
- // CHECK: pshufb
- return _mm_shuffle_pi8(a, b);
-}
-
-__m64 test10(__m64 a, __m64 b) {
- // CHECK: psignb
- return _mm_sign_pi8(a, b);
-}
-
-__m64 test11(__m64 a, __m64 b) {
- // CHECK: psignw
- return _mm_sign_pi16(a, b);
-}
-
-__m64 test12(__m64 a, __m64 b) {
- // CHECK: psignd
- return _mm_sign_pi32(a, b);
-}
-
-__m64 test13(__m64 a) {
- // CHECK: pabsb
+__m64 test_mm_abs_pi8(__m64 a) {
+ // CHECK-LABEL: test_mm_abs_pi8
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pabs.b
return _mm_abs_pi8(a);
}
-__m64 test14(__m64 a) {
- // CHECK: pabsw
+__m64 test_mm_abs_pi16(__m64 a) {
+ // CHECK-LABEL: test_mm_abs_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pabs.w
return _mm_abs_pi16(a);
}
-__m64 test15(__m64 a) {
- // CHECK: pabsd
+__m64 test_mm_abs_pi32(__m64 a) {
+ // CHECK-LABEL: test_mm_abs_pi32
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pabs.d
return _mm_abs_pi32(a);
}
-__m64 test16(__m64 a, __m64 b) {
- // CHECK: palignr
- return _mm_alignr_pi8(a, b, 2);
-}
-
-__m64 test17(__m128d a) {
- // CHECK: cvtpd2pi
- return _mm_cvtpd_pi32(a);
-}
-
-__m64 test18(__m128d a) {
- // CHECK: cvttpd2pi
- return _mm_cvttpd_pi32(a);
-}
-
-__m128d test19(__m64 a) {
- // CHECK: cvtpi2pd
- return _mm_cvtpi32_pd(a);
-}
-
-__m64 test20(__m64 a, __m64 b) {
- // CHECK: pmuludq
- return _mm_mul_su32(a, b);
-}
-
-__m64 test21(__m64 a) {
- // CHECK: pshufw
- return _mm_shuffle_pi16(a, 3);
-}
-
-__m64 test22(__m64 a, __m64 b) {
- // CHECK: pmulhuw
- return _mm_mulhi_pu16(a, b);
-}
-
-void test23(__m64 d, __m64 n, char *p) {
- // CHECK: maskmovq
- _mm_maskmove_si64(d, n, p);
-}
-
-int test24(__m64 a) {
- // CHECK: pmovmskb
- return _mm_movemask_pi8(a);
-}
-
-void test25(__m64 *p, __m64 a) {
- // CHECK: movntq
- _mm_stream_pi(p, a);
-}
-
-__m64 test26(__m64 a, __m64 b) {
- // CHECK: pavgb
- return _mm_avg_pu8(a, b);
-}
-
-__m64 test27(__m64 a, __m64 b) {
- // CHECK: pavgw
- return _mm_avg_pu16(a, b);
-}
-
-__m64 test28(__m64 a, __m64 b) {
- // CHECK: pmaxub
- return _mm_max_pu8(a, b);
-}
-
-__m64 test29(__m64 a, __m64 b) {
- // CHECK: pmaxsw
- return _mm_max_pi16(a, b);
-}
-
-__m64 test30(__m64 a, __m64 b) {
- // CHECK: pminub
- return _mm_min_pu8(a, b);
-}
-
-__m64 test31(__m64 a, __m64 b) {
- // CHECK: pminsw
- return _mm_min_pi16(a, b);
-}
-
-__m64 test32(__m64 a, __m64 b) {
- // CHECK: psadbw
- return _mm_sad_pu8(a, b);
-}
-
-__m64 test33(__m64 a, __m64 b) {
- // CHECK: paddb
+__m64 test_mm_add_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_add_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.padd.b
return _mm_add_pi8(a, b);
}
-__m64 test34(__m64 a, __m64 b) {
- // CHECK: paddw
+__m64 test_mm_add_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_add_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.padd.w
return _mm_add_pi16(a, b);
}
-__m64 test35(__m64 a, __m64 b) {
- // CHECK: paddd
+__m64 test_mm_add_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_add_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.padd.d
return _mm_add_pi32(a, b);
}
-__m64 test36(__m64 a, __m64 b) {
- // CHECK: paddq
+__m64 test_mm_add_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_add_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.padd.q
return __builtin_ia32_paddq(a, b);
}
-__m64 test37(__m64 a, __m64 b) {
- // CHECK: paddsb
+__m64 test_mm_adds_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_adds_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.padds.b
return _mm_adds_pi8(a, b);
}
-__m64 test38(__m64 a, __m64 b) {
- // CHECK: paddsw
+__m64 test_mm_adds_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_adds_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.padds.w
return _mm_adds_pi16(a, b);
}
-__m64 test39(__m64 a, __m64 b) {
- // CHECK: paddusb
+__m64 test_mm_adds_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_adds_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.paddus.b
return _mm_adds_pu8(a, b);
}
-__m64 test40(__m64 a, __m64 b) {
- // CHECK: paddusw
+__m64 test_mm_adds_pu16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_adds_pu16
+ // CHECK: call x86_mmx @llvm.x86.mmx.paddus.w
return _mm_adds_pu16(a, b);
}
-__m64 test41(__m64 a, __m64 b) {
- // CHECK: psubb
- return _mm_sub_pi8(a, b);
+__m64 test_mm_alignr_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_alignr_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.palignr.b
+ return _mm_alignr_pi8(a, b, 2);
}
-__m64 test42(__m64 a, __m64 b) {
- // CHECK: psubw
- return _mm_sub_pi16(a, b);
-}
-
-__m64 test43(__m64 a, __m64 b) {
- // CHECK: psubd
- return _mm_sub_pi32(a, b);
-}
-
-__m64 test44(__m64 a, __m64 b) {
- // CHECK: psubq
- return __builtin_ia32_psubq(a, b);
-}
-
-__m64 test45(__m64 a, __m64 b) {
- // CHECK: psubsb
- return _mm_subs_pi8(a, b);
-}
-
-__m64 test46(__m64 a, __m64 b) {
- // CHECK: psubsw
- return _mm_subs_pi16(a, b);
-}
-
-__m64 test47(__m64 a, __m64 b) {
- // CHECK: psubusb
- return _mm_subs_pu8(a, b);
-}
-
-__m64 test48(__m64 a, __m64 b) {
- // CHECK: psubusw
- return _mm_subs_pu16(a, b);
-}
-
-__m64 test49(__m64 a, __m64 b) {
- // CHECK: pmaddwd
- return _mm_madd_pi16(a, b);
-}
-
-__m64 test50(__m64 a, __m64 b) {
- // CHECK: pmulhw
- return _mm_mulhi_pi16(a, b);
-}
-
-__m64 test51(__m64 a, __m64 b) {
- // CHECK: pmullw
- return _mm_mullo_pi16(a, b);
-}
-
-__m64 test52(__m64 a, __m64 b) {
- // CHECK: pmullw
- return _mm_mullo_pi16(a, b);
-}
-
-__m64 test53(__m64 a, __m64 b) {
- // CHECK: pand
+__m64 test_mm_and_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_and_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.pand
return _mm_and_si64(a, b);
}
-__m64 test54(__m64 a, __m64 b) {
- // CHECK: pandn
+__m64 test_mm_andnot_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_andnot_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.pandn
return _mm_andnot_si64(a, b);
}
-__m64 test55(__m64 a, __m64 b) {
- // CHECK: por
- return _mm_or_si64(a, b);
-}
-
-__m64 test56(__m64 a, __m64 b) {
- // CHECK: pxor
- return _mm_xor_si64(a, b);
-}
-
-__m64 test57(__m64 a, __m64 b) {
- // CHECK: pavgb
+__m64 test_mm_avg_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_avg_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.pavg.b
return _mm_avg_pu8(a, b);
}
-__m64 test58(__m64 a, __m64 b) {
- // CHECK: pavgw
+__m64 test_mm_avg_pu16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_avg_pu16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pavg.w
return _mm_avg_pu16(a, b);
}
-__m64 test59(__m64 a, __m64 b) {
- // CHECK: psllw
- return _mm_sll_pi16(a, b);
-}
-
-__m64 test60(__m64 a, __m64 b) {
- // CHECK: pslld
- return _mm_sll_pi32(a, b);
-}
-
-__m64 test61(__m64 a, __m64 b) {
- // CHECK: psllq
- return _mm_sll_si64(a, b);
-}
-
-__m64 test62(__m64 a, __m64 b) {
- // CHECK: psrlw
- return _mm_srl_pi16(a, b);
-}
-
-__m64 test63(__m64 a, __m64 b) {
- // CHECK: psrld
- return _mm_srl_pi32(a, b);
-}
-
-__m64 test64(__m64 a, __m64 b) {
- // CHECK: psrlq
- return _mm_srl_si64(a, b);
-}
-
-__m64 test65(__m64 a, __m64 b) {
- // CHECK: psraw
- return _mm_sra_pi16(a, b);
-}
-
-__m64 test66(__m64 a, __m64 b) {
- // CHECK: psrad
- return _mm_sra_pi32(a, b);
-}
-
-__m64 test67(__m64 a) {
- // CHECK: psllw
- return _mm_slli_pi16(a, 3);
-}
-
-__m64 test68(__m64 a) {
- // CHECK: pslld
- return _mm_slli_pi32(a, 3);
-}
-
-__m64 test69(__m64 a) {
- // CHECK: psllq
- return _mm_slli_si64(a, 3);
-}
-
-__m64 test70(__m64 a) {
- // CHECK: psrlw
- return _mm_srli_pi16(a, 3);
-}
-
-__m64 test71(__m64 a) {
- // CHECK: psrld
- return _mm_srli_pi32(a, 3);
-}
-
-__m64 test72(__m64 a) {
- // CHECK: psrlq
- return _mm_srli_si64(a, 3);
-}
-
-__m64 test73(__m64 a) {
- // CHECK: psraw
- return _mm_srai_pi16(a, 3);
-}
-
-__m64 test74(__m64 a) {
- // CHECK: psrad
- return _mm_srai_pi32(a, 3);
-}
-
-__m64 test75(__m64 a, __m64 b) {
- // CHECK: packsswb
- return _mm_packs_pi16(a, b);
-}
-
-__m64 test76(__m64 a, __m64 b) {
- // CHECK: packssdw
- return _mm_packs_pi32(a, b);
-}
-
-__m64 test77(__m64 a, __m64 b) {
- // CHECK: packuswb
- return _mm_packs_pu16(a, b);
-}
-
-__m64 test78(__m64 a, __m64 b) {
- // CHECK: punpckhbw
- return _mm_unpackhi_pi8(a, b);
-}
-
-__m64 test79(__m64 a, __m64 b) {
- // CHECK: punpckhwd
- return _mm_unpackhi_pi16(a, b);
-}
-
-__m64 test80(__m64 a, __m64 b) {
- // CHECK: punpckhdq
- return _mm_unpackhi_pi32(a, b);
-}
-
-__m64 test81(__m64 a, __m64 b) {
- // CHECK: punpcklbw
- return _mm_unpacklo_pi8(a, b);
-}
-
-__m64 test82(__m64 a, __m64 b) {
- // CHECK: punpcklwd
- return _mm_unpacklo_pi16(a, b);
-}
-
-__m64 test83(__m64 a, __m64 b) {
- // CHECK: punpckldq
- return _mm_unpacklo_pi32(a, b);
-}
-
-__m64 test84(__m64 a, __m64 b) {
- // CHECK: pcmpeqb
+__m64 test_mm_cmpeq_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpeq_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpeq.b
return _mm_cmpeq_pi8(a, b);
}
-__m64 test85(__m64 a, __m64 b) {
- // CHECK: pcmpeqw
+__m64 test_mm_cmpeq_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpeq_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpeq.w
return _mm_cmpeq_pi16(a, b);
}
-__m64 test86(__m64 a, __m64 b) {
- // CHECK: pcmpeqd
+__m64 test_mm_cmpeq_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpeq_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpeq.d
return _mm_cmpeq_pi32(a, b);
}
-__m64 test87(__m64 a, __m64 b) {
- // CHECK: pcmpgtb
+__m64 test_mm_cmpgt_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpgt_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpgt.b
return _mm_cmpgt_pi8(a, b);
}
-__m64 test88(__m64 a, __m64 b) {
- // CHECK: pcmpgtw
+__m64 test_mm_cmpgt_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpgt_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpgt.w
return _mm_cmpgt_pi16(a, b);
}
-__m64 test89(__m64 a, __m64 b) {
- // CHECK: pcmpgtd
+__m64 test_mm_cmpgt_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cmpgt_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.pcmpgt.d
return _mm_cmpgt_pi32(a, b);
}
-__m64 test90(int a) {
- // CHECK: movd
+__m128 test_mm_cvt_pi2ps(__m128 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cvt_pi2ps
+ // CHECK: <4 x float> @llvm.x86.sse.cvtpi2ps
+ return _mm_cvt_pi2ps(a, b);
+}
+
+__m64 test_mm_cvt_ps2pi(__m128 a) {
+ // CHECK-LABEL: test_mm_cvt_ps2pi
+ // CHECK: call x86_mmx @llvm.x86.sse.cvtps2pi
+ return _mm_cvt_ps2pi(a);
+}
+
+__m64 test_mm_cvtpd_pi32(__m128d a) {
+ // CHECK-LABEL: test_mm_cvtpd_pi32
+ // CHECK: call x86_mmx @llvm.x86.sse.cvtpd2pi
+ return _mm_cvtpd_pi32(a);
+}
+
+__m128 test_mm_cvtpi16_ps(__m64 a) {
+ // CHECK-LABEL: test_mm_cvtpi16_ps
+ // CHECK: call <4 x float> @llvm.x86.sse.cvtpi2ps
+ return _mm_cvtpi16_ps(a);
+}
+
+__m128d test_mm_cvtpi32_pd(__m64 a) {
+ // CHECK-LABEL: test_mm_cvtpi32_pd
+ // CHECK: call <2 x double> @llvm.x86.sse.cvtpi2pd
+ return _mm_cvtpi32_pd(a);
+}
+
+__m128 test_mm_cvtpi32_ps(__m128 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cvtpi32_ps
+ // CHECK: call <4 x float> @llvm.x86.sse.cvtpi2ps
+ return _mm_cvtpi32_ps(a, b);
+}
+
+__m128 test_mm_cvtpi32x2_ps(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_cvtpi32x2_ps
+ // CHECK: call <4 x float> @llvm.x86.sse.cvtpi2ps
+ // CHECK: call <4 x float> @llvm.x86.sse.cvtpi2ps
+ return _mm_cvtpi32x2_ps(a, b);
+}
+
+__m64 test_mm_cvtps_pi16(__m128 a) {
+ // CHECK-LABEL: test_mm_cvtps_pi16
+ // CHECK: call x86_mmx @llvm.x86.sse.cvtps2pi
+ return _mm_cvtps_pi16(a);
+}
+
+__m64 test_mm_cvtps_pi32(__m128 a) {
+ // CHECK-LABEL: test_mm_cvtps_pi32
+ // CHECK: call x86_mmx @llvm.x86.sse.cvtps2pi
+ return _mm_cvtps_pi32(a);
+}
+
+__m64 test_mm_cvtsi32_si64(int a) {
+ // CHECK-LABEL: test_mm_cvtsi32_si64
+ // CHECK: insertelement <2 x i32>
+ return _mm_cvtsi32_si64(a);
+}
+
+int test_mm_cvtsi64_si32(__m64 a) {
+ // CHECK-LABEL: test_mm_cvtsi64_si32
+ // CHECK: extractelement <2 x i32>
+ return _mm_cvtsi64_si32(a);
+}
+
+__m64 test_mm_cvttpd_pi32(__m128d a) {
+ // CHECK-LABEL: test_mm_cvttpd_pi32
+ // CHECK: call x86_mmx @llvm.x86.sse.cvttpd2pi
+ return _mm_cvttpd_pi32(a);
+}
+
+__m64 test_mm_cvttps_pi32(__m128 a) {
+ // CHECK-LABEL: test_mm_cvttps_pi32
+ // CHECK: call x86_mmx @llvm.x86.sse.cvttps2pi
+ return _mm_cvttps_pi32(a);
+}
+
+__m64 test_m_from_int(int a) {
+ // CHECK-LABEL: test_m_from_int
+ // CHECK: insertelement <2 x i32>
return _m_from_int(a);
}
-int test91(__m64 a) {
- // CHECK: movd
+__m64 test_m_from_int64(long long a) {
+ // CHECK-LABEL: test_m_from_int64
+ // CHECK: bitcast
+ return _m_from_int64(a);
+}
+
+__m64 test_mm_hadd_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hadd_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phadd.w
+ return _mm_hadd_pi16(a, b);
+}
+
+__m64 test_mm_hadd_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hadd_pi32
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phadd.d
+ return _mm_hadd_pi32(a, b);
+}
+
+__m64 test_mm_hadds_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hadds_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phadd.sw
+ return _mm_hadds_pi16(a, b);
+}
+
+__m64 test_mm_hsub_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hsub_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phsub.w
+ return _mm_hsub_pi16(a, b);
+}
+
+__m64 test_mm_hsub_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hsub_pi32
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phsub.d
+ return _mm_hsub_pi32(a, b);
+}
+
+__m64 test_mm_hsubs_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_hsubs_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.phsub.sw
+ return _mm_hsubs_pi16(a, b);
+}
+
+__m64 test_mm_madd_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_madd_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmadd.wd
+ return _mm_madd_pi16(a, b);
+}
+
+__m64 test_mm_maddubs_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_maddubs_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pmadd.ub.sw
+ return _mm_maddubs_pi16(a, b);
+}
+
+void test_mm_maskmove_si64(__m64 d, __m64 n, char *p) {
+ // CHECK-LABEL: test_mm_maskmove_si64
+ // CHECK: call void @llvm.x86.mmx.maskmovq
+ _mm_maskmove_si64(d, n, p);
+}
+
+__m64 test_mm_max_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_max_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmaxs.w
+ return _mm_max_pi16(a, b);
+}
+
+__m64 test_mm_max_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_max_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmaxu.b
+ return _mm_max_pu8(a, b);
+}
+
+__m64 test_mm_min_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_min_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmins.w
+ return _mm_min_pi16(a, b);
+}
+
+__m64 test_mm_min_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_min_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.pminu.b
+ return _mm_min_pu8(a, b);
+}
+
+int test_mm_movemask_pi8(__m64 a) {
+ // CHECK-LABEL: test_mm_movemask_pi8
+ // CHECK: call i32 @llvm.x86.mmx.pmovmskb
+ return _mm_movemask_pi8(a);
+}
+
+__m64 test_mm_mul_su32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_mul_su32
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmulu.dq
+ return _mm_mul_su32(a, b);
+}
+
+__m64 test_mm_mulhi_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_mulhi_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmulh.w
+ return _mm_mulhi_pi16(a, b);
+}
+
+__m64 test_mm_mulhi_pu16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_mulhi_pu16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmulhu.w
+ return _mm_mulhi_pu16(a, b);
+}
+
+__m64 test_mm_mulhrs_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_mulhrs_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pmul.hr.sw
+ return _mm_mulhrs_pi16(a, b);
+}
+
+__m64 test_mm_mullo_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_mullo_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pmull.w
+ return _mm_mullo_pi16(a, b);
+}
+
+__m64 test_mm_or_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_or_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.por
+ return _mm_or_si64(a, b);
+}
+
+__m64 test_mm_packs_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_packs_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.packsswb
+ return _mm_packs_pi16(a, b);
+}
+
+__m64 test_mm_packs_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_packs_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.packssdw
+ return _mm_packs_pi32(a, b);
+}
+
+__m64 test_mm_packs_pu16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_packs_pu16
+ // CHECK: call x86_mmx @llvm.x86.mmx.packuswb
+ return _mm_packs_pu16(a, b);
+}
+
+__m64 test_mm_sad_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sad_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.psad.bw
+ return _mm_sad_pu8(a, b);
+}
+
+__m64 test_mm_shuffle_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_shuffle_pi8
+ // CHECK: call x86_mmx @llvm.x86.ssse3.pshuf.b
+ return _mm_shuffle_pi8(a, b);
+}
+
+__m64 test_mm_shuffle_pi16(__m64 a) {
+ // CHECK-LABEL: test_mm_shuffle_pi16
+ // CHECK: call x86_mmx @llvm.x86.sse.pshuf.w
+ return _mm_shuffle_pi16(a, 3);
+}
+
+__m64 test_mm_sign_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sign_pi8
+ // CHECK: call x86_mmx @llvm.x86.ssse3.psign.b
+ return _mm_sign_pi8(a, b);
+}
+
+__m64 test_mm_sign_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sign_pi16
+ // CHECK: call x86_mmx @llvm.x86.ssse3.psign.w
+ return _mm_sign_pi16(a, b);
+}
+
+__m64 test_mm_sign_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sign_pi32
+ // CHECK: call x86_mmx @llvm.x86.ssse3.psign.d
+ return _mm_sign_pi32(a, b);
+}
+
+__m64 test_mm_sll_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sll_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psll.w
+ return _mm_sll_pi16(a, b);
+}
+
+__m64 test_mm_sll_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sll_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psll.d
+ return _mm_sll_pi32(a, b);
+}
+
+__m64 test_mm_sll_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sll_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.psll.q
+ return _mm_sll_si64(a, b);
+}
+
+__m64 test_mm_slli_pi16(__m64 a) {
+ // CHECK-LABEL: test_mm_slli_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.pslli.w
+ return _mm_slli_pi16(a, 3);
+}
+
+__m64 test_mm_slli_pi32(__m64 a) {
+ // CHECK-LABEL: test_mm_slli_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.pslli.d
+ return _mm_slli_pi32(a, 3);
+}
+
+__m64 test_mm_slli_si64(__m64 a) {
+ // CHECK-LABEL: test_mm_slli_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.pslli.q
+ return _mm_slli_si64(a, 3);
+}
+
+__m64 test_mm_sra_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sra_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psra.w
+ return _mm_sra_pi16(a, b);
+}
+
+__m64 test_mm_sra_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sra_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psra.d
+ return _mm_sra_pi32(a, b);
+}
+
+__m64 test_mm_srai_pi16(__m64 a) {
+ // CHECK-LABEL: test_mm_srai_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrai.w
+ return _mm_srai_pi16(a, 3);
+}
+
+__m64 test_mm_srai_pi32(__m64 a) {
+ // CHECK-LABEL: test_mm_srai_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrai.d
+ return _mm_srai_pi32(a, 3);
+}
+
+__m64 test_mm_srl_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_srl_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrl.w
+ return _mm_srl_pi16(a, b);
+}
+
+__m64 test_mm_srl_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_srl_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrl.d
+ return _mm_srl_pi32(a, b);
+}
+
+__m64 test_mm_srl_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_srl_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrl.q
+ return _mm_srl_si64(a, b);
+}
+
+__m64 test_mm_srli_pi16(__m64 a) {
+ // CHECK-LABEL: test_mm_srli_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrli.w
+ return _mm_srli_pi16(a, 3);
+}
+
+__m64 test_mm_srli_pi32(__m64 a) {
+ // CHECK-LABEL: test_mm_srli_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrli.d
+ return _mm_srli_pi32(a, 3);
+}
+
+__m64 test_mm_srli_si64(__m64 a) {
+ // CHECK-LABEL: test_mm_srli_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.psrli.q
+ return _mm_srli_si64(a, 3);
+}
+
+void test_mm_stream_pi(__m64 *p, __m64 a) {
+ // CHECK-LABEL: test_mm_stream_pi
+ // CHECK: call void @llvm.x86.mmx.movnt.dq
+ _mm_stream_pi(p, a);
+}
+
+__m64 test_mm_sub_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sub_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.psub.b
+ return _mm_sub_pi8(a, b);
+}
+
+__m64 test_mm_sub_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sub_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psub.w
+ return _mm_sub_pi16(a, b);
+}
+
+__m64 test_mm_sub_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sub_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.psub.d
+ return _mm_sub_pi32(a, b);
+}
+
+__m64 test_mm_sub_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_sub_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.psub.q
+ return __builtin_ia32_psubq(a, b);
+}
+
+__m64 test_mm_subs_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_subs_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.psubs.b
+ return _mm_subs_pi8(a, b);
+}
+
+__m64 test_mm_subs_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_subs_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psubs.w
+ return _mm_subs_pi16(a, b);
+}
+
+__m64 test_mm_subs_pu8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_subs_pu8
+ // CHECK: call x86_mmx @llvm.x86.mmx.psubus.b
+ return _mm_subs_pu8(a, b);
+}
+
+__m64 test_mm_subs_pu16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_subs_pu16
+ // CHECK: call x86_mmx @llvm.x86.mmx.psubus.w
+ return _mm_subs_pu16(a, b);
+}
+
+int test_m_to_int(__m64 a) {
+ // CHECK-LABEL: test_m_to_int
+ // CHECK: extractelement <2 x i32>
return _m_to_int(a);
}
+
+long long test_m_to_int64(__m64 a) {
+ // CHECK-LABEL: test_m_to_int64
+ // CHECK: bitcast
+ return _m_to_int64(a);
+}
+
+__m64 test_mm_unpackhi_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpackhi_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpckhbw
+ return _mm_unpackhi_pi8(a, b);
+}
+
+__m64 test_mm_unpackhi_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpackhi_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpckhwd
+ return _mm_unpackhi_pi16(a, b);
+}
+
+__m64 test_mm_unpackhi_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpackhi_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpckhdq
+ return _mm_unpackhi_pi32(a, b);
+}
+
+__m64 test_mm_unpacklo_pi8(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpacklo_pi8
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpcklbw
+ return _mm_unpacklo_pi8(a, b);
+}
+
+__m64 test_mm_unpacklo_pi16(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpacklo_pi16
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpcklwd
+ return _mm_unpacklo_pi16(a, b);
+}
+
+__m64 test_mm_unpacklo_pi32(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_unpacklo_pi32
+ // CHECK: call x86_mmx @llvm.x86.mmx.punpckldq
+ return _mm_unpacklo_pi32(a, b);
+}
+
+__m64 test_mm_xor_si64(__m64 a, __m64 b) {
+ // CHECK-LABEL: test_mm_xor_si64
+ // CHECK: call x86_mmx @llvm.x86.mmx.pxor
+ return _mm_xor_si64(a, b);
+}
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index d5071ab..91f5aa2 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -41,4 +41,4 @@
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK: attributes [[NI]] = { noinline nounwind{{.*}} }
// CHECK: attributes [[NR]] = { noreturn }
-// CHECK: attributes [[NA]] = { nounwind argmemonly{{.*}} }
+// CHECK: attributes [[NA]] = { argmemonly nounwind{{.*}} }
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index cc0fb06..2f5de67 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -470,6 +470,18 @@
int b;
} A;
+typedef struct {
+ int b1;
+ A b2;
+} B;
+
+typedef struct {
+ int c1;
+ A c2;
+ int c3;
+ B c4;
+} C;
+
void t39() {
// CHECK-LABEL: define void @t39
__asm mov eax, [eax].A.b
@@ -478,6 +490,14 @@
// CHECK: mov eax, [eax] .4
__asm mov eax, fs:[0] A.b
// CHECK: mov eax, fs:[$$0] .4
+ __asm mov eax, [eax].B.b2.a
+// CHECK: mov eax, [eax].4
+ __asm mov eax, [eax] B.b2.b
+// CHECK: mov eax, [eax] .8
+ __asm mov eax, fs:[0] C.c2.b
+// CHECK: mov eax, fs:[$$0] .8
+ __asm mov eax, [eax]C.c4.b2.b
+// CHECK: mov eax, [eax].24
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
@@ -516,6 +536,38 @@
// CHECK: "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %flags)
}
+void t43() {
+// CHECK-LABEL: define void @t43
+ C strct;
+// Work around PR20368: These should be single line blocks
+ __asm { mov eax, 4[strct.c1] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 4[strct.c3 + 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 8[strct.c2.a + 4 + 32*2 - 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$72$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 12[4 + strct.c2.b] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$16$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 4[4 + strct.c4.b2.b + 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 4[64 + strct.c1 + (2*32)] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$132$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, 4[64 + strct.c2.a - 2*32] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [strct.c4.b1 + 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [strct.c4.b2.a + 4 + 32*2 - 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$64$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [4 + strct.c1] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [4 + strct.c2.b + 4] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [64 + strct.c3 + (2*32)] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$128$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+ __asm { mov eax, [64 + strct.c4.b2.b - 2*32] }
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+}
+
void call_clobber() {
__asm call t41
// CHECK-LABEL: define void @call_clobber
@@ -533,8 +585,8 @@
label:
jmp label
}
- // CHECK-LABEL: define void @label1
- // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.1__label:\0A\09jmp {{.*}}__MSASMLABEL_.1__label", "~{dirflag},~{fpsr},~{flags}"()
+ // CHECK-LABEL: define void @label1()
+ // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.1__label:\0A\09jmp {{.*}}__MSASMLABEL_.1__label", "~{dirflag},~{fpsr},~{flags}"() [[ATTR1:#[0-9]+]]
}
void label2() {
@@ -564,6 +616,15 @@
// CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.4__label:\0A\09mov eax, {{.*}}__MSASMLABEL_.4__label", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
+void label5() {
+ __asm {
+ jmp dollar_label$
+ dollar_label$:
+ }
+ // CHECK-LABEL: define void @label5
+ // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.5__dollar_label$$\0A\09{{.*}}__MSASMLABEL_.5__dollar_label$$:", "~{dirflag},~{fpsr},~{flags}"()
+}
+
typedef union _LARGE_INTEGER {
struct {
unsigned int LowPart;
@@ -581,3 +642,6 @@
}
// CHECK-LABEL: define i32 @test_indirect_field(
// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1",
+
+// MS ASM containing labels must not be duplicated (PR23715).
+// CHECK: attributes [[ATTR1]] = { {{.*}}noduplicate{{.*}} }
diff --git a/test/CodeGen/ms_this.cpp b/test/CodeGen/ms_this.cpp
new file mode 100644
index 0000000..8647a5b
--- /dev/null
+++ b/test/CodeGen/ms_this.cpp
@@ -0,0 +1,57 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -fasm-blocks -emit-llvm %s -o - | FileCheck %s
+class t1 {
+public:
+ double a;
+ void runc();
+};
+
+class t2 {
+public:
+ double a;
+ void runc();
+};
+
+// CHECK: define void @"\01?runc@t2@@
+void t2::runc() {
+ double num = 0;
+ __asm {
+ mov rax,[this]
+ // CHECK: [[THIS_ADDR_T2:%.+]] = alloca %class.t2*
+ // CHECK: [[THIS1_T2:%.+]] = load %class.t2*, %class.t2** [[THIS_ADDR_T2]],
+ // CHECK: call void asm sideeffect inteldialect "mov rax,qword ptr $1{{.*}}%class.t2* [[THIS1_T2]]
+ mov rbx,[rax]
+ mov num, rbx
+ };
+}
+
+// CHECK: define void @"\01?runc@t1@@
+void t1::runc() {
+ double num = 0;
+ __asm {
+ mov rax,[this]
+ // CHECK: [[THIS_ADDR_T1:%.+]] = alloca %class.t1*
+ // CHECK: [[THIS1_T1:%.+]] = load %class.t1*, %class.t1** [[THIS_ADDR_T1]],
+ // CHECK: call void asm sideeffect inteldialect "mov rax,qword ptr $1{{.*}}%class.t1* [[THIS1_T1]]
+ mov rbx,[rax]
+ mov num, rbx
+ };
+}
+
+struct s {
+ int a;
+ // CHECK: define linkonce_odr void @"\01?func@s@@
+ void func() {
+ __asm mov rax, [this]
+ // CHECK: [[THIS_ADDR_S:%.+]] = alloca %struct.s*
+ // CHECK: [[THIS1_S:%.+]] = load %struct.s*, %struct.s** [[THIS_ADDR_S]],
+ // CHECK: call void asm sideeffect inteldialect "mov rax, qword ptr $0{{.*}}%struct.s* [[THIS1_S]]
+ }
+} f3;
+
+int main() {
+ f3.func();
+ f3.a=1;
+ return 0;
+}
diff --git a/test/CodeGen/named_reg_global.c b/test/CodeGen/named_reg_global.c
index 8f9a9c6..1da6257 100644
--- a/test/CodeGen/named_reg_global.c
+++ b/test/CodeGen/named_reg_global.c
@@ -1,16 +1,26 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple armv7-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X86-64
+// RUN: %clang_cc1 -triple arm64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
+// RUN: %clang_cc1 -triple armv7-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
// CHECK-NOT: @sp = common global
+
+#if defined(__x86_64__)
+register unsigned long current_stack_pointer asm("rsp");
+#else
register unsigned long current_stack_pointer asm("sp");
+#endif
+
struct p4_Thread {
struct {
int len;
} word;
};
// Testing pointer types as well
+#if defined(__x86_64__)
+register struct p4_Thread *p4TH asm("rsp");
+#else
register struct p4_Thread *p4TH asm("sp");
+#endif
// CHECK: define{{.*}} i[[bits:[0-9]+]] @get_stack_pointer_addr()
// CHECK: [[ret:%[0-9]+]] = call i[[bits]] @llvm.read_register.i[[bits]](metadata !0)
@@ -43,5 +53,7 @@
// CHECK: %[[regw:[0-9]+]] = ptrtoint %struct.p4_Thread* %{{.*}} to i[[bits]]
// CHECK: call void @llvm.write_register.i[[bits]](metadata !0, i[[bits]] %[[regw]])
-// CHECK: !llvm.named.register.sp = !{!0}
-// CHECK: !0 = !{!"sp"}
+// CHECK-X86-64: !llvm.named.register.rsp = !{!0}
+// CHECK-X86-64: !0 = !{!"rsp"}
+// CHECK-ARM: !llvm.named.register.sp = !{!0}
+// CHECK-ARM: !0 = !{!"sp"}
diff --git a/test/CodeGen/nobuiltin.c b/test/CodeGen/nobuiltin.c
index 0a8e8bb..7cc8164 100644
--- a/test/CodeGen/nobuiltin.c
+++ b/test/CodeGen/nobuiltin.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fno-builtin -O1 -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fno-builtin-memset -O1 -S -o - %s | FileCheck -check-prefix=MEMSET %s
void PR13497() {
char content[2];
@@ -6,3 +7,11 @@
// CHECK: __strcpy_chk
__builtin___strcpy_chk(content, "", 1);
}
+
+void PR4941(char *s) {
+ // Make sure we don't optimize this loop to a memset().
+ // MEMSET-LABEL: PR4941:
+ // MEMSET-NOT: memset
+ for (unsigned i = 0; i < 8192; ++i)
+ s[i] = 0;
+}
diff --git a/test/CodeGen/pass-object-size.c b/test/CodeGen/pass-object-size.c
new file mode 100644
index 0000000..1ad3f85
--- /dev/null
+++ b/test/CodeGen/pass-object-size.c
@@ -0,0 +1,353 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s
+
+typedef unsigned long size_t;
+
+struct Foo {
+ int t[10];
+};
+
+#define PS(N) __attribute__((pass_object_size(N)))
+
+int gi = 0;
+
+// CHECK-LABEL: define i32 @ObjectSize0(i8* %{{.*}}, i64)
+int ObjectSize0(void *const p PS(0)) {
+ // CHECK-NOT: @llvm.objectsize
+ return __builtin_object_size(p, 0);
+}
+
+// CHECK-LABEL: define i32 @ObjectSize1(i8* %{{.*}}, i64)
+int ObjectSize1(void *const p PS(1)) {
+ // CHECK-NOT: @llvm.objectsize
+ return __builtin_object_size(p, 1);
+}
+
+// CHECK-LABEL: define i32 @ObjectSize2(i8* %{{.*}}, i64)
+int ObjectSize2(void *const p PS(2)) {
+ // CHECK-NOT: @llvm.objectsize
+ return __builtin_object_size(p, 2);
+}
+
+// CHECK-LABEL: define i32 @ObjectSize3(i8* %{{.*}}, i64)
+int ObjectSize3(void *const p PS(3)) {
+ // CHECK-NOT: @llvm.objectsize
+ return __builtin_object_size(p, 3);
+}
+
+// CHECK-LABEL: define void @test1
+void test1() {
+ struct Foo t[10];
+
+ // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 360)
+ gi = ObjectSize0(&t[1]);
+ // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 360)
+ gi = ObjectSize1(&t[1]);
+ // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 360)
+ gi = ObjectSize2(&t[1]);
+ // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 360)
+ gi = ObjectSize3(&t[1]);
+
+ // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 356)
+ gi = ObjectSize0(&t[1].t[1]);
+ // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
+ gi = ObjectSize1(&t[1].t[1]);
+ // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 356)
+ gi = ObjectSize2(&t[1].t[1]);
+ // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
+ gi = ObjectSize3(&t[1].t[1]);
+}
+
+// CHECK-LABEL: define void @test2
+void test2(struct Foo *t) {
+ // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
+ gi = ObjectSize1(&t->t[1]);
+ // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
+ gi = ObjectSize3(&t->t[1]);
+}
+
+// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv
+int NoViableOverloadObjectSize0(void *const p) __attribute__((overloadable)) {
+ // CHECK: @llvm.objectsize
+ return __builtin_object_size(p, 0);
+}
+
+// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize1Pv
+int NoViableOverloadObjectSize1(void *const p) __attribute__((overloadable)) {
+ // CHECK: @llvm.objectsize
+ return __builtin_object_size(p, 1);
+}
+
+// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize2Pv
+int NoViableOverloadObjectSize2(void *const p) __attribute__((overloadable)) {
+ // CHECK: @llvm.objectsize
+ return __builtin_object_size(p, 2);
+}
+
+// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize3Pv
+int NoViableOverloadObjectSize3(void *const p) __attribute__((overloadable)) {
+ // CHECK-NOT: @llvm.objectsize
+ return __builtin_object_size(p, 3);
+}
+
+// CHECK-LABEL: define i32 @_Z27NoViableOverloadObjectSize0Pv
+// CHECK-NOT: @llvm.objectsize
+int NoViableOverloadObjectSize0(void *const p PS(0))
+ __attribute__((overloadable)) {
+ return __builtin_object_size(p, 0);
+}
+
+int NoViableOverloadObjectSize1(void *const p PS(1))
+ __attribute__((overloadable)) {
+ return __builtin_object_size(p, 1);
+}
+
+int NoViableOverloadObjectSize2(void *const p PS(2))
+ __attribute__((overloadable)) {
+ return __builtin_object_size(p, 2);
+}
+
+int NoViableOverloadObjectSize3(void *const p PS(3))
+ __attribute__((overloadable)) {
+ return __builtin_object_size(p, 3);
+}
+
+const static int SHOULDNT_BE_CALLED = -100;
+int NoViableOverloadObjectSize0(void *const p PS(0))
+ __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
+ return SHOULDNT_BE_CALLED;
+}
+
+int NoViableOverloadObjectSize1(void *const p PS(1))
+ __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
+ return SHOULDNT_BE_CALLED;
+}
+
+int NoViableOverloadObjectSize2(void *const p PS(2))
+ __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
+ return SHOULDNT_BE_CALLED;
+}
+
+int NoViableOverloadObjectSize3(void *const p PS(3))
+ __attribute__((overloadable, enable_if(p == 0, "never selected"))) {
+ return SHOULDNT_BE_CALLED;
+}
+
+// CHECK-LABEL: define void @test3
+void test3() {
+ struct Foo t[10];
+
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 360)
+ gi = NoViableOverloadObjectSize0(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 360)
+ gi = NoViableOverloadObjectSize1(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 360)
+ gi = NoViableOverloadObjectSize2(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 360)
+ gi = NoViableOverloadObjectSize3(&t[1]);
+
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 356)
+ gi = NoViableOverloadObjectSize0(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
+ gi = NoViableOverloadObjectSize1(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 356)
+ gi = NoViableOverloadObjectSize2(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36)
+ gi = NoViableOverloadObjectSize3(&t[1].t[1]);
+}
+
+// CHECK-LABEL: define void @test4
+void test4(struct Foo *t) {
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
+ gi = NoViableOverloadObjectSize0(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 %{{.*}})
+ gi = NoViableOverloadObjectSize1(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
+ gi = NoViableOverloadObjectSize2(&t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 0)
+ gi = NoViableOverloadObjectSize3(&t[1]);
+
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
+ gi = NoViableOverloadObjectSize0(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
+ gi = NoViableOverloadObjectSize1(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
+ gi = NoViableOverloadObjectSize2(&t[1].t[1]);
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize3PvU17pass_object_size3(i8* %{{.*}}, i64 36)
+ gi = NoViableOverloadObjectSize3(&t[1].t[1]);
+}
+
+void test5() {
+ struct Foo t[10];
+
+ int (*f)(void *) = &NoViableOverloadObjectSize0;
+ gi = f(&t[1]);
+}
+
+// CHECK-LABEL: define i32 @IndirectObjectSize0
+int IndirectObjectSize0(void *const p PS(0)) {
+ // CHECK: call i32 @ObjectSize0(i8* %{{.*}}, i64 %{{.*}})
+ // CHECK-NOT: @llvm.objectsize
+ return ObjectSize0(p);
+}
+
+// CHECK-LABEL: define i32 @IndirectObjectSize1
+int IndirectObjectSize1(void *const p PS(1)) {
+ // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 %{{.*}})
+ // CHECK-NOT: @llvm.objectsize
+ return ObjectSize1(p);
+}
+
+// CHECK-LABEL: define i32 @IndirectObjectSize2
+int IndirectObjectSize2(void *const p PS(2)) {
+ // CHECK: call i32 @ObjectSize2(i8* %{{.*}}, i64 %{{.*}})
+ // CHECK-NOT: @llvm.objectsize
+ return ObjectSize2(p);
+}
+
+// CHECK-LABEL: define i32 @IndirectObjectSize3
+int IndirectObjectSize3(void *const p PS(3)) {
+ // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 %{{.*}})
+ // CHECK-NOT: @llvm.objectsize
+ return ObjectSize3(p);
+}
+
+int Overload0(void *, size_t, void *, size_t);
+int OverloadNoSize(void *, void *);
+
+int OverloadedObjectSize(void *const p PS(0),
+ void *const c PS(0))
+ __attribute__((overloadable)) __asm__("Overload0");
+
+int OverloadedObjectSize(void *const p, void *const c)
+ __attribute__((overloadable)) __asm__("OverloadNoSize");
+
+// CHECK-LABEL: define void @test6
+void test6() {
+ int known[10], *opaque;
+
+ // CHECK: call i32 @"\01Overload0"
+ gi = OverloadedObjectSize(&known[0], &known[0]);
+
+ // CHECK: call i32 @"\01Overload0"
+ gi = OverloadedObjectSize(&known[0], opaque);
+
+ // CHECK: call i32 @"\01Overload0"
+ gi = OverloadedObjectSize(opaque, &known[0]);
+
+ // CHECK: call i32 @"\01Overload0"
+ gi = OverloadedObjectSize(opaque, opaque);
+}
+
+int Identity(void *p, size_t i) { return i; }
+
+// CHECK-NOT: define void @AsmObjectSize
+int AsmObjectSize0(void *const p PS(0)) __asm__("Identity");
+
+int AsmObjectSize1(void *const p PS(1)) __asm__("Identity");
+
+int AsmObjectSize2(void *const p PS(2)) __asm__("Identity");
+
+int AsmObjectSize3(void *const p PS(3)) __asm__("Identity");
+
+// CHECK-LABEL: define void @test7
+void test7() {
+ struct Foo t[10];
+
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
+ gi = AsmObjectSize0(&t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
+ gi = AsmObjectSize1(&t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
+ gi = AsmObjectSize2(&t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 360)
+ gi = AsmObjectSize3(&t[1]);
+
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356)
+ gi = AsmObjectSize0(&t[1].t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
+ gi = AsmObjectSize1(&t[1].t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 356)
+ gi = AsmObjectSize2(&t[1].t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
+ gi = AsmObjectSize3(&t[1].t[1]);
+}
+
+// CHECK-LABEL: define void @test8
+void test8(struct Foo *t) {
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
+ gi = AsmObjectSize1(&t[1].t[1]);
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
+ gi = AsmObjectSize3(&t[1].t[1]);
+}
+
+void DifferingObjectSize0(void *const p __attribute__((pass_object_size(0))));
+void DifferingObjectSize1(void *const p __attribute__((pass_object_size(1))));
+void DifferingObjectSize2(void *const p __attribute__((pass_object_size(2))));
+void DifferingObjectSize3(void *const p __attribute__((pass_object_size(3))));
+
+// CHECK-LABEL: define void @test9
+void test9(void *const p __attribute__((pass_object_size(0)))) {
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize2(p);
+
+ // CHECK-NOT: @llvm.objectsize
+ DifferingObjectSize0(p);
+ DifferingObjectSize1(p);
+
+ // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
+ DifferingObjectSize3(p);
+}
+
+// CHECK-LABEL: define void @test10
+void test10(void *const p __attribute__((pass_object_size(1)))) {
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize2(p);
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize0(p);
+
+ // CHECK-NOT: @llvm.objectsize
+ DifferingObjectSize1(p);
+
+ // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
+ DifferingObjectSize3(p);
+}
+
+// CHECK-LABEL: define void @test11
+void test11(void *const p __attribute__((pass_object_size(2)))) {
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize0(p);
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize1(p);
+
+ // CHECK-NOT: @llvm.objectsize
+ DifferingObjectSize2(p);
+
+ // CHECK: call void @DifferingObjectSize3(i8* %{{.*}}, i64 0)
+ DifferingObjectSize3(p);
+}
+
+// CHECK-LABEL: define void @test12
+void test12(void *const p __attribute__((pass_object_size(3)))) {
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize0(p);
+ // CHECK: @llvm.objectsize
+ DifferingObjectSize1(p);
+
+ // CHECK-NOT: @llvm.objectsize
+ DifferingObjectSize2(p);
+ DifferingObjectSize3(p);
+}
+
+// CHECK-LABEL: define void @test13
+void test13() {
+ // Ensuring that we don't lower objectsize if the expression has side-effects
+ char c[10];
+ char *p = c;
+
+ // CHECK: @llvm.objectsize
+ ObjectSize0(p);
+
+ // CHECK-NOT: @llvm.objectsize
+ ObjectSize0(++p);
+ ObjectSize0(p++);
+}
diff --git a/test/CodeGen/pku.c b/test/CodeGen/pku.c
new file mode 100644
index 0000000..30565a8
--- /dev/null
+++ b/test/CodeGen/pku.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +pku -emit-llvm -o - -Werror | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+unsigned int test_rdpkru_u32() {
+ // CHECK-LABEL: @test_rdpkru_u32
+ // CHECK: @llvm.x86.rdpkru
+ return _rdpkru_u32();
+}
+void test_wrpkru(unsigned int __A) {
+ // CHECK-LABEL: @test_wrpkru
+ // CHECK: @llvm.x86.wrpkru
+ _wrpkru(__A);
+ return ;
+}
diff --git a/test/CodeGen/popcnt-builtins.c b/test/CodeGen/popcnt-builtins.c
index 1105c37..5ae40c7 100644
--- a/test/CodeGen/popcnt-builtins.c
+++ b/test/CodeGen/popcnt-builtins.c
@@ -6,11 +6,21 @@
#include <x86intrin.h>
unsigned int test_mm_popcnt_u32(unsigned int __X) {
- // CHECK: @llvm.ctpop.i32
+ //CHECK: call i32 @llvm.ctpop.i32
return _mm_popcnt_u32(__X);
}
+unsigned int test_popcnt_32(int __X) {
+ //CHECK: call i32 @llvm.ctpop.i32
+ return _popcnt32(__X);
+}
+
unsigned long long test_mm_popcnt_u64(unsigned long long __X) {
- // CHECK: @llvm.ctpop.i64
+ //CHECK: call i64 @llvm.ctpop.i64
return _mm_popcnt_u64(__X);
}
+
+unsigned long long test_popcnt_64(long long __X) {
+ //CHECK: call i64 @llvm.ctpop.i64
+ return _popcnt64(__X);
+}
diff --git a/test/CodeGen/ppc-sfvarargs.c b/test/CodeGen/ppc-sfvarargs.c
new file mode 100644
index 0000000..924d9c5
--- /dev/null
+++ b/test/CodeGen/ppc-sfvarargs.c
@@ -0,0 +1,17 @@
+// RUN: %clang -O0 --target=powerpc-unknown-linux-gnu -EB -msoft-float -S -emit-llvm %s -o - | FileCheck %s
+
+#include <stdarg.h>
+void test(char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ va_arg(ap, double);
+ va_end(ap);
+}
+
+void foo() {
+ double a;
+ test("test",a);
+}
+// CHECK: %{{[0-9]+}} = add i8 %{{[0-9]+|numUsedRegs}}, 1
+// CHECK: %{{[0-9]+}} = and i8 %{{[0-9]+}}, -2
+// CHECK: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, 4
diff --git a/test/CodeGen/ppc-varargs-struct.c b/test/CodeGen/ppc-varargs-struct.c
index a6ba137..1ad57c2 100644
--- a/test/CodeGen/ppc-varargs-struct.c
+++ b/test/CodeGen/ppc-varargs-struct.c
@@ -39,9 +39,13 @@
// CHECK-PPC:[[USING_OVERFLOW]]
// CHECK-PPC-NEXT: [[OVERFLOW_AREA_P:%[0-9]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* [[ARRAYDECAY]], i32 0, i32 3
// CHECK-PPC-NEXT: [[OVERFLOW_AREA:%.+]] = load i8*, i8** [[OVERFLOW_AREA_P]], align 4
-// CHECK-PPC-NEXT: [[MEMADDR:%.+]] = bitcast i8* [[OVERFLOW_AREA]] to %struct.x**
-// CHECK-PPC-NEXT: [[NEW_OVERFLOW_AREA:%[0-9]+]] = getelementptr inbounds i8, i8* [[OVERFLOW_AREA]], i32 4
-// CHECK-PPC-NEXT: store i8* [[NEW_OVERFLOW_AREA]], i8** [[OVERFLOW_AREA_P]]
+// CHECK-PPC-NEXT: %{{[0-9]+}} = ptrtoint i8* %argp.cur to i32
+// CHECK-PPC-NEXT: %{{[0-9]+}} = add i32 %{{[0-9]+}}, 7
+// CHECK-PPC-NEXT: %{{[0-9]+}} = and i32 %{{[0-9]+}}, -8
+// CHECK-PPC-NEXT: %argp.cur.aligned = inttoptr i32 %{{[0-9]+}} to i8*
+// CHECK-PPC-NEXT: [[MEMADDR:%.+]] = bitcast i8* %argp.cur.aligned to %struct.x**
+// CHECK-PPC-NEXT: [[NEW_OVERFLOW_AREA:%[0-9]+]] = getelementptr inbounds i8, i8* %argp.cur.aligned, i32 4
+// CHECK-PPC-NEXT: store i8* [[NEW_OVERFLOW_AREA:%[0-9]+]], i8** [[OVERFLOW_AREA_P]], align 4
// CHECK-PPC-NEXT: br label %[[CONT]]
//
// CHECK-PPC:[[CONT]]
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 11a094a..0f964e8 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -495,3 +495,27 @@
// CHECK: ret <2 x i64> undef
return _mm_undefined_si128();
}
+
+__m64 test_mm_add_si64(__m64 __a, __m64 __b) {
+ // CHECK-LABEL: @test_mm_add_si64
+ // CHECK @llvm.x86.mmx.padd.q(x86_mmx %{{.*}}, x86_mmx %{{.*}})
+ return _mm_add_si64(__a, __b);
+}
+
+__m64 test_mm_sub_si64(__m64 __a, __m64 __b) {
+ // CHECK-LABEL: @test_mm_sub_si64
+ // CHECK @llvm.x86.mmx.psub.q(x86_mmx %{{.*}}, x86_mmx %{{.*}})
+ return _mm_sub_si64(__a, __b);
+}
+
+__m64 test_mm_mul_su32(__m64 __a, __m64 __b) {
+ // CHECK-LABEL: @test_mm_mul_su32
+ // CHECK @llvm.x86.mmx.pmulu.dq(x86_mmx %{{.*}}, x86_mmx %{{.*}})
+ return _mm_mul_su32(__a, __b);
+}
+
+void test_mm_pause() {
+ // CHECK-LABEL: @test_mm_pause
+ // CHECK @llvm.x86.sse2.pause()
+ return _mm_pause();
+}
diff --git a/test/CodeGen/sse2-builtins.c b/test/CodeGen/sse2-builtins.c
new file mode 100644
index 0000000..4ceb93a
--- /dev/null
+++ b/test/CodeGen/sse2-builtins.c
@@ -0,0 +1,1105 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse2 -emit-llvm -o - -Werror | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse2 -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+__m128i test_mm_add_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_add_epi8
+ // CHECK: add <16 x i8>
+ return _mm_add_epi8(A, B);
+}
+
+__m128i test_mm_add_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_add_epi16
+ // CHECK: add <8 x i16>
+ return _mm_add_epi16(A, B);
+}
+
+__m128i test_mm_add_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_add_epi32
+ // CHECK: add <4 x i32>
+ return _mm_add_epi32(A, B);
+}
+
+__m128i test_mm_add_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_add_epi64
+ // CHECK: add <2 x i64>
+ return _mm_add_epi64(A, B);
+}
+
+__m128d test_mm_add_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_add_pd
+ // CHECK: fadd <2 x double>
+ return _mm_add_pd(A, B);
+}
+
+__m128d test_mm_add_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_add_sd
+ // CHECK: fadd double
+ return _mm_add_sd(A, B);
+}
+
+__m128i test_mm_adds_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_adds_epi8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.padds.b
+ return _mm_adds_epi8(A, B);
+}
+
+__m128i test_mm_adds_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_adds_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.padds.w
+ return _mm_adds_epi16(A, B);
+}
+
+__m128i test_mm_adds_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_adds_epu8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.paddus.b
+ return _mm_adds_epu8(A, B);
+}
+
+__m128i test_mm_adds_epu16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_adds_epu16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.paddus.w
+ return _mm_adds_epu16(A, B);
+}
+
+__m128d test_mm_and_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_and_pd
+ // CHECK: and <4 x i32>
+ return _mm_and_pd(A, B);
+}
+
+__m128i test_mm_and_si128(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_and_si128
+ // CHECK: and <2 x i64>
+ return _mm_and_si128(A, B);
+}
+
+__m128i test_mm_avg_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_avg_epu8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.pavg.b
+ return _mm_avg_epu8(A, B);
+}
+
+__m128i test_mm_avg_epu16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_avg_epu16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pavg.w
+ return _mm_avg_epu16(A, B);
+}
+
+__m128i test_mm_bslli_si128(__m128i A) {
+ // CHECK-LABEL: test_mm_bslli_si128
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26>
+ return _mm_bslli_si128(A, 5);
+}
+
+__m128i test_mm_bsrli_si128(__m128i A) {
+ // CHECK-LABEL: test_mm_bsrli_si128
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20>
+ return _mm_bsrli_si128(A, 5);
+}
+
+void test_mm_clflush(void* A) {
+ // CHECK-LABEL: test_mm_clflush
+ // CHECK: call void @llvm.x86.sse2.clflush(i8* %{{.*}})
+ _mm_clflush(A);
+}
+
+__m128i test_mm_cmpeq_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpeq_epi8
+ // CHECK: icmp eq <16 x i8>
+ return _mm_cmpeq_epi8(A, B);
+}
+
+__m128i test_mm_cmpeq_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpeq_epi16
+ // CHECK: icmp eq <8 x i16>
+ return _mm_cmpeq_epi16(A, B);
+}
+
+__m128i test_mm_cmpeq_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpeq_epi32
+ // CHECK: icmp eq <4 x i32>
+ return _mm_cmpeq_epi32(A, B);
+}
+
+__m128d test_mm_cmpeq_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpeq_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 0)
+ return _mm_cmpeq_pd(A, B);
+}
+
+__m128d test_mm_cmpeq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpeq_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 0)
+ return _mm_cmpeq_sd(A, B);
+}
+
+__m128d test_mm_cmpge_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpge_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmpge_pd(A, B);
+}
+
+__m128d test_mm_cmpge_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpge_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmpge_sd(A, B);
+}
+
+__m128i test_mm_cmpgt_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpgt_epi8
+ // CHECK: icmp sgt <16 x i8>
+ return _mm_cmpgt_epi8(A, B);
+}
+
+__m128i test_mm_cmpgt_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpgt_epi16
+ // CHECK: icmp sgt <8 x i16>
+ return _mm_cmpgt_epi16(A, B);
+}
+
+__m128i test_mm_cmpgt_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmpgt_epi32
+ // CHECK: icmp sgt <4 x i32>
+ return _mm_cmpgt_epi32(A, B);
+}
+
+__m128d test_mm_cmpgt_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpgt_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmpgt_pd(A, B);
+}
+
+__m128d test_mm_cmpgt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpgt_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmpgt_sd(A, B);
+}
+
+__m128d test_mm_cmple_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmple_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmple_pd(A, B);
+}
+
+__m128d test_mm_cmple_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmple_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ return _mm_cmple_sd(A, B);
+}
+
+__m128i test_mm_cmplt_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmplt_epi8
+ // CHECK: icmp sgt <16 x i8>
+ return _mm_cmplt_epi8(A, B);
+}
+
+__m128i test_mm_cmplt_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmplt_epi16
+ // CHECK: icmp sgt <8 x i16>
+ return _mm_cmplt_epi16(A, B);
+}
+
+__m128i test_mm_cmplt_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_cmplt_epi32
+ // CHECK: icmp sgt <4 x i32>
+ return _mm_cmplt_epi32(A, B);
+}
+
+__m128d test_mm_cmplt_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmplt_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmplt_pd(A, B);
+}
+
+__m128d test_mm_cmplt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmplt_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 1)
+ return _mm_cmplt_sd(A, B);
+}
+
+__m128d test_mm_cmpneq_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpneq_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 4)
+ return _mm_cmpneq_pd(A, B);
+}
+
+__m128d test_mm_cmpneq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpneq_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 4)
+ return _mm_cmpneq_sd(A, B);
+}
+
+__m128d test_mm_cmpnge_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnge_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnge_pd(A, B);
+}
+
+__m128d test_mm_cmpnge_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnge_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnge_sd(A, B);
+}
+
+__m128d test_mm_cmpngt_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpngt_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpngt_pd(A, B);
+}
+
+__m128d test_mm_cmpngt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpngt_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpngt_sd(A, B);
+}
+
+__m128d test_mm_cmpnle_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnle_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnle_pd(A, B);
+}
+
+__m128d test_mm_cmpnle_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnle_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 6)
+ return _mm_cmpnle_sd(A, B);
+}
+
+__m128d test_mm_cmpnlt_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnlt_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpnlt_pd(A, B);
+}
+
+__m128d test_mm_cmpnlt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpnlt_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 5)
+ return _mm_cmpnlt_sd(A, B);
+}
+
+__m128d test_mm_cmpord_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpord_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 7)
+ return _mm_cmpord_pd(A, B);
+}
+
+__m128d test_mm_cmpord_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpord_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 7)
+ return _mm_cmpord_sd(A, B);
+}
+
+__m128d test_mm_cmpunord_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpunord_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 3)
+ return _mm_cmpunord_pd(A, B);
+}
+
+__m128d test_mm_cmpunord_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_cmpunord_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i8 3)
+ return _mm_cmpunord_sd(A, B);
+}
+
+int test_mm_comieq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comieq_sd
+ // CHECK: call i32 @llvm.x86.sse2.comieq.sd
+ return _mm_comieq_sd(A, B);
+}
+
+int test_mm_comige_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comige_sd
+ // CHECK: call i32 @llvm.x86.sse2.comige.sd
+ return _mm_comige_sd(A, B);
+}
+
+int test_mm_comigt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comigt_sd
+ // CHECK: call i32 @llvm.x86.sse2.comigt.sd
+ return _mm_comigt_sd(A, B);
+}
+
+int test_mm_comile_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comile_sd
+ // CHECK: call i32 @llvm.x86.sse2.comile.sd
+ return _mm_comile_sd(A, B);
+}
+
+int test_mm_comilt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comilt_sd
+ // CHECK: call i32 @llvm.x86.sse2.comilt.sd
+ return _mm_comilt_sd(A, B);
+}
+
+int test_mm_comineq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_comineq_sd
+ // CHECK: call i32 @llvm.x86.sse2.comineq.sd
+ return _mm_comineq_sd(A, B);
+}
+
+__m128d test_mm_cvtepi32_pd(__m128i A) {
+ // CHECK-LABEL: test_mm_cvtepi32_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cvtdq2pd
+ return _mm_cvtepi32_pd(A);
+}
+
+__m128 test_mm_cvtepi32_ps(__m128i A) {
+ // CHECK-LABEL: test_mm_cvtepi32_ps
+ // CHECK: call <4 x float> @llvm.x86.sse2.cvtdq2ps
+ return _mm_cvtepi32_ps(A);
+}
+
+__m128i test_mm_cvtpd_epi32(__m128d A) {
+ // CHECK-LABEL: test_mm_cvtpd_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.cvtpd2dq
+ return _mm_cvtpd_epi32(A);
+}
+
+__m128 test_mm_cvtpd_ps(__m128d A) {
+ // CHECK-LABEL: test_mm_cvtpd_ps
+ // CHECK: call <4 x float> @llvm.x86.sse2.cvtpd2ps
+ return _mm_cvtpd_ps(A);
+}
+
+__m128i test_mm_cvtps_epi32(__m128 A) {
+ // CHECK-LABEL: test_mm_cvtps_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.cvtps2dq
+ return _mm_cvtps_epi32(A);
+}
+
+__m128d test_mm_cvtps_pd(__m128 A) {
+ // CHECK-LABEL: test_mm_cvtps_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.cvtps2pd
+ return _mm_cvtps_pd(A);
+}
+
+double test_mm_cvtsd_f64(__m128d A) {
+ // CHECK-LABEL: test_mm_cvtsd_f64
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ return _mm_cvtsd_f64(A);
+}
+
+int test_mm_cvtsd_si32(__m128d A) {
+ // CHECK-LABEL: test_mm_cvtsd_si32
+ // CHECK: call i32 @llvm.x86.sse2.cvtsd2si
+ return _mm_cvtsd_si32(A);
+}
+
+long long test_mm_cvtsd_si64(__m128d A) {
+ // CHECK-LABEL: test_mm_cvtsd_si64
+ // CHECK: call i64 @llvm.x86.sse2.cvtsd2si64
+ return _mm_cvtsd_si64(A);
+}
+
+__m128 test_mm_cvtsd_ss(__m128 A, __m128d B) {
+ // CHECK-LABEL: test_mm_cvtsd_ss
+ // CHECK: fptrunc double %{{.*}} to float
+ return _mm_cvtsd_ss(A, B);
+}
+
+int test_mm_cvtsi128_si32(__m128i A) {
+ // CHECK-LABEL: test_mm_cvtsi128_si32
+ // CHECK: extractelement <4 x i32> %{{.*}}, i32 0
+ return _mm_cvtsi128_si32(A);
+}
+
+long long test_mm_cvtsi128_si64(__m128i A) {
+ // CHECK-LABEL: test_mm_cvtsi128_si64
+ // CHECK: extractelement <2 x i64> %{{.*}}, i32 0
+ return _mm_cvtsi128_si64(A);
+}
+
+__m128d test_mm_cvtsi32_sd(__m128d A, int B) {
+ // CHECK-LABEL: test_mm_cvtsi32_sd
+ // CHECK: sitofp i32 %{{.*}} to double
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0
+ return _mm_cvtsi32_sd(A, B);
+}
+
+__m128i test_mm_cvtsi32_si128(int A) {
+ // CHECK-LABEL: test_mm_cvtsi32_si128
+ // CHECK: insertelement <4 x i32> undef, i32 %{{.*}}, i32 0
+ return _mm_cvtsi32_si128(A);
+}
+
+__m128d test_mm_cvtsi64_sd(__m128d A, long long B) {
+ // CHECK-LABEL: test_mm_cvtsi64_sd
+ // CHECK: sitofp i64 %{{.*}} to double
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0
+ return _mm_cvtsi64_sd(A, B);
+}
+
+__m128i test_mm_cvtsi64_si128(long long A) {
+ // CHECK-LABEL: test_mm_cvtsi64_si128
+ // CHECK: insertelement <2 x i64> undef, i64 %{{.*}}, i32 0
+ return _mm_cvtsi64_si128(A);
+}
+
+__m128d test_mm_cvtss_sd(__m128d A, __m128 B) {
+ // CHECK-LABEL: test_mm_cvtss_sd
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 0
+ // CHECK: fpext float %{{.*}} to double
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0
+ return _mm_cvtss_sd(A, B);
+}
+
+__m128i test_mm_cvttpd_epi32(__m128d A) {
+ // CHECK-LABEL: test_mm_cvttpd_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.cvttpd2dq
+ return _mm_cvttpd_epi32(A);
+}
+
+__m128i test_mm_cvttps_epi32(__m128 A) {
+ // CHECK-LABEL: test_mm_cvttps_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.cvttps2dq
+ return _mm_cvttps_epi32(A);
+}
+
+int test_mm_cvttsd_si32(__m128d A) {
+ // CHECK-LABEL: test_mm_cvttsd_si32
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ // CHECK: fptosi double %{{.*}} to i32
+ return _mm_cvttsd_si32(A);
+}
+
+long long test_mm_cvttsd_si64(__m128d A) {
+ // CHECK-LABEL: test_mm_cvttsd_si64
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ // CHECK: fptosi double %{{.*}} to i64
+ return _mm_cvttsd_si64(A);
+}
+
+__m128d test_mm_div_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_div_pd
+ // CHECK: fdiv <2 x double>
+ return _mm_div_pd(A, B);
+}
+
+__m128d test_mm_div_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_div_sd
+ // CHECK: fdiv double
+ return _mm_div_sd(A, B);
+}
+
+// Lowering to pextrw requires optimization.
+int test_mm_extract_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_extract_epi16
+ // CHECK: [[x:%.*]] = and i32 %{{.*}}, 7
+ // CHECK: extractelement <8 x i16> %{{.*}}, i32 [[x]]
+ return _mm_extract_epi16(A, 8);
+}
+
+__m128i test_mm_insert_epi16(__m128i A, short B) {
+ // CHECK-LABEL: test_mm_insert_epi16
+ // CHECK: [[x:%.*]] = and i32 %{{.*}}, 7
+ // CHECK: insertelement <8 x i16> %{{.*}}, i32 [[x]]
+ return _mm_insert_epi16(A, B, 8);
+}
+
+void test_mm_lfence() {
+ // CHECK-LABEL: test_mm_lfence
+ // CHECK: call void @llvm.x86.sse2.lfence()
+ _mm_lfence();
+}
+
+__m128d test_mm_load_pd(double const* A) {
+ // CHECK-LABEL: test_mm_load_pd
+ // CHECK: load <2 x double>, <2 x double>* %{{.*}}, align 16
+ return _mm_load_pd(A);
+}
+
+__m128d test_mm_load_sd(double const* A) {
+ // CHECK-LABEL: test_mm_load_sd
+ // CHECK: load double, double* %{{.*}}, align 1
+ return _mm_load_sd(A);
+}
+
+__m128i test_mm_load_si128(__m128i const* A) {
+ // CHECK-LABEL: test_mm_load_si128
+ // CHECK: load <2 x i64>, <2 x i64>* %{{.*}}, align 16
+ return _mm_load_si128(A);
+}
+
+__m128d test_mm_load1_pd(double const* A) {
+ // CHECK-LABEL: test_mm_load1_pd
+ // CHECK: load double, double* %{{.*}}, align 8
+ // CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 0
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1
+ return _mm_load1_pd(A);
+}
+
+__m128d test_mm_loadh_pd(__m128d x, void* y) {
+ // CHECK-LABEL: test_mm_loadh_pd
+ // CHECK: load double, double* %{{.*}}, align 1{{$}}
+ return _mm_loadh_pd(x, y);
+}
+
+__m128d test_mm_loadr_pd(double const* A) {
+ // CHECK-LABEL: test_mm_loadr_pd
+ // CHECK: load <2 x double>, <2 x double>* %{{.*}}, align 16
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 0>
+ return _mm_loadr_pd(A);
+}
+
+__m128d test_mm_loadu_pd(double const* A) {
+ // CHECK-LABEL: test_mm_loadu_pd
+ // CHECK: load <2 x double>, <2 x double>* %{{.*}}, align 1
+ return _mm_loadu_pd(A);
+}
+
+__m128i test_mm_loadu_si128(__m128i const* A) {
+ // CHECK-LABEL: test_mm_loadu_si128
+ // CHECK: load <2 x i64>, <2 x i64>* %{{.*}}, align 1
+ return _mm_loadu_si128(A);
+}
+
+__m128i test_mm_madd_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_madd_epi16
+ // CHECK: call <4 x i32> @llvm.x86.sse2.pmadd.wd(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_madd_epi16(A, B);
+}
+
+void test_mm_maskmoveu_si128(__m128i A, __m128i B, char* C) {
+ // CHECK-LABEL: test_mm_maskmoveu_si128
+ // CHECK: call void @llvm.x86.sse2.maskmov.dqu(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8* %{{.*}})
+ _mm_maskmoveu_si128(A, B, C);
+}
+
+__m128i test_mm_max_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_max_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pmaxs.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_max_epi16(A, B);
+}
+
+__m128i test_mm_max_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_max_epu8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.pmaxu.b(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ return _mm_max_epu8(A, B);
+}
+
+__m128d test_mm_max_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_max_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.max.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ return _mm_max_pd(A, B);
+}
+
+__m128d test_mm_max_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_max_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.max.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ return _mm_max_sd(A, B);
+}
+
+void test_mm_mfence() {
+ // CHECK-LABEL: test_mm_mfence
+ // CHECK: call void @llvm.x86.sse2.mfence()
+ _mm_mfence();
+}
+
+__m128i test_mm_min_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_min_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pmins.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_min_epi16(A, B);
+}
+
+__m128i test_mm_min_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_min_epu8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.pminu.b(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ return _mm_min_epu8(A, B);
+}
+
+__m128d test_mm_min_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_min_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.min.pd(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ return _mm_min_pd(A, B);
+}
+
+__m128d test_mm_min_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_min_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.min.sd(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ return _mm_min_sd(A, B);
+}
+
+int test_mm_movemask_epi8(__m128i A) {
+ // CHECK-LABEL: test_mm_movemask_epi8
+ // CHECK: call i32 @llvm.x86.sse2.pmovmskb.128(<16 x i8> %{{.*}})
+ return _mm_movemask_epi8(A);
+}
+
+int test_mm_movemask_pd(__m128d A) {
+ // CHECK-LABEL: test_mm_movemask_pd
+ // CHECK: call i32 @llvm.x86.sse2.movmsk.pd(<2 x double> %{{.*}})
+ return _mm_movemask_pd(A);
+}
+
+__m128i test_mm_mul_epu32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_mul_epu32
+ // CHECK: call <2 x i64> @llvm.x86.sse2.pmulu.dq(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
+ return _mm_mul_epu32(A, B);
+}
+
+__m128d test_mm_mul_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_mul_pd
+ // CHECK: fmul <2 x double> %{{.*}}, %{{.*}}
+ return _mm_mul_pd(A, B);
+}
+
+__m128d test_mm_mul_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_mul_sd
+ // CHECK: fmul double %{{.*}}, %{{.*}}
+ return _mm_mul_sd(A, B);
+}
+
+__m128i test_mm_mulhi_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_mulhi_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pmulh.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_mulhi_epi16(A, B);
+}
+
+__m128i test_mm_mulhi_epu16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_mulhi_epu16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pmulhu.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_mulhi_epu16(A, B);
+}
+
+__m128i test_mm_mullo_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_mullo_epi16
+ // CHECK: mul <8 x i16> %{{.*}}, %{{.*}}
+ return _mm_mullo_epi16(A, B);
+}
+
+__m128d test_mm_or_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_or_pd
+ // CHECK: or <4 x i32> %{{.*}}, %{{.*}}
+ return _mm_or_pd(A, B);
+}
+
+__m128i test_mm_or_si128(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_or_si128
+ // CHECK: or <2 x i64> %{{.*}}, %{{.*}}
+ return _mm_or_si128(A, B);
+}
+
+__m128i test_mm_packs_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_packs_epi16
+ // CHECK: call <16 x i8> @llvm.x86.sse2.packsswb.128(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_packs_epi16(A, B);
+}
+
+__m128i test_mm_packs_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_packs_epi32
+ // CHECK: call <8 x i16> @llvm.x86.sse2.packssdw.128(<4 x i32> %{{.*}}, <4 x i32> %{{.*}})
+ return _mm_packs_epi32(A, B);
+}
+
+__m128i test_mm_packus_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_packus_epi16
+ // CHECK: call <16 x i8> @llvm.x86.sse2.packuswb.128(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ return _mm_packus_epi16(A, B);
+}
+
+void test_mm_pause() {
+ // CHECK-LABEL: test_mm_pause
+ // CHECK: call void @llvm.x86.sse2.pause()
+ return _mm_pause();
+}
+
+__m128i test_mm_sad_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sad_epu8
+ // CHECK: call <2 x i64> @llvm.x86.sse2.psad.bw(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ return _mm_sad_epu8(A, B);
+}
+
+__m128d test_mm_setzero_pd() {
+ // CHECK-LABEL: test_mm_setzero_pd
+ // CHECK: store <2 x double> zeroinitializer
+ return _mm_setzero_pd();
+}
+
+__m128i test_mm_setzero_si128() {
+ // CHECK-LABEL: test_mm_setzero_si128
+ // CHECK: store <2 x i64> zeroinitializer
+ return _mm_setzero_si128();
+}
+
+__m128i test_mm_shuffle_epi32(__m128i A) {
+ // CHECK-LABEL: test_mm_shuffle_epi32
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> zeroinitializer
+ return _mm_shuffle_epi32(A, 0);
+}
+
+__m128d test_mm_shuffle_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_shuffle_pd
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 2>
+ return _mm_shuffle_pd(A, B, 1);
+}
+
+__m128i test_mm_shufflehi_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_shufflehi_epi16
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 4, i32 4, i32 4>
+ return _mm_shufflehi_epi16(A, 0);
+}
+
+__m128i test_mm_shufflelo_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_shufflelo_epi16
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 5, i32 6, i32 7>
+ return _mm_shufflelo_epi16(A, 0);
+}
+
+__m128i test_mm_sll_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sll_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psll.w
+ return _mm_sll_epi16(A, B);
+}
+
+__m128i test_mm_sll_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sll_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.psll.d
+ return _mm_sll_epi32(A, B);
+}
+
+__m128i test_mm_sll_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sll_epi64
+ // CHECK: call <2 x i64> @llvm.x86.sse2.psll.q
+ return _mm_sll_epi64(A, B);
+}
+
+__m128i test_mm_slli_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_slli_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.pslli.w
+ return _mm_slli_epi16(A, 1);
+}
+
+__m128i test_mm_slli_epi32(__m128i A) {
+ // CHECK-LABEL: test_mm_slli_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.pslli.d
+ return _mm_slli_epi32(A, 1);
+}
+
+__m128i test_mm_slli_epi64(__m128i A) {
+ // CHECK-LABEL: test_mm_slli_epi64
+ // CHECK: call <2 x i64> @llvm.x86.sse2.pslli.q
+ return _mm_slli_epi64(A, 1);
+}
+
+__m128i test_mm_slli_si128(__m128i A) {
+ // CHECK-LABEL: test_mm_slli_si128
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26>
+ return _mm_slli_si128(A, 5);
+}
+
+__m128d test_mm_sqrt_pd(__m128d A) {
+ // CHECK-LABEL: test_mm_sqrt_pd
+ // CHECK: call <2 x double> @llvm.x86.sse2.sqrt.pd(<2 x double> %{{.*}})
+ return _mm_sqrt_pd(A);
+}
+
+__m128d test_mm_sqrt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_sqrt_sd
+ // CHECK: call <2 x double> @llvm.x86.sse2.sqrt.sd(<2 x double> %{{.*}})
+ return _mm_sqrt_sd(A, B);
+}
+
+__m128i test_mm_sra_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sra_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psra.w
+ return _mm_sra_epi16(A, B);
+}
+
+__m128i test_mm_sra_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sra_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.psra.d
+ return _mm_sra_epi32(A, B);
+}
+
+__m128i test_mm_srai_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_srai_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psrai.w
+ return _mm_srai_epi16(A, 1);
+}
+
+__m128i test_mm_srai_epi32(__m128i A) {
+ // CHECK-LABEL: test_mm_srai_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.psrai.d
+ return _mm_srai_epi32(A, 1);
+}
+
+__m128i test_mm_srl_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_srl_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psrl.w
+ return _mm_srl_epi16(A, B);
+}
+
+__m128i test_mm_srl_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_srl_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.psrl.d
+ return _mm_srl_epi32(A, B);
+}
+
+__m128i test_mm_srl_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_srl_epi64
+ // CHECK: call <2 x i64> @llvm.x86.sse2.psrl.q
+ return _mm_srl_epi64(A, B);
+}
+
+__m128i test_mm_srli_epi16(__m128i A) {
+ // CHECK-LABEL: test_mm_srli_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psrli.w
+ return _mm_srli_epi16(A, 1);
+}
+
+__m128i test_mm_srli_epi32(__m128i A) {
+ // CHECK-LABEL: test_mm_srli_epi32
+ // CHECK: call <4 x i32> @llvm.x86.sse2.psrli.d
+ return _mm_srli_epi32(A, 1);
+}
+
+__m128i test_mm_srli_epi64(__m128i A) {
+ // CHECK-LABEL: test_mm_srli_epi64
+ // CHECK: call <2 x i64> @llvm.x86.sse2.psrli.q
+ return _mm_srli_epi64(A, 1);
+}
+
+__m128i test_mm_srli_si128(__m128i A) {
+ // CHECK-LABEL: test_mm_srli_si128
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20>
+ return _mm_srli_si128(A, 5);
+}
+
+void test_mm_store_pd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_store_pd
+ // CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 16
+ _mm_store_pd(A, B);
+}
+
+void test_mm_store_sd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_store_sd
+ // CHECK: store double %{{.*}}, double* %{{.*}}, align 1{{$}}
+ _mm_store_sd(A, B);
+}
+
+void test_mm_store_si128(__m128i* A, __m128i B) {
+ // CHECK-LABEL: test_mm_store_si128
+ // CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 16
+ _mm_store_si128(A, B);
+}
+
+void test_mm_storeh_pd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_storeh_pd
+ // CHECK: store double %{{.*}}, double* %{{.*}}, align 1
+ _mm_storeh_pd(A, B);
+}
+
+void test_mm_storel_pd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_storel_pd
+ // CHECK: store double %{{.*}}, double* %{{.*}}, align 1
+ _mm_storel_pd(A, B);
+}
+
+void test_mm_storeu_pd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_storeu_pd
+ // CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 1
+ _mm_storeu_pd(A, B);
+}
+
+void test_mm_storeu_si128(__m128i* A, __m128i B) {
+ // CHECK-LABEL: test_mm_storeu_si128
+ // CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 1
+ _mm_storeu_si128(A, B);
+}
+
+void test_mm_stream_pd(double *A, __m128d B) {
+ // CHECK-LABEL: test_mm_stream_pd
+ // CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 16, !nontemporal
+ _mm_stream_pd(A, B);
+}
+
+void test_mm_stream_si32(int *A, int B) {
+ // CHECK-LABEL: test_mm_stream_si32
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 1, !nontemporal
+ _mm_stream_si32(A, B);
+}
+
+void test_mm_stream_si64(long long *A, long long B) {
+ // CHECK-LABEL: test_mm_stream_si64
+ // CHECK: store i64 %{{.*}}, i64* %{{.*}}, align 1, !nontemporal
+ _mm_stream_si64(A, B);
+}
+
+void test_mm_stream_si128(__m128i *A, __m128i B) {
+ // CHECK-LABEL: test_mm_stream_si128
+ // CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 16, !nontemporal
+ _mm_stream_si128(A, B);
+}
+
+__m128i test_mm_sub_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sub_epi8
+ // CHECK: sub <16 x i8>
+ return _mm_sub_epi8(A, B);
+}
+
+__m128i test_mm_sub_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sub_epi16
+ // CHECK: sub <8 x i16>
+ return _mm_sub_epi16(A, B);
+}
+
+__m128i test_mm_sub_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sub_epi32
+ // CHECK: sub <4 x i32>
+ return _mm_sub_epi32(A, B);
+}
+
+__m128i test_mm_sub_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_sub_epi64
+ // CHECK: sub <2 x i64>
+ return _mm_sub_epi64(A, B);
+}
+
+__m128d test_mm_sub_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_sub_pd
+ // CHECK: fsub <2 x double>
+ return _mm_sub_pd(A, B);
+}
+
+__m128d test_mm_sub_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_sub_sd
+ // CHECK: fsub double
+ return _mm_sub_sd(A, B);
+}
+
+__m128i test_mm_subs_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_subs_epi8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.psubs.b
+ return _mm_subs_epi8(A, B);
+}
+
+__m128i test_mm_subs_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_subs_epi16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psubs.w
+ return _mm_subs_epi16(A, B);
+}
+
+__m128i test_mm_subs_epu8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_subs_epu8
+ // CHECK: call <16 x i8> @llvm.x86.sse2.psubus.b
+ return _mm_subs_epu8(A, B);
+}
+
+__m128i test_mm_subs_epu16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_subs_epu16
+ // CHECK: call <8 x i16> @llvm.x86.sse2.psubus.w
+ return _mm_subs_epu16(A, B);
+}
+
+int test_mm_ucomieq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomieq_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomieq.sd
+ return _mm_ucomieq_sd(A, B);
+}
+
+int test_mm_ucomige_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomige_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomige.sd
+ return _mm_ucomige_sd(A, B);
+}
+
+int test_mm_ucomigt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomigt_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomigt.sd
+ return _mm_ucomigt_sd(A, B);
+}
+
+int test_mm_ucomile_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomile_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomile.sd
+ return _mm_ucomile_sd(A, B);
+}
+
+int test_mm_ucomilt_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomilt_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomilt.sd
+ return _mm_ucomilt_sd(A, B);
+}
+
+int test_mm_ucomineq_sd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_ucomineq_sd
+ // CHECK: call i32 @llvm.x86.sse2.ucomineq.sd
+ return _mm_ucomineq_sd(A, B);
+}
+
+__m128i test_mm_unpackhi_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpackhi_epi8
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 8, i32 24, i32 9, i32 25, i32 10, i32 26, i32 11, i32 27, i32 12, i32 28, i32 13, i32 29, i32 14, i32 30, i32 15, i32 31>
+ return _mm_unpackhi_epi8(A, B);
+}
+
+__m128i test_mm_unpackhi_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpackhi_epi16
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
+ return _mm_unpackhi_epi16(A, B);
+}
+
+__m128i test_mm_unpackhi_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpackhi_epi32
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> <i32 2, i32 6, i32 3, i32 7>
+ return _mm_unpackhi_epi32(A, B);
+}
+
+__m128i test_mm_unpackhi_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpackhi_epi64
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <2 x i32> <i32 1, i32 3>
+ return _mm_unpackhi_epi64(A, B);
+}
+
+__m128d test_mm_unpackhi_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_unpackhi_pd
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 3>
+ return _mm_unpackhi_pd(A, B);
+}
+
+__m128i test_mm_unpacklo_epi8(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpacklo_epi8
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 0, i32 16, i32 1, i32 17, i32 2, i32 18, i32 3, i32 19, i32 4, i32 20, i32 5, i32 21, i32 6, i32 22, i32 7, i32 23>
+ return _mm_unpacklo_epi8(A, B);
+}
+
+__m128i test_mm_unpacklo_epi16(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpacklo_epi16
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11>
+ return _mm_unpacklo_epi16(A, B);
+}
+
+__m128i test_mm_unpacklo_epi32(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpacklo_epi32
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+ return _mm_unpacklo_epi32(A, B);
+}
+
+__m128i test_mm_unpacklo_epi64(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_unpacklo_epi64
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <2 x i32> <i32 0, i32 2>
+ return _mm_unpacklo_epi64(A, B);
+}
+
+__m128d test_mm_unpacklo_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_unpacklo_pd
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 0, i32 2>
+ return _mm_unpacklo_pd(A, B);
+}
+
+__m128d test_mm_xor_pd(__m128d A, __m128d B) {
+ // CHECK-LABEL: test_mm_xor_pd
+ // CHECK: xor <4 x i32> %{{.*}}, %{{.*}}
+ return _mm_xor_pd(A, B);
+}
+
+__m128i test_mm_xor_si128(__m128i A, __m128i B) {
+ // CHECK-LABEL: test_mm_xor_si128
+ // CHECK: xor <2 x i64> %{{.*}}, %{{.*}}
+ return _mm_xor_si128(A, B);
+}
diff --git a/test/CodeGen/sse3-builtins.c b/test/CodeGen/sse3-builtins.c
index 5b80e5c..71a34e9 100644
--- a/test/CodeGen/sse3-builtins.c
+++ b/test/CodeGen/sse3-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse3 -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse3 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -10,76 +8,65 @@
__m128d test_mm_addsub_pd(__m128d A, __m128d B) {
// CHECK-LABEL: test_mm_addsub_pd
// CHECK: call <2 x double> @llvm.x86.sse3.addsub.pd
- // CHECK-ASM: addsubpd %xmm{{.*}}, %xmm{{.*}}
return _mm_addsub_pd(A, B);
}
__m128 test_mm_addsub_ps(__m128 A, __m128 B) {
// CHECK-LABEL: test_mm_addsub_ps
// CHECK: call <4 x float> @llvm.x86.sse3.addsub.ps
- // CHECK-ASM: addsubps %xmm{{.*}}, %xmm{{.*}}
return _mm_addsub_ps(A, B);
}
__m128d test_mm_hadd_pd(__m128d A, __m128d B) {
// CHECK-LABEL: test_mm_hadd_pd
// CHECK: call <2 x double> @llvm.x86.sse3.hadd.pd
- // CHECK-ASM: haddpd %xmm{{.*}}, %xmm{{.*}}
return _mm_hadd_pd(A, B);
}
__m128 test_mm_hadd_ps(__m128 A, __m128 B) {
// CHECK-LABEL: test_mm_hadd_ps
// CHECK: call <4 x float> @llvm.x86.sse3.hadd.ps
- // CHECK-ASM: haddps %xmm{{.*}}, %xmm{{.*}}
return _mm_hadd_ps(A, B);
}
__m128d test_mm_hsub_pd(__m128d A, __m128d B) {
// CHECK-LABEL: test_mm_hsub_pd
// CHECK: call <2 x double> @llvm.x86.sse3.hsub.pd
- // CHECK-ASM: hsubpd %xmm{{.*}}, %xmm{{.*}}
return _mm_hsub_pd(A, B);
}
__m128 test_mm_hsub_ps(__m128 A, __m128 B) {
// CHECK-LABEL: test_mm_hsub_ps
// CHECK: call <4 x float> @llvm.x86.sse3.hsub.ps
- // CHECK-ASM: hsubps %xmm{{.*}}, %xmm{{.*}}
return _mm_hsub_ps(A, B);
}
__m128i test_mm_lddqu_si128(__m128i const* P) {
// CHECK-LABEL: test_mm_lddqu_si128
// CHECK: call <16 x i8> @llvm.x86.sse3.ldu.dq
- // CHECK-ASM: lddqu
return _mm_lddqu_si128(P);
}
__m128d test_mm_loaddup_pd(double const* P) {
// CHECK-LABEL: test_mm_loaddup_pd
// CHECK: load double*
- // CHECK-ASM: movddup %xmm{{.*}}
return _mm_loaddup_pd(P);
}
__m128d test_mm_movedup_pd(__m128d A) {
// CHECK-LABEL: test_mm_movedup_pd
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> zeroinitializer
- // CHECK-ASM: movddup %xmm{{.*}}, %xmm{{.*}}
return _mm_movedup_pd(A);
}
__m128 test_mm_movehdup_ps(__m128 A) {
// CHECK-LABEL: test_mm_movehdup_ps
// CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
- // CHECK-ASM: movshdup %xmm{{.*}}, %xmm{{.*}}
return _mm_movehdup_ps(A);
}
-__m128 test_mm_movedup_ps(__m128 A) {
- // CHECK-LABEL: test_mm_movedup_ps
+__m128 test_mm_moveldup_ps(__m128 A) {
+ // CHECK-LABEL: test_mm_moveldup_ps
// CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
- // CHECK-ASM: movsldup %xmm{{.*}}, %xmm{{.*}}
return _mm_moveldup_ps(A);
}
diff --git a/test/CodeGen/sse41-builtins.c b/test/CodeGen/sse41-builtins.c
index 63d8e80..9cd5c45 100644
--- a/test/CodeGen/sse41-builtins.c
+++ b/test/CodeGen/sse41-builtins.c
@@ -1,435 +1,372 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -emit-llvm -o - -Werror | FileCheck %s
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -fno-signed-char -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
#include <x86intrin.h>
-__m128i test_blend_epi16(__m128i V1, __m128i V2) {
- // CHECK-LABEL: test_blend_epi16
+__m128i test_mm_blend_epi16(__m128i V1, __m128i V2) {
+ // CHECK-LABEL: test_mm_blend_epi16
// CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i32> <i32 0, i32 9, i32 2, i32 11, i32 4, i32 13, i32 6, i32 7>
- // CHECK-ASM: pblendw $42, %xmm{{.*}}, %xmm{{.*}}
return _mm_blend_epi16(V1, V2, 42);
}
-__m128d test_blend_pd(__m128d V1, __m128d V2) {
- // CHECK-LABEL: test_blend_pd
+__m128d test_mm_blend_pd(__m128d V1, __m128d V2) {
+ // CHECK-LABEL: test_mm_blend_pd
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 0, i32 3>
- // CHECK-ASM: blendpd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_blend_pd(V1, V2, 2);
}
-__m128 test_blend_ps(__m128 V1, __m128 V2) {
- // CHECK-LABEL: test_blend_ps
+__m128 test_mm_blend_ps(__m128 V1, __m128 V2) {
+ // CHECK-LABEL: test_mm_blend_ps
// CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> <i32 0, i32 5, i32 6, i32 3>
- // CHECK-ASM: blendps $6, %xmm{{.*}}, %xmm{{.*}}
return _mm_blend_ps(V1, V2, 6);
}
-__m128i test_blendv_epi8(__m128i V1, __m128i V2, __m128i V3) {
- // CHECK-LABEL: test_blendv_epi8
+__m128i test_mm_blendv_epi8(__m128i V1, __m128i V2, __m128i V3) {
+ // CHECK-LABEL: test_mm_blendv_epi8
// CHECK: call <16 x i8> @llvm.x86.sse41.pblendvb
- // CHECK-ASM: pblendvb %xmm{{.*}}, %xmm{{.*}}
return _mm_blendv_epi8(V1, V2, V3);
}
-__m128d test_blendv_pd(__m128d V1, __m128d V2, __m128d V3) {
- // CHECK-LABEL: test_blendv_pd
+__m128d test_mm_blendv_pd(__m128d V1, __m128d V2, __m128d V3) {
+ // CHECK-LABEL: test_mm_blendv_pd
// CHECK: call <2 x double> @llvm.x86.sse41.blendvpd
- // CHECK-ASM: blendvpd %xmm{{.*}}, %xmm{{.*}}
return _mm_blendv_pd(V1, V2, V3);
}
-__m128 test_blendv_ps(__m128 V1, __m128 V2, __m128 V3) {
- // CHECK-LABEL: test_blendv_ps
+__m128 test_mm_blendv_ps(__m128 V1, __m128 V2, __m128 V3) {
+ // CHECK-LABEL: test_mm_blendv_ps
// CHECK: call <4 x float> @llvm.x86.sse41.blendvps
- // CHECK-ASM: blendvps %xmm{{.*}}, %xmm{{.*}}
return _mm_blendv_ps(V1, V2, V3);
}
__m128d test_mm_ceil_pd(__m128d x) {
// CHECK-LABEL: test_mm_ceil_pd
// CHECK: call <2 x double> @llvm.x86.sse41.round.pd
- // CHECK-ASM: roundpd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_ceil_pd(x);
}
__m128 test_mm_ceil_ps(__m128 x) {
// CHECK-LABEL: test_mm_ceil_ps
// CHECK: call <4 x float> @llvm.x86.sse41.round.ps
- // CHECK-ASM: roundps $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_ceil_ps(x);
}
__m128d test_mm_ceil_sd(__m128d x, __m128d y) {
// CHECK-LABEL: test_mm_ceil_sd
// CHECK: call <2 x double> @llvm.x86.sse41.round.sd
- // CHECK-ASM: roundsd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_ceil_sd(x, y);
}
__m128 test_mm_ceil_ss(__m128 x, __m128 y) {
// CHECK-LABEL: test_mm_ceil_ss
// CHECK: call <4 x float> @llvm.x86.sse41.round.ss
- // CHECK-ASM: roundss $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_ceil_ss(x, y);
}
__m128i test_mm_cmpeq_epi64(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpeq_epi64
// CHECK: icmp eq <2 x i64>
- // CHECK-ASM: pcmpeqq %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpeq_epi64(A, B);
}
__m128i test_mm_cvtepi8_epi16(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi8_epi16
// CHECK: sext <8 x i8> {{.*}} to <8 x i16>
- // CHECK-ASM: pmovsxbw %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi8_epi16(a);
}
__m128i test_mm_cvtepi8_epi32(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi8_epi32
// CHECK: sext <4 x i8> {{.*}} to <4 x i32>
- // CHECK-ASM: pmovsxbd %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi8_epi32(a);
}
__m128i test_mm_cvtepi8_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi8_epi64
// CHECK: sext <2 x i8> {{.*}} to <2 x i64>
- // CHECK-ASM: pmovsxbq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi8_epi64(a);
}
__m128i test_mm_cvtepi16_epi32(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi16_epi32
// CHECK: sext <4 x i16> {{.*}} to <4 x i32>
- // CHECK-ASM: pmovsxwd %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi16_epi32(a);
}
__m128i test_mm_cvtepi16_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi16_epi64
// CHECK: sext <2 x i16> {{.*}} to <2 x i64>
- // CHECK-ASM: pmovsxwq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi16_epi64(a);
}
__m128i test_mm_cvtepi32_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepi32_epi64
// CHECK: sext <2 x i32> {{.*}} to <2 x i64>
- // CHECK-ASM: pmovsxdq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepi32_epi64(a);
}
__m128i test_mm_cvtepu8_epi16(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu8_epi16
// CHECK: call <8 x i16> @llvm.x86.sse41.pmovzxbw(<16 x i8> {{.*}})
- // CHECK-ASM: pmovzxbw %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu8_epi16(a);
}
__m128i test_mm_cvtepu8_epi32(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu8_epi32
// CHECK: call <4 x i32> @llvm.x86.sse41.pmovzxbd(<16 x i8> {{.*}})
- // CHECK-ASM: pmovzxbd %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu8_epi32(a);
}
__m128i test_mm_cvtepu8_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu8_epi64
// CHECK: call <2 x i64> @llvm.x86.sse41.pmovzxbq(<16 x i8> {{.*}})
- // CHECK-ASM: pmovzxbq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu8_epi64(a);
}
__m128i test_mm_cvtepu16_epi32(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu16_epi32
// CHECK: call <4 x i32> @llvm.x86.sse41.pmovzxwd(<8 x i16> {{.*}})
- // CHECK-ASM: pmovzxwd %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu16_epi32(a);
}
__m128i test_mm_cvtepu16_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu16_epi64
// CHECK: call <2 x i64> @llvm.x86.sse41.pmovzxwq(<8 x i16> {{.*}})
- // CHECK-ASM: pmovzxwq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu16_epi64(a);
}
__m128i test_mm_cvtepu32_epi64(__m128i a) {
// CHECK-LABEL: test_mm_cvtepu32_epi64
// CHECK: call <2 x i64> @llvm.x86.sse41.pmovzxdq(<4 x i32> {{.*}})
- // CHECK-ASM: pmovzxdq %xmm{{.*}}, %xmm{{.*}}
return _mm_cvtepu32_epi64(a);
}
__m128d test_mm_dp_pd(__m128d x, __m128d y) {
// CHECK-LABEL: test_mm_dp_pd
// CHECK: call <2 x double> @llvm.x86.sse41.dppd
- // CHECK-ASM: dppd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_dp_pd(x, y, 2);
}
__m128 test_mm_dp_ps(__m128 x, __m128 y) {
// CHECK-LABEL: test_mm_dp_ps
// CHECK: call <4 x float> @llvm.x86.sse41.dpps
- // CHECK-ASM: dpps $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_dp_ps(x, y, 2);
}
-int test_extract_epi8(__m128i x) {
- // CHECK-LABEL: test_extract_epi8
+int test_mm_extract_epi8(__m128i x) {
+ // CHECK-LABEL: test_mm_extract_epi8
// CHECK: extractelement <16 x i8> %{{.*}}, i32 0
- // CHECK-ASM: pextrb
return _mm_extract_epi8(x, 16);
}
-int test_extract_epi32(__m128i x) {
- // CHECK-LABEL: test_extract_epi32
+int test_mm_extract_epi32(__m128i x) {
+ // CHECK-LABEL: test_mm_extract_epi32
// CHECK: extractelement <4 x i32> %{{.*}}, i32 1
- // CHECK-ASM: pextrd
return _mm_extract_epi32(x, 1);
}
-long long test_extract_epi64(__m128i x) {
- // CHECK-LABEL: test_extract_epi64
+long long test_mm_extract_epi64(__m128i x) {
+ // CHECK-LABEL: test_mm_extract_epi64
// CHECK: extractelement <2 x i64> %{{.*}}, i32 1
- // CHECK-ASM: pextrq
return _mm_extract_epi64(x, 1);
}
//TODO
-//int test_extract_ps(__m128i x) {
+//int test_mm_extract_ps(__m128i x) {
// return _mm_extract_ps(_mm_add_ps(x,x), 1);
//}
__m128d test_mm_floor_pd(__m128d x) {
// CHECK-LABEL: test_mm_floor_pd
// CHECK: call <2 x double> @llvm.x86.sse41.round.pd
- // CHECK-ASM: roundpd $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_floor_pd(x);
}
__m128 test_mm_floor_ps(__m128 x) {
// CHECK-LABEL: test_mm_floor_ps
// CHECK: call <4 x float> @llvm.x86.sse41.round.ps
- // CHECK-ASM: roundps $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_floor_ps(x);
}
__m128d test_mm_floor_sd(__m128d x, __m128d y) {
// CHECK-LABEL: test_mm_floor_sd
// CHECK: call <2 x double> @llvm.x86.sse41.round.sd
- // CHECK-ASM: roundsd $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_floor_sd(x, y);
}
__m128 test_mm_floor_ss(__m128 x, __m128 y) {
// CHECK-LABEL: test_mm_floor_ss
// CHECK: call <4 x float> @llvm.x86.sse41.round.ss
- // CHECK-ASM: roundss $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_floor_ss(x, y);
}
-__m128i test_insert_epi8(__m128i x, char b) {
- // CHECK-LABEL: test_insert_epi8
+__m128i test_mm_insert_epi8(__m128i x, char b) {
+ // CHECK-LABEL: test_mm_insert_epi8
// CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 0
- // CHECK-ASM: pinsrb
return _mm_insert_epi8(x, b, 16);
}
-__m128i test_insert_epi32(__m128i x, int b) {
- // CHECK-LABEL: test_insert_epi32
+__m128i test_mm_insert_epi32(__m128i x, int b) {
+ // CHECK-LABEL: test_mm_insert_epi32
// CHECK: insertelement <4 x i32> %{{.*}}, i32 %{{.*}}, i32 0
- // CHECK-ASM: pinsrd
return _mm_insert_epi32(x, b, 4);
}
-__m128i test_insert_epi64(__m128i x, long long b) {
- // CHECK-LABEL: test_insert_epi64
+__m128i test_mm_insert_epi64(__m128i x, long long b) {
+ // CHECK-LABEL: test_mm_insert_epi64
// CHECK: insertelement <2 x i64> %{{.*}}, i64 %{{.*}}, i32 0
- // CHECK-ASM: pinsrq
return _mm_insert_epi64(x, b, 2);
}
-__m128 test_insert_ps(__m128 x, __m128 y) {
- // CHECK-LABEL: test_insert_ps
+__m128 test_mm_insert_ps(__m128 x, __m128 y) {
+ // CHECK-LABEL: test_mm_insert_ps
// CHECK: call <4 x float> @llvm.x86.sse41.insertps
- // CHECK-ASM: insertps $5, %xmm{{.*}}, %xmm{{.*}}
return _mm_insert_ps(x, y, 5);
}
__m128i test_mm_max_epi8(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_max_epi8
// CHECK: call <16 x i8> @llvm.x86.sse41.pmaxsb
- // CHECK-ASM: pmaxsb %xmm{{.*}}, %xmm{{.*}}
return _mm_max_epi8(x, y);
}
__m128i test_mm_max_epu16(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_max_epu16
// CHECK: call <8 x i16> @llvm.x86.sse41.pmaxuw
- // CHECK-ASM: pmaxuw %xmm{{.*}}, %xmm{{.*}}
return _mm_max_epu16(x, y);
}
__m128i test_mm_max_epi32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_max_epi32
// CHECK: call <4 x i32> @llvm.x86.sse41.pmaxsd
- // CHECK-ASM: pmaxsd %xmm{{.*}}, %xmm{{.*}}
return _mm_max_epi32(x, y);
}
__m128i test_mm_max_epu32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_max_epu32
// CHECK: call <4 x i32> @llvm.x86.sse41.pmaxud
- // CHECK-ASM: pmaxud %xmm{{.*}}, %xmm{{.*}}
return _mm_max_epu32(x, y);
}
__m128i test_mm_min_epi8(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_min_epi8
// CHECK: call <16 x i8> @llvm.x86.sse41.pminsb
- // CHECK-ASM: pminsb %xmm{{.*}}, %xmm{{.*}}
return _mm_min_epi8(x, y);
}
__m128i test_mm_min_epu16(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_min_epu16
// CHECK: call <8 x i16> @llvm.x86.sse41.pminuw
- // CHECK-ASM: pminuw %xmm{{.*}}, %xmm{{.*}}
return _mm_min_epu16(x, y);
}
__m128i test_mm_min_epi32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_min_epi32
// CHECK: call <4 x i32> @llvm.x86.sse41.pminsd
- // CHECK-ASM: pminsd %xmm{{.*}}, %xmm{{.*}}
return _mm_min_epi32(x, y);
}
__m128i test_mm_min_epu32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_min_epu32
// CHECK: call <4 x i32> @llvm.x86.sse41.pminud
- // CHECK-ASM: pminud %xmm{{.*}}, %xmm{{.*}}
return _mm_min_epu32(x, y);
}
__m128i test_mm_minpos_epu16(__m128i x) {
// CHECK-LABEL: test_mm_minpos_epu16
// CHECK: call <8 x i16> @llvm.x86.sse41.phminposuw
- // CHECK-ASM: phminposuw %xmm{{.*}}, %xmm{{.*}}
return _mm_minpos_epu16(x);
}
__m128i test_mm_mpsadbw_epu8(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_mpsadbw_epu8
// CHECK: call <8 x i16> @llvm.x86.sse41.mpsadbw
- // CHECK-ASM: mpsadbw $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_mpsadbw_epu8(x, y, 1);
}
__m128i test_mm_mul_epi32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_mul_epi32
// CHECK: call <2 x i64> @llvm.x86.sse41.pmuldq
- // CHECK-ASM: pmuldq %xmm{{.*}}, %xmm{{.*}}
return _mm_mul_epi32(x, y);
}
__m128i test_mm_mullo_epi32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_mullo_epi32
// CHECK: mul <4 x i32>
- // CHECK-ASM: pmulld %xmm{{.*}}, %xmm{{.*}}
return _mm_mullo_epi32(x, y);
}
__m128i test_mm_packus_epi32(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_packus_epi32
// CHECK: call <8 x i16> @llvm.x86.sse41.packusdw
- // CHECK-ASM: packusdw %xmm{{.*}}, %xmm{{.*}}
return _mm_packus_epi32(x, y);
}
__m128d test_mm_round_pd(__m128d x) {
// CHECK-LABEL: test_mm_round_pd
// CHECK: call <2 x double> @llvm.x86.sse41.round.pd
- // CHECK-ASM: roundpd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_round_pd(x, 2);
}
__m128 test_mm_round_ps(__m128 x) {
// CHECK-LABEL: test_mm_round_ps
// CHECK: call <4 x float> @llvm.x86.sse41.round.ps
- // CHECK-ASM: roundps $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_round_ps(x, 2);
}
__m128d test_mm_round_sd(__m128d x, __m128d y) {
// CHECK-LABEL: test_mm_round_sd
// CHECK: call <2 x double> @llvm.x86.sse41.round.sd
- // CHECK-ASM: roundsd $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_round_sd(x, y, 2);
}
__m128 test_mm_round_ss(__m128 x, __m128 y) {
// CHECK-LABEL: test_mm_round_ss
// CHECK: call <4 x float> @llvm.x86.sse41.round.ss
- // CHECK-ASM: roundss $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_round_ss(x, y, 2);
}
__m128i test_mm_stream_load_si128(__m128i const *a) {
// CHECK-LABEL: test_mm_stream_load_si128
// CHECK: call <2 x i64> @llvm.x86.sse41.movntdqa
- // CHECK-ASM: movntdqa
return _mm_stream_load_si128(a);
}
int test_mm_test_all_ones(__m128i x) {
// CHECK-LABEL: test_mm_test_all_ones
// CHECK: call i32 @llvm.x86.sse41.ptestc
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_test_all_ones(x);
}
int test_mm_test_all_zeros(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_test_all_zeros
// CHECK: call i32 @llvm.x86.sse41.ptestz
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_test_all_zeros(x, y);
}
int test_mm_test_mix_ones_zeros(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_test_mix_ones_zeros
// CHECK: call i32 @llvm.x86.sse41.ptestnzc
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_test_mix_ones_zeros(x, y);
}
int test_mm_testc_si128(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_testc_si128
// CHECK: call i32 @llvm.x86.sse41.ptestc
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_testc_si128(x, y);
}
int test_mm_testnzc_si128(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_testnzc_si128
// CHECK: call i32 @llvm.x86.sse41.ptestnzc
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_testnzc_si128(x, y);
}
int test_mm_testz_si128(__m128i x, __m128i y) {
// CHECK-LABEL: test_mm_testz_si128
// CHECK: call i32 @llvm.x86.sse41.ptestz
- // CHECK-ASM: ptest %xmm{{.*}}, %xmm{{.*}}
return _mm_testz_si128(x, y);
}
diff --git a/test/CodeGen/sse42-builtins.c b/test/CodeGen/sse42-builtins.c
index f45355f..e3215dd 100644
--- a/test/CodeGen/sse42-builtins.c
+++ b/test/CodeGen/sse42-builtins.c
@@ -1,8 +1,5 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.2 -emit-llvm -o - -Werror | FileCheck %s
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.2 -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.2 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4.2 -fno-signed-char -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -12,153 +9,131 @@
__m128i test_mm_cmpgt_epi8(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpgt_epi8
// CHECK: icmp sgt <16 x i8>
- // CHECK-ASM: pcmpgtb %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpgt_epi8(A, B);
}
__m128i test_mm_cmpgt_epi16(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpgt_epi16
// CHECK: icmp sgt <8 x i16>
- // CHECK-ASM: pcmpgtw %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpgt_epi16(A, B);
}
__m128i test_mm_cmpgt_epi32(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpgt_epi32
// CHECK: icmp sgt <4 x i32>
- // CHECK-ASM: pcmpgtd %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpgt_epi32(A, B);
}
__m128i test_mm_cmpgt_epi64(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpgt_epi64
// CHECK: icmp sgt <2 x i64>
- // CHECK-ASM: pcmpgtq %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpgt_epi64(A, B);
}
int test_mm_cmpestra(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestra
// CHECK: @llvm.x86.sse42.pcmpestria128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestra(A, LA, B, LB, 7);
}
int test_mm_cmpestrc(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestrc
// CHECK: @llvm.x86.sse42.pcmpestric128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestrc(A, LA, B, LB, 7);
}
int test_mm_cmpestri(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestri
// CHECK: @llvm.x86.sse42.pcmpestri128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestri(A, LA, B, LB, 7);
}
__m128i test_mm_cmpestrm(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestrm
// CHECK: @llvm.x86.sse42.pcmpestrm128
- // CHECK-ASM: pcmpestrm $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestrm(A, LA, B, LB, 7);
}
int test_mm_cmpestro(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestro
// CHECK: @llvm.x86.sse42.pcmpestrio128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestro(A, LA, B, LB, 7);
}
int test_mm_cmpestrs(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestrs
// CHECK: @llvm.x86.sse42.pcmpestris128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestrs(A, LA, B, LB, 7);
}
int test_mm_cmpestrz(__m128i A, int LA, __m128i B, int LB) {
// CHECK-LABEL: test_mm_cmpestrz
// CHECK: @llvm.x86.sse42.pcmpestriz128
- // CHECK-ASM: pcmpestri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpestrz(A, LA, B, LB, 7);
}
int test_mm_cmpistra(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistra
// CHECK: @llvm.x86.sse42.pcmpistria128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistra(A, B, 7);
}
int test_mm_cmpistrc(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistrc
// CHECK: @llvm.x86.sse42.pcmpistric128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistrc(A, B, 7);
}
int test_mm_cmpistri(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistri
// CHECK: @llvm.x86.sse42.pcmpistri128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistri(A, B, 7);
}
__m128i test_mm_cmpistrm(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistrm
// CHECK: @llvm.x86.sse42.pcmpistrm128
- // CHECK-ASM: pcmpistrm $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistrm(A, B, 7);
}
int test_mm_cmpistro(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistro
// CHECK: @llvm.x86.sse42.pcmpistrio128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistro(A, B, 7);
}
int test_mm_cmpistrs(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistrs
// CHECK: @llvm.x86.sse42.pcmpistris128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistrs(A, B, 7);
}
int test_mm_cmpistrz(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_cmpistrz
// CHECK: @llvm.x86.sse42.pcmpistriz128
- // CHECK-ASM: pcmpistri $7, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmpistrz(A, B, 7);
}
unsigned int test_mm_crc32_u8(unsigned int CRC, unsigned char V) {
// CHECK-LABEL: test_mm_crc32_u8
// CHECK: call i32 @llvm.x86.sse42.crc32.32.8
- // CHECK-ASM: crc32
return _mm_crc32_u8(CRC, V);
}
unsigned int test_mm_crc32_u16(unsigned int CRC, unsigned short V) {
// CHECK-LABEL: test_mm_crc32_u16
// CHECK: call i32 @llvm.x86.sse42.crc32.32.16
- // CHECK-ASM: crc32
return _mm_crc32_u16(CRC, V);
}
unsigned int test_mm_crc32_u32(unsigned int CRC, unsigned int V) {
// CHECK-LABEL: test_mm_crc32_u32
// CHECK: call i32 @llvm.x86.sse42.crc32.32.32
- // CHECK-ASM: crc32
return _mm_crc32_u32(CRC, V);
}
unsigned int test_mm_crc32_u64(unsigned long long CRC, unsigned long long V) {
// CHECK-LABEL: test_mm_crc32_u64
// CHECK: call i64 @llvm.x86.sse42.crc32.64.64
- // CHECK-ASM: crc32
return _mm_crc32_u64(CRC, V);
}
diff --git a/test/CodeGen/sse4a-builtins.c b/test/CodeGen/sse4a-builtins.c
index cdea03f..9a408b8 100644
--- a/test/CodeGen/sse4a-builtins.c
+++ b/test/CodeGen/sse4a-builtins.c
@@ -1,50 +1,42 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4a -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +sse4a -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
#include <x86intrin.h>
-__m128i test_extracti_si64(__m128i x) {
- // CHECK-LABEL: test_extracti_si64
+__m128i test_mm_extracti_si64(__m128i x) {
+ // CHECK-LABEL: test_mm_extracti_si64
// CHECK: call <2 x i64> @llvm.x86.sse4a.extrqi(<2 x i64> %{{[^,]+}}, i8 3, i8 2)
- // CHECK-ASM: extrq $2, $3, %xmm{{.*}}
return _mm_extracti_si64(x, 3, 2);
}
-__m128i test_extract_si64(__m128i x, __m128i y) {
- // CHECK-LABEL: test_extract_si64
+__m128i test_mm_extract_si64(__m128i x, __m128i y) {
+ // CHECK-LABEL: test_mm_extract_si64
// CHECK: call <2 x i64> @llvm.x86.sse4a.extrq(<2 x i64> %{{[^,]+}}, <16 x i8> %{{[^,]+}})
- // CHECK-ASM: extrq %xmm{{.*}}, %xmm{{.*}}
return _mm_extract_si64(x, y);
}
-__m128i test_inserti_si64(__m128i x, __m128i y) {
- // CHECK-LABEL: test_inserti_si64
+__m128i test_mm_inserti_si64(__m128i x, __m128i y) {
+ // CHECK-LABEL: test_mm_inserti_si64
// CHECK: call <2 x i64> @llvm.x86.sse4a.insertqi(<2 x i64> %{{[^,]+}}, <2 x i64> %{{[^,]+}}, i8 5, i8 6)
- // CHECK-ASM: insertq $6, $5, %xmm{{.*}}, %xmm{{.*}}
return _mm_inserti_si64(x, y, 5, 6);
}
-__m128i test_insert_si64(__m128i x, __m128i y) {
- // CHECK-LABEL: test_insert_si64
+__m128i test_mm_insert_si64(__m128i x, __m128i y) {
+ // CHECK-LABEL: test_mm_insert_si64
// CHECK: call <2 x i64> @llvm.x86.sse4a.insertq(<2 x i64> %{{[^,]+}}, <2 x i64> %{{[^,]+}})
- // CHECK-ASM: insertq %xmm{{.*}}, %xmm{{.*}}
return _mm_insert_si64(x, y);
}
-void test_stream_sd(double *p, __m128d a) {
- // CHECK-LABEL: test_stream_sd
+void test_mm_stream_sd(double *p, __m128d a) {
+ // CHECK-LABEL: test_mm_stream_sd
// CHECK: call void @llvm.x86.sse4a.movnt.sd(i8* %{{[^,]+}}, <2 x double> %{{[^,]+}})
- // CHECK-ASM: movntsd %xmm{{.*}}
_mm_stream_sd(p, a);
}
-void test_stream_ss(float *p, __m128 a) {
- // CHECK-LABEL: test_stream_ss
+void test_mm_stream_ss(float *p, __m128 a) {
+ // CHECK-LABEL: test_mm_stream_ss
// CHECK: call void @llvm.x86.sse4a.movnt.ss(i8* %{{[^,]+}}, <4 x float> %{{[^,]+}})
- // CHECK-ASM: movntss %xmm{{.*}}
_mm_stream_ss(p, a);
}
diff --git a/test/CodeGen/ssse3-builtins.c b/test/CodeGen/ssse3-builtins.c
index ec311d9..d4b27a1 100644
--- a/test/CodeGen/ssse3-builtins.c
+++ b/test/CodeGen/ssse3-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +ssse3 -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -10,118 +8,101 @@
__m128i test_mm_abs_epi8(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi8
// CHECK: call <16 x i8> @llvm.x86.ssse3.pabs.b.128
- // CHECK-ASM: pabsb %xmm{{.*}}, %xmm{{.*}}
return _mm_abs_epi8(a);
}
__m128i test_mm_abs_epi16(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.pabs.w.128
- // CHECK-ASM: pabsw %xmm{{.*}}, %xmm{{.*}}
return _mm_abs_epi16(a);
}
__m128i test_mm_abs_epi32(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi32
// CHECK: call <4 x i32> @llvm.x86.ssse3.pabs.d.128
- // CHECK-ASM: pabsd %xmm{{.*}}, %xmm{{.*}}
return _mm_abs_epi32(a);
}
__m128i test_mm_alignr_epi8(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_alignr_epi8
// CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17>
- // CHECK-ASM: palignr $2, %xmm{{.*}}, %xmm{{.*}}
return _mm_alignr_epi8(a, b, 2);
}
__m128i test2_mm_alignr_epi8(__m128i a, __m128i b) {
// CHECK-LABEL: test2_mm_alignr_epi8
// CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> zeroinitializer, <16 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>
- // CHECK-ASM: psrldq $1, %xmm{{.*}}
return _mm_alignr_epi8(a, b, 17);
}
__m128i test_mm_hadd_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hadd_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.phadd.w.128
- // CHECK-ASM: phaddw %xmm{{.*}}, %xmm{{.*}}
return _mm_hadd_epi16(a, b);
}
__m128i test_mm_hadd_epi32(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hadd_epi32
// CHECK: call <4 x i32> @llvm.x86.ssse3.phadd.d.128
- // CHECK-ASM: phaddd %xmm{{.*}}, %xmm{{.*}}
return _mm_hadd_epi32(a, b);
}
__m128i test_mm_hadds_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hadds_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.phadd.sw.128
- // CHECK-ASM: phaddsw %xmm{{.*}}, %xmm{{.*}}
return _mm_hadds_epi16(a, b);
}
__m128i test_mm_hsub_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hsub_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.phsub.w.128
- // CHECK-ASM: phsubw %xmm{{.*}}, %xmm{{.*}}
return _mm_hsub_epi16(a, b);
}
__m128i test_mm_hsub_epi32(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hsub_epi32
// CHECK: call <4 x i32> @llvm.x86.ssse3.phsub.d.128
- // CHECK-ASM: phsubd %xmm{{.*}}, %xmm{{.*}}
return _mm_hsub_epi32(a, b);
}
__m128i test_mm_hsubs_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_hsubs_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.phsub.sw.128
- // CHECK-ASM: phsubsw %xmm{{.*}}, %xmm{{.*}}
return _mm_hsubs_epi16(a, b);
}
__m128i test_mm_maddubs_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_maddubs_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.pmadd.ub.sw.128
- // CHECK-ASM: pmaddubsw %xmm{{.*}}, %xmm{{.*}}
return _mm_maddubs_epi16(a, b);
}
__m128i test_mm_mulhrs_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_mulhrs_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.pmul.hr.sw.128
- // CHECK-ASM: pmulhrsw %xmm{{.*}}, %xmm{{.*}}
return _mm_mulhrs_epi16(a, b);
}
__m128i test_mm_shuffle_epi8(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_shuffle_epi8
// CHECK: call <16 x i8> @llvm.x86.ssse3.pshuf.b.128
- // CHECK-ASM: pshufb %xmm{{.*}}, %xmm{{.*}}
return _mm_shuffle_epi8(a, b);
}
__m128i test_mm_sign_epi8(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_sign_epi8
// CHECK: call <16 x i8> @llvm.x86.ssse3.psign.b.128
- // CHECK-ASM: psignb %xmm{{.*}}, %xmm{{.*}}
return _mm_sign_epi8(a, b);
}
__m128i test_mm_sign_epi16(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_sign_epi16
// CHECK: call <8 x i16> @llvm.x86.ssse3.psign.w.128
- // CHECK-ASM: psignw %xmm{{.*}}, %xmm{{.*}}
return _mm_sign_epi16(a, b);
}
__m128i test_mm_sign_epi32(__m128i a, __m128i b) {
// CHECK-LABEL: test_mm_sign_epi32
// CHECK: call <4 x i32> @llvm.x86.ssse3.psign.d.128
- // CHECK-ASM: psignd %xmm{{.*}}, %xmm{{.*}}
return _mm_sign_epi32(a, b);
}
diff --git a/test/CodeGen/string-literal-short-wstring.c b/test/CodeGen/string-literal-short-wstring.c
index 89aa6f7..01de6a4 100644
--- a/test/CodeGen/string-literal-short-wstring.c
+++ b/test/CodeGen/string-literal-short-wstring.c
@@ -2,6 +2,10 @@
// RUN: %clang_cc1 -x c++ -triple %ms_abi_triple -emit-llvm -fshort-wchar %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=MSABI
// Runs in c++ mode so that wchar_t is available.
+// XFAIL: hexagon
+// Hexagon aligns arrays of size 8+ bytes to a 64-bit boundary, which fails
+// the first check line with "align 1".
+
int main() {
// This should convert to utf8.
// CHECK: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
diff --git a/test/CodeGen/target-builtin-error-3.c b/test/CodeGen/target-builtin-error-3.c
new file mode 100644
index 0000000..5beb474
--- /dev/null
+++ b/test/CodeGen/target-builtin-error-3.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -S -verify -o - -target-feature +avx
+
+// RUN: not %clang_cc1 %s -triple=x86_64-apple-darwin -emit-obj -target-feature +avx 2> %t.err
+// RUN: FileCheck < %t.err %s
+// CHECK: 1 error generated
+
+typedef unsigned short uint16_t;
+typedef long long __m128i __attribute__((__vector_size__(16)));
+typedef float __v8sf __attribute__ ((__vector_size__ (32)));
+typedef float __m256 __attribute__ ((__vector_size__ (32)));
+typedef uint16_t half;
+typedef __attribute__ ((ext_vector_type( 8),__aligned__( 16))) half half8;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 32))) half half16;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 2))) half half16U;
+typedef __attribute__ ((ext_vector_type( 8),__aligned__( 32))) float float8;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 64))) float float16;
+static inline half8 __attribute__((__overloadable__)) convert_half( float8 a ) {
+ return __extension__ ({ __m256 __a = (a); (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (0x00)); }); // expected-error {{'__builtin_ia32_vcvtps2ph256' needs target feature f16c}}
+}
+static inline half16 __attribute__((__overloadable__)) convert_half( float16 a ) {
+ half16 r;
+ r.lo = convert_half( a.lo);
+ return r;
+}
+void avx_test( uint16_t *destData, float16 argbF)
+{
+ ((half16U*)destData)[0] = convert_half(argbF);
+}
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 049e4d1..2ed7f09 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -80,11 +80,11 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY32
-// WEBASSEMBLY32: target datalayout = "e-p:32:32-i64:64-n32:64-S128"
+// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY64
-// WEBASSEMBLY64: target datalayout = "e-p:64:64-i64:64-n32:64-S128"
+// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
// RUN: %clang_cc1 -triple powerpc-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=PPC
@@ -157,7 +157,7 @@
// RUN: %clang_cc1 -triple hexagon-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=HEXAGON
-// HEXAGON: target datalayout = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32"
+// HEXAGON: target datalayout = "e-m:e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f64:64:64-f32:32:32-v64:64:64-v32:32:32-a:0-n16:32"
// RUN: %clang_cc1 -triple s390x-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SYSTEMZ
diff --git a/test/CodeGen/target-features-error-2.c b/test/CodeGen/target-features-error-2.c
new file mode 100644
index 0000000..c23d152
--- /dev/null
+++ b/test/CodeGen/target-features-error-2.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o -
+#define __MM_MALLOC_H
+#include <x86intrin.h>
+
+int baz(__m256i a) {
+ return _mm256_extract_epi32(a, 3); // expected-error {{always_inline function '_mm256_extract_epi32' requires target feature 'sse4.2', but would be inlined into function 'baz' that is compiled without support for 'sse4.2'}}
+}
diff --git a/test/CodeGen/target-features-error.c b/test/CodeGen/target-features-error.c
new file mode 100644
index 0000000..518f6e6
--- /dev/null
+++ b/test/CodeGen/target-features-error.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o -
+int __attribute__((target("avx"), always_inline)) foo(int a) {
+ return a + 4;
+}
+int bar() {
+ return foo(4); // expected-error {{always_inline function 'foo' requires target feature 'sse4.2', but would be inlined into function 'bar' that is compiled without support for 'sse4.2'}}
+}
+
diff --git a/test/CodeGen/target-features-no-error.c b/test/CodeGen/target-features-no-error.c
new file mode 100644
index 0000000..b6283b6
--- /dev/null
+++ b/test/CodeGen/target-features-no-error.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -o - -target-feature -sse2
+
+// Verify that negative features don't cause additional requirements on the inline function.
+int __attribute__((target("sse"), always_inline)) foo(int a) {
+ return a + 4;
+}
+int bar() {
+ return foo(4); // expected-no-diagnostics
+}
diff --git a/test/CodeGen/tbm-builtins.c b/test/CodeGen/tbm-builtins.c
index dc4d50d..29e147a 100644
--- a/test/CodeGen/tbm-builtins.c
+++ b/test/CodeGen/tbm-builtins.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -O3 -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
// FIXME: The code generation checks for add/sub and/or are depending on the optimizer.
+// The REQUIRES keyword will be removed when the FIXME is complete.
+// REQUIRES: x86-registered-target
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
diff --git a/test/CodeGen/thinlto_backend.c b/test/CodeGen/thinlto_backend.c
new file mode 100644
index 0000000..a2737fb
--- /dev/null
+++ b/test/CodeGen/thinlto_backend.c
@@ -0,0 +1,14 @@
+// RUN: %clang -O2 %s -flto=thin -c -o %t.o
+// RUN: llvm-lto -thinlto -o %t %t.o
+
+// Ensure clang -cc1 give expected error for incorrect input type
+// RUN: not %clang_cc1 -O2 -o %t1.o %s -c -fthinlto-index=%t.thinlto.bc 2>&1 | FileCheck %s -check-prefix=CHECK-WARNING
+// CHECK-WARNING: error: invalid argument '-fthinlto-index={{.*}}' only allowed with '-x ir'
+
+// Ensure we get expected error for missing index file
+// RUN: %clang -O2 -o %t1.o -x ir %t.o -c -fthinlto-index=bad.thinlto.bc 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR
+// CHECK-ERROR: Error loading index file 'bad.thinlto.bc'
+
+// Ensure Function Importing pass added
+// RUN: %clang -O2 -o %t1.o -x ir %t.o -c -fthinlto-index=%t.thinlto.bc -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PASS
+// CHECK-PASS: Function Importing
diff --git a/test/CodeGen/ubsan-conditional.c b/test/CodeGen/ubsan-conditional.c
new file mode 100644
index 0000000..7f63b39
--- /dev/null
+++ b/test/CodeGen/ubsan-conditional.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -fsanitize=float-divide-by-zero -o - | FileCheck %s
+
+_Bool b;
+// CHECK: @f(
+double f() {
+ // CHECK: %[[B:.*]] = load {{.*}} @b
+ // CHECK: %[[COND:.*]] = trunc {{.*}} %[[B]] to i1
+ // CHECK: br i1 %[[COND]]
+ return b ? 0.0 / 0.0 : 0.0;
+}
diff --git a/test/CodeGen/ubsan-type-blacklist.cpp b/test/CodeGen/ubsan-type-blacklist.cpp
index b3137e7..26b7aa8 100644
--- a/test/CodeGen/ubsan-type-blacklist.cpp
+++ b/test/CodeGen/ubsan-type-blacklist.cpp
@@ -14,7 +14,7 @@
// DEFAULT: @_Z7checkmev
// TYPE: @_Z7checkmev
void checkme() {
-// DEFAULT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (%class.Bar* @bar to
+// DEFAULT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} ({{.*}}* @bar to
// TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss
Foo* foo = static_cast<Foo*>(&bar); // down-casting
// DEFAULT: ret void
diff --git a/test/CodeGen/wasm-arguments.c b/test/CodeGen/wasm-arguments.c
index 5238804..723632b 100644
--- a/test/CodeGen/wasm-arguments.c
+++ b/test/CodeGen/wasm-arguments.c
@@ -5,8 +5,8 @@
// Basic argument/attribute tests for WebAssembly
-// WEBASSEMBLY32: define void @f0(i32 %i, i32 %j, i64 %k, double %l, double %m)
-// WEBASSEMBLY64: define void @f0(i32 %i, i64 %j, i64 %k, double %l, double %m)
+// WEBASSEMBLY32: define void @f0(i32 %i, i32 %j, i64 %k, double %l, fp128 %m)
+// WEBASSEMBLY64: define void @f0(i32 %i, i64 %j, i64 %k, double %l, fp128 %m)
void f0(int i, long j, long long k, double l, long double m) {}
typedef struct {
diff --git a/test/CodeGen/x86_32-arguments-iamcu.c b/test/CodeGen/x86_32-arguments-iamcu.c
index 12fafdf..b53d34a 100644
--- a/test/CodeGen/x86_32-arguments-iamcu.c
+++ b/test/CodeGen/x86_32-arguments-iamcu.c
@@ -1,20 +1,24 @@
// RUN: %clang_cc1 -w -triple i386-pc-elfiamcu -mfloat-abi soft -emit-llvm -o - %s | FileCheck %s
-// CHECK-LABEL: define void @ints(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 %d)
+// CHECK-LABEL: define void @ints(i32 %a, i32 %b, i32 %c, i32 %d)
void ints(int a, int b, int c, int d) {}
-// CHECK-LABEL: define void @floats(float inreg %a, float inreg %b, float inreg %c, float %d)
+// CHECK-LABEL: define void @floats(float %a, float %b, float %c, float %d)
void floats(float a, float b, float c, float d) {}
-// CHECK-LABEL: define void @mixed(i32 inreg %a, float inreg %b, i32 inreg %c, float %d)
+// CHECK-LABEL: define void @mixed(i32 %a, float %b, i32 %c, float %d)
void mixed(int a, float b, int c, float d) {}
-// CHECK-LABEL: define void @doubles(double inreg %d1, double %d2)
+// CHECK-LABEL: define void @doubles(double %d1, double %d2)
void doubles(double d1, double d2) {}
-// CHECK-LABEL: define void @mixedDoubles(i32 inreg %a, double inreg %d1)
+// CHECK-LABEL: define void @mixedDoubles(i32 %a, double %d1)
void mixedDoubles(int a, double d1) {}
+typedef struct st3_t {
+ char a[3];
+} st3_t;
+
typedef struct st4_t {
int a;
} st4_t;
@@ -30,33 +34,36 @@
int c;
} st12_t;
-// CHECK-LABEL: define void @smallStructs(i32 inreg %st1.coerce, i32 inreg %st2.coerce, i32 inreg %st3.coerce)
+// CHECK-LABEL: define void @smallStructs(i32 %st1.coerce, i32 %st2.coerce, i32 %st3.coerce)
void smallStructs(st4_t st1, st4_t st2, st4_t st3) {}
-// CHECK-LABEL: define void @paddedStruct(i32 inreg %i1, i32 inreg %st.coerce0, i32 inreg %st.coerce1, i32 %st4.0)
+// CHECK-LABEL: define void @paddedStruct(i32 %i1, i32 %st.coerce0, i32 %st.coerce1, i32 %st4.0)
void paddedStruct(int i1, st5_t st, st4_t st4) {}
-// CHECK-LABEL: define void @largeStruct(i32 %st.0, i32 %st.1, i32 %st.2)
-void largeStruct(st12_t st) {}
+// CHECK-LABEL: define void @largeStructBegin(%struct.st12_t* byval align 4 %st)
+void largeStructBegin(st12_t st) {}
-// CHECK-LABEL: define void @largeStructMiddle(i32 inreg %i1, i32 %st.0, i32 %st.1, i32 %st.2, i32 inreg %i2, i32 inreg %i3)
+// CHECK-LABEL: define void @largeStructMiddle(i32 %i1, %struct.st12_t* byval align 4 %st, i32 %i2, i32 %i3)
void largeStructMiddle(int i1, st12_t st, int i2, int i3) {}
-// CHECK-LABEL: define i32 @retSmallStruct(i32 inreg %r.coerce)
+// CHECK-LABEL: define void @largeStructEnd(i32 %i1, i32 %i2, i32 %i3, i32 %st.0, i32 %st.1, i32 %st.2)
+void largeStructEnd(int i1, int i2, int i3, st12_t st) {}
+
+// CHECK-LABEL: define i24 @retNonPow2Struct(i32 %r.coerce)
+st3_t retNonPow2Struct(st3_t r) { return r; }
+
+// CHECK-LABEL: define i32 @retSmallStruct(i32 %r.coerce)
st4_t retSmallStruct(st4_t r) { return r; }
-// CHECK-LABEL: define i64 @retPaddedStruct(i32 inreg %r.coerce0, i32 inreg %r.coerce1)
+// CHECK-LABEL: define i64 @retPaddedStruct(i32 %r.coerce0, i32 %r.coerce1)
st5_t retPaddedStruct(st5_t r) { return r; }
-// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* inreg noalias sret %agg.result, i32 inreg %i1, i32 %r.0, i32 %r.1, i32 %r.2)
+// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret %agg.result, i32 %i1, %struct.st12_t* byval align 4 %r)
st12_t retLargeStruct(int i1, st12_t r) { return r; }
-// FIXME: We really shouldn't be marking this inreg. Right now the
-// inreg gets ignored by the CG for varargs functions, but that's
-// insane.
-// CHECK-LABEL: define i32 @varArgs(i32 inreg %i1, ...)
+// CHECK-LABEL: define i32 @varArgs(i32 %i1, ...)
int varArgs(int i1, ...) { return i1; }
-// CHECK-LABEL: define double @longDoubleArg(double inreg %ld1)
+// CHECK-LABEL: define double @longDoubleArg(double %ld1)
long double longDoubleArg(long double ld1) { return ld1; }
diff --git a/test/CodeGen/x86_32-xsave.c b/test/CodeGen/x86_32-xsave.c
index af458af..da5d38a 100644
--- a/test/CodeGen/x86_32-xsave.c
+++ b/test/CodeGen/x86_32-xsave.c
@@ -1,72 +1,72 @@
-// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=i686-unknown-unknown -target-feature +xsave -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
-// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=i686-unknown-unknown -target-feature +xsave -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
-
-// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
-// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
-
-// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsavec -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
-// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsavec -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
-
-// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaves -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
-// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaves -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
-
-void test() {
- unsigned long long tmp_ULLi;
- void* tmp_vp;
-
-#ifdef TEST_XSAVE
-// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
-
-// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
-// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
- (void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVEOPT
-// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVEC
-// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVES
-// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
-
-// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
-// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
- (void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
-#endif
-}
+// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=i686-unknown-unknown -target-feature +xsave -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
+// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=i686-unknown-unknown -target-feature +xsave -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
+
+// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
+// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
+
+// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsavec -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
+// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsavec -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
+
+// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaves -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
+// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=i686-unknown-unknown -target-feature +xsave -target-feature +xsaves -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
+
+void test() {
+ unsigned long long tmp_ULLi;
+ void* tmp_vp;
+
+#ifdef TEST_XSAVE
+// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
+
+// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
+ (void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVEOPT
+// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVEC
+// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVES
+// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
+
+// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
+ (void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
+#endif
+}
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index bb9fba1..e3b853d 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -336,7 +336,8 @@
// CHECK-LABEL: define i32 @f44
// CHECK: ptrtoint
-// CHECK-NEXT: and {{.*}}, -32
+// CHECK-NEXT: add i64 %{{[0-9]+}}, 31
+// CHECK-NEXT: and i64 %{{[0-9]+}}, -32
// CHECK-NEXT: inttoptr
typedef int T44 __attribute((vector_size(32)));
struct s44 { T44 x; int y; };
diff --git a/test/CodeGen/x86_64-profiling-keep-fp.c b/test/CodeGen/x86_64-profiling-keep-fp.c
new file mode 100644
index 0000000..ca679fa
--- /dev/null
+++ b/test/CodeGen/x86_64-profiling-keep-fp.c
@@ -0,0 +1,14 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O3 -pg -S -o - %s | \
+// RUN: FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O3 -momit-leaf-frame-pointer -pg -S -o - %s | \
+// RUN: FileCheck %s
+
+// Test that the frame pointer is kept when compiling with
+// profiling.
+
+//CHECK: pushq %rbp
+int main(void)
+{
+ return 0;
+}
diff --git a/test/CodeGen/x86_64-xsave.c b/test/CodeGen/x86_64-xsave.c
index ed536be..ecdb725 100644
--- a/test/CodeGen/x86_64-xsave.c
+++ b/test/CodeGen/x86_64-xsave.c
@@ -1,120 +1,120 @@
-// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
-// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
-
-// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
-// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
-
-// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsavec -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
-// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsavec -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
-
-// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaves -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
-// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaves -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
-
-void test() {
- unsigned long long tmp_ULLi;
- void* tmp_vp;
-
-#ifdef TEST_XSAVE
-// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
-
-// XSAVE: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVE: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVE: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
-// XSAVE: call void @llvm.x86.xsave64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
- (void)__builtin_ia32_xsave64(tmp_vp, tmp_ULLi);
-
-// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
-// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
- (void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
-
-// XSAVE: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
-// XSAVE: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
-// XSAVE: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
-// XSAVE: call void @llvm.x86.xrstor64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
- (void)__builtin_ia32_xrstor64(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVEOPT
-// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
-
-// XSAVEOPT: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEOPT: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVEOPT: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVEOPT: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
-// XSAVEOPT: call void @llvm.x86.xsaveopt64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
- (void)__builtin_ia32_xsaveopt64(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVEC
-// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
-
-// XSAVEC: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEC: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVEC: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVEC: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
-// XSAVEC: call void @llvm.x86.xsavec64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
- (void)__builtin_ia32_xsavec64(tmp_vp, tmp_ULLi);
-#endif
-
-#ifdef TEST_XSAVES
-// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
-// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
- (void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
-
-// XSAVES: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVES: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVES: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
-// XSAVES: call void @llvm.x86.xsaves64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
- (void)__builtin_ia32_xsaves64(tmp_vp, tmp_ULLi);
-
-// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
-// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
- (void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
-
-// XSAVES: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
-// XSAVES: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
-// XSAVES: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
-// XSAVES: call void @llvm.x86.xrstors64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
- (void)__builtin_ia32_xrstors64(tmp_vp, tmp_ULLi);
-#endif
-}
+// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
+// RUN: %clang_cc1 %s -DTEST_XSAVE -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVE
+
+// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
+// RUN: %clang_cc1 %s -DTEST_XSAVEOPT -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaveopt -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEOPT
+
+// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsavec -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
+// RUN: %clang_cc1 %s -DTEST_XSAVEC -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsavec -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVEC
+
+// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaves -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
+// RUN: %clang_cc1 %s -DTEST_XSAVES -O0 -triple=x86_64-unknown-unknown -target-feature +xsave -target-feature +xsaves -fno-signed-char -emit-llvm -o - -Werror | FileCheck %s --check-prefix=XSAVES
+
+void test() {
+ unsigned long long tmp_ULLi;
+ void* tmp_vp;
+
+#ifdef TEST_XSAVE
+// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
+
+// XSAVE: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVE: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVE: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVE: call void @llvm.x86.xsave64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
+ (void)__builtin_ia32_xsave64(tmp_vp, tmp_ULLi);
+
+// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
+ (void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
+
+// XSAVE: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
+// XSAVE: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
+// XSAVE: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
+// XSAVE: call void @llvm.x86.xrstor64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
+ (void)__builtin_ia32_xrstor64(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVEOPT
+// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
+
+// XSAVEOPT: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEOPT: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVEOPT: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVEOPT: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVEOPT: call void @llvm.x86.xsaveopt64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
+ (void)__builtin_ia32_xsaveopt64(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVEC
+// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
+
+// XSAVEC: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEC: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVEC: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVEC: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVEC: call void @llvm.x86.xsavec64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
+ (void)__builtin_ia32_xsavec64(tmp_vp, tmp_ULLi);
+#endif
+
+#ifdef TEST_XSAVES
+// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
+ (void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
+
+// XSAVES: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVES: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVES: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVES: call void @llvm.x86.xsaves64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
+ (void)__builtin_ia32_xsaves64(tmp_vp, tmp_ULLi);
+
+// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
+ (void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
+
+// XSAVES: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
+// XSAVES: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
+// XSAVES: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
+// XSAVES: call void @llvm.x86.xrstors64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
+ (void)__builtin_ia32_xrstors64(tmp_vp, tmp_ULLi);
+#endif
+}
diff --git a/test/CodeGen/xop-builtins.c b/test/CodeGen/xop-builtins.c
index 359fc60..5f0f20d 100644
--- a/test/CodeGen/xop-builtins.c
+++ b/test/CodeGen/xop-builtins.c
@@ -1,6 +1,4 @@
-// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +xop -emit-llvm -o - -Werror | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +xop -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -8,385 +6,385 @@
#include <x86intrin.h>
__m128i test_mm_maccs_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccs_epi16
// CHECK: @llvm.x86.xop.vpmacssww
- // CHECK-ASM: vpmacssww %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccs_epi16(a, b, c);
}
__m128i test_mm_macc_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_macc_epi16
// CHECK: @llvm.x86.xop.vpmacsww
- // CHECK-ASM: vpmacsww %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_epi16(a, b, c);
}
__m128i test_mm_maccsd_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccsd_epi16
// CHECK: @llvm.x86.xop.vpmacsswd
- // CHECK-ASM: vpmacsswd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccsd_epi16(a, b, c);
}
__m128i test_mm_maccd_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccd_epi16
// CHECK: @llvm.x86.xop.vpmacswd
- // CHECK-ASM: vpmacswd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccd_epi16(a, b, c);
}
__m128i test_mm_maccs_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccs_epi32
// CHECK: @llvm.x86.xop.vpmacssdd
- // CHECK-ASM: vpmacssdd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccs_epi32(a, b, c);
}
__m128i test_mm_macc_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_macc_epi32
// CHECK: @llvm.x86.xop.vpmacsdd
- // CHECK-ASM: vpmacsdd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macc_epi32(a, b, c);
}
__m128i test_mm_maccslo_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccslo_epi32
// CHECK: @llvm.x86.xop.vpmacssdql
- // CHECK-ASM: vpmacssdql %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccslo_epi32(a, b, c);
}
__m128i test_mm_macclo_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_macclo_epi32
// CHECK: @llvm.x86.xop.vpmacsdql
- // CHECK-ASM: vpmacsdql %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macclo_epi32(a, b, c);
}
__m128i test_mm_maccshi_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maccshi_epi32
// CHECK: @llvm.x86.xop.vpmacssdqh
- // CHECK-ASM: vpmacssdqh %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maccshi_epi32(a, b, c);
}
__m128i test_mm_macchi_epi32(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_macchi_epi32
// CHECK: @llvm.x86.xop.vpmacsdqh
- // CHECK-ASM: vpmacsdqh %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_macchi_epi32(a, b, c);
}
__m128i test_mm_maddsd_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maddsd_epi16
// CHECK: @llvm.x86.xop.vpmadcsswd
- // CHECK-ASM: vpmadcsswd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maddsd_epi16(a, b, c);
}
__m128i test_mm_maddd_epi16(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_maddd_epi16
// CHECK: @llvm.x86.xop.vpmadcswd
- // CHECK-ASM: vpmadcswd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_maddd_epi16(a, b, c);
}
__m128i test_mm_haddw_epi8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddw_epi8
// CHECK: @llvm.x86.xop.vphaddbw
- // CHECK-ASM: vphaddbw %xmm{{.*}}, %xmm{{.*}}
return _mm_haddw_epi8(a);
}
__m128i test_mm_haddd_epi8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddd_epi8
// CHECK: @llvm.x86.xop.vphaddbd
- // CHECK-ASM: vphaddbd %xmm{{.*}}, %xmm{{.*}}
return _mm_haddd_epi8(a);
}
__m128i test_mm_haddq_epi8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epi8
// CHECK: @llvm.x86.xop.vphaddbq
- // CHECK-ASM: vphaddbq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epi8(a);
}
__m128i test_mm_haddd_epi16(__m128i a) {
+ // CHECK-LABEL: test_mm_haddd_epi16
// CHECK: @llvm.x86.xop.vphaddwd
- // CHECK-ASM: vphaddwd %xmm{{.*}}, %xmm{{.*}}
return _mm_haddd_epi16(a);
}
__m128i test_mm_haddq_epi16(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epi16
// CHECK: @llvm.x86.xop.vphaddwq
- // CHECK-ASM: vphaddwq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epi16(a);
}
__m128i test_mm_haddq_epi32(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epi32
// CHECK: @llvm.x86.xop.vphadddq
- // CHECK-ASM: vphadddq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epi32(a);
}
__m128i test_mm_haddw_epu8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddw_epu8
// CHECK: @llvm.x86.xop.vphaddubw
- // CHECK-ASM: vphaddubw %xmm{{.*}}, %xmm{{.*}}
return _mm_haddw_epu8(a);
}
__m128i test_mm_haddd_epu8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddd_epu8
// CHECK: @llvm.x86.xop.vphaddubd
- // CHECK-ASM: vphaddubd %xmm{{.*}}, %xmm{{.*}}
return _mm_haddd_epu8(a);
}
__m128i test_mm_haddq_epu8(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epu8
// CHECK: @llvm.x86.xop.vphaddubq
- // CHECK-ASM: vphaddubq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epu8(a);
}
__m128i test_mm_haddd_epu16(__m128i a) {
+ // CHECK-LABEL: test_mm_haddd_epu16
// CHECK: @llvm.x86.xop.vphadduwd
- // CHECK-ASM: vphadduwd %xmm{{.*}}, %xmm{{.*}}
return _mm_haddd_epu16(a);
}
__m128i test_mm_haddq_epu16(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epu16
// CHECK: @llvm.x86.xop.vphadduwq
- // CHECK-ASM: vphadduwq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epu16(a);
}
__m128i test_mm_haddq_epu32(__m128i a) {
+ // CHECK-LABEL: test_mm_haddq_epu32
// CHECK: @llvm.x86.xop.vphaddudq
- // CHECK-ASM: vphaddudq %xmm{{.*}}, %xmm{{.*}}
return _mm_haddq_epu32(a);
}
__m128i test_mm_hsubw_epi8(__m128i a) {
+ // CHECK-LABEL: test_mm_hsubw_epi8
// CHECK: @llvm.x86.xop.vphsubbw
- // CHECK-ASM: vphsubbw %xmm{{.*}}, %xmm{{.*}}
return _mm_hsubw_epi8(a);
}
__m128i test_mm_hsubd_epi16(__m128i a) {
+ // CHECK-LABEL: test_mm_hsubd_epi16
// CHECK: @llvm.x86.xop.vphsubwd
- // CHECK-ASM: vphsubwd %xmm{{.*}}, %xmm{{.*}}
return _mm_hsubd_epi16(a);
}
__m128i test_mm_hsubq_epi32(__m128i a) {
+ // CHECK-LABEL: test_mm_hsubq_epi32
// CHECK: @llvm.x86.xop.vphsubdq
- // CHECK-ASM: vphsubdq %xmm{{.*}}, %xmm{{.*}}
return _mm_hsubq_epi32(a);
}
__m128i test_mm_cmov_si128(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_cmov_si128
// CHECK: @llvm.x86.xop.vpcmov
- // CHECK-ASM: vpcmov %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_cmov_si128(a, b, c);
}
__m256i test_mm256_cmov_si256(__m256i a, __m256i b, __m256i c) {
+ // CHECK-LABEL: test_mm256_cmov_si256
// CHECK: @llvm.x86.xop.vpcmov.256
- // CHECK-ASM: vpcmov %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_cmov_si256(a, b, c);
}
__m128i test_mm_perm_epi8(__m128i a, __m128i b, __m128i c) {
+ // CHECK-LABEL: test_mm_perm_epi8
// CHECK: @llvm.x86.xop.vpperm
- // CHECK-ASM: vpperm %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_perm_epi8(a, b, c);
}
__m128i test_mm_rot_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_rot_epi8
// CHECK: @llvm.x86.xop.vprotb
- // CHECK-ASM: vprotb %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_rot_epi8(a, b);
}
__m128i test_mm_rot_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_rot_epi16
// CHECK: @llvm.x86.xop.vprotw
- // CHECK-ASM: vprotw %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_rot_epi16(a, b);
}
__m128i test_mm_rot_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_rot_epi32
// CHECK: @llvm.x86.xop.vprotd
- // CHECK-ASM: vprotd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_rot_epi32(a, b);
}
__m128i test_mm_rot_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_rot_epi64
// CHECK: @llvm.x86.xop.vprotq
- // CHECK-ASM: vprotq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_rot_epi64(a, b);
}
__m128i test_mm_roti_epi8(__m128i a) {
+ // CHECK-LABEL: test_mm_roti_epi8
// CHECK: @llvm.x86.xop.vprotbi
- // CHECK-ASM: vprotb $1, %xmm{{.*}}, %xmm{{.*}}
return _mm_roti_epi8(a, 1);
}
__m128i test_mm_roti_epi16(__m128i a) {
+ // CHECK-LABEL: test_mm_roti_epi16
// CHECK: @llvm.x86.xop.vprotwi
- // CHECK-ASM: vprotw $50, %xmm{{.*}}, %xmm{{.*}}
return _mm_roti_epi16(a, 50);
}
__m128i test_mm_roti_epi32(__m128i a) {
+ // CHECK-LABEL: test_mm_roti_epi32
// CHECK: @llvm.x86.xop.vprotdi
- // CHECK-ASM: vprotd $226, %xmm{{.*}}, %xmm{{.*}}
return _mm_roti_epi32(a, -30);
}
__m128i test_mm_roti_epi64(__m128i a) {
+ // CHECK-LABEL: test_mm_roti_epi64
// CHECK: @llvm.x86.xop.vprotqi
- // CHECK-ASM: vprotq $100, %xmm{{.*}}, %xmm{{.*}}
return _mm_roti_epi64(a, 100);
}
__m128i test_mm_shl_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_shl_epi8
// CHECK: @llvm.x86.xop.vpshlb
- // CHECK-ASM: vpshlb %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_shl_epi8(a, b);
}
__m128i test_mm_shl_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_shl_epi16
// CHECK: @llvm.x86.xop.vpshlw
- // CHECK-ASM: vpshlw %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_shl_epi16(a, b);
}
__m128i test_mm_shl_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_shl_epi32
// CHECK: @llvm.x86.xop.vpshld
- // CHECK-ASM: vpshld %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_shl_epi32(a, b);
}
__m128i test_mm_shl_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_shl_epi64
// CHECK: @llvm.x86.xop.vpshlq
- // CHECK-ASM: vpshlq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_shl_epi64(a, b);
}
__m128i test_mm_sha_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_sha_epi8
// CHECK: @llvm.x86.xop.vpshab
- // CHECK-ASM: vpshab %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sha_epi8(a, b);
}
__m128i test_mm_sha_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_sha_epi16
// CHECK: @llvm.x86.xop.vpshaw
- // CHECK-ASM: vpshaw %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sha_epi16(a, b);
}
__m128i test_mm_sha_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_sha_epi32
// CHECK: @llvm.x86.xop.vpshad
- // CHECK-ASM: vpshad %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sha_epi32(a, b);
}
__m128i test_mm_sha_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_sha_epi64
// CHECK: @llvm.x86.xop.vpshaq
- // CHECK-ASM: vpshaq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_sha_epi64(a, b);
}
__m128i test_mm_com_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epu8
// CHECK: @llvm.x86.xop.vpcomub
- // CHECK-ASM: vpcomltub %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epu8(a, b, 0);
}
__m128i test_mm_com_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epu16
// CHECK: @llvm.x86.xop.vpcomuw
- // CHECK-ASM: vpcomltuw %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epu16(a, b, 0);
}
__m128i test_mm_com_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epu32
// CHECK: @llvm.x86.xop.vpcomud
- // CHECK-ASM: vpcomltud %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epu32(a, b, 0);
}
__m128i test_mm_com_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epu64
// CHECK: @llvm.x86.xop.vpcomuq
- // CHECK-ASM: vpcomltuq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epu64(a, b, 0);
}
__m128i test_mm_com_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epi8
// CHECK: @llvm.x86.xop.vpcomb
- // CHECK-ASM: vpcomltb %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epi8(a, b, 0);
}
__m128i test_mm_com_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epi16
// CHECK: @llvm.x86.xop.vpcomw
- // CHECK-ASM: vpcomltw %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epi16(a, b, 0);
}
__m128i test_mm_com_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epi32
// CHECK: @llvm.x86.xop.vpcomd
- // CHECK-ASM: vpcomltd %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epi32(a, b, 0);
}
__m128i test_mm_com_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_com_epi64
// CHECK: @llvm.x86.xop.vpcomq
- // CHECK-ASM: vpcomltq %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_com_epi64(a, b, 0);
}
__m128d test_mm_permute2_pd(__m128d a, __m128d b, __m128i c) {
+ // CHECK-LABEL: test_mm_permute2_pd
// CHECK: @llvm.x86.xop.vpermil2pd
- // CHECK-ASM: vpermil2pd $0, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_permute2_pd(a, b, c, 0);
}
__m256d test_mm256_permute2_pd(__m256d a, __m256d b, __m256i c) {
+ // CHECK-LABEL: test_mm256_permute2_pd
// CHECK: @llvm.x86.xop.vpermil2pd.256
- // CHECK-ASM: vpermil2pd $0, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permute2_pd(a, b, c, 0);
}
__m128 test_mm_permute2_ps(__m128 a, __m128 b, __m128i c) {
+ // CHECK-LABEL: test_mm_permute2_ps
// CHECK: @llvm.x86.xop.vpermil2ps
- // CHECK-ASM: vpermil2ps $0, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}, %xmm{{.*}}
return _mm_permute2_ps(a, b, c, 0);
}
__m256 test_mm256_permute2_ps(__m256 a, __m256 b, __m256i c) {
+ // CHECK-LABEL: test_mm256_permute2_ps
// CHECK: @llvm.x86.xop.vpermil2ps.256
- // CHECK-ASM: vpermil2ps $0, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}, %ymm{{.*}}
return _mm256_permute2_ps(a, b, c, 0);
}
__m128 test_mm_frcz_ss(__m128 a) {
+ // CHECK-LABEL: test_mm_frcz_ss
// CHECK: @llvm.x86.xop.vfrcz.ss
- // CHECK-ASM: vfrczss %xmm{{.*}}, %xmm{{.*}}
return _mm_frcz_ss(a);
}
__m128d test_mm_frcz_sd(__m128d a) {
+ // CHECK-LABEL: test_mm_frcz_sd
// CHECK: @llvm.x86.xop.vfrcz.sd
- // CHECK-ASM: vfrczsd %xmm{{.*}}, %xmm{{.*}}
return _mm_frcz_sd(a);
}
__m128 test_mm_frcz_ps(__m128 a) {
+ // CHECK-LABEL: test_mm_frcz_ps
// CHECK: @llvm.x86.xop.vfrcz.ps
- // CHECK-ASM: vfrczps %xmm{{.*}}, %xmm{{.*}}
return _mm_frcz_ps(a);
}
__m128d test_mm_frcz_pd(__m128d a) {
+ // CHECK-LABEL: test_mm_frcz_pd
// CHECK: @llvm.x86.xop.vfrcz.pd
- // CHECK-ASM: vfrczpd %xmm{{.*}}, %xmm{{.*}}
return _mm_frcz_pd(a);
}
__m256 test_mm256_frcz_ps(__m256 a) {
+ // CHECK-LABEL: test_mm256_frcz_ps
// CHECK: @llvm.x86.xop.vfrcz.ps.256
- // CHECK-ASM: vfrczps %ymm{{.*}}, %ymm{{.*}}
return _mm256_frcz_ps(a);
}
__m256d test_mm256_frcz_pd(__m256d a) {
+ // CHECK-LABEL: test_mm256_frcz_pd
// CHECK: @llvm.x86.xop.vfrcz.pd.256
- // CHECK-ASM: vfrczpd %ymm{{.*}}, %ymm{{.*}}
return _mm256_frcz_pd(a);
}
diff --git a/test/CodeGenCUDA/device-vtable.cu b/test/CodeGenCUDA/device-vtable.cu
new file mode 100644
index 0000000..9730e40
--- /dev/null
+++ b/test/CodeGenCUDA/device-vtable.cu
@@ -0,0 +1,61 @@
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// Make sure we don't emit vtables for classes with methods that have
+// inappropriate target attributes. Currently it's mostly needed in
+// order to avoid emitting vtables for host-only classes on device
+// side where we can't codegen them.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix=CHECK-HOST -check-prefix=CHECK-BOTH
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fcuda-is-device -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix=CHECK-DEVICE -check-prefix=CHECK-BOTH
+
+#include "Inputs/cuda.h"
+
+struct H {
+ virtual void method();
+};
+//CHECK-HOST: @_ZTV1H =
+//CHECK-HOST-SAME: @_ZN1H6methodEv
+//CHECK-DEVICE-NOT: @_ZTV1H =
+
+struct D {
+ __device__ virtual void method();
+};
+
+//CHECK-DEVICE: @_ZTV1D
+//CHECK-DEVICE-SAME: @_ZN1D6methodEv
+//CHECK-HOST-NOT: @_ZTV1D
+
+// This is the case with mixed host and device virtual methods. It's
+// impossible to emit a valid vtable in that case because only host or
+// only device methods would be available during host or device
+// compilation. At the moment Clang (and NVCC) emit NULL pointers for
+// unavailable methods,
+struct HD {
+ virtual void h_method();
+ __device__ virtual void d_method();
+};
+// CHECK-BOTH: @_ZTV2HD
+// CHECK-DEVICE-NOT: @_ZN2HD8h_methodEv
+// CHECK-DEVICE-SAME: null
+// CHECK-DEVICE-SAME: @_ZN2HD8d_methodEv
+// CHECK-HOST-SAME: @_ZN2HD8h_methodEv
+// CHECK-HOST-NOT: @_ZN2HD8d_methodEv
+// CHECK-HOST-SAME: null
+// CHECK-BOTH-SAME: ]
+
+void H::method() {}
+//CHECK-HOST: define void @_ZN1H6methodEv
+
+void __device__ D::method() {}
+//CHECK-DEVICE: define void @_ZN1D6methodEv
+
+void __device__ HD::d_method() {}
+// CHECK-DEVICE: define void @_ZN2HD8d_methodEv
+// CHECK-HOST-NOT: define void @_ZN2HD8d_methodEv
+void HD::h_method() {}
+// CHECK-HOST: define void @_ZN2HD8h_methodEv
+// CHECK-DEVICE-NOT: define void @_ZN2HD8h_methodEv
+
diff --git a/test/CodeGenCXX/attr-disable-tail-calls.cpp b/test/CodeGenCXX/attr-disable-tail-calls.cpp
new file mode 100644
index 0000000..b9a3c27
--- /dev/null
+++ b/test/CodeGenCXX/attr-disable-tail-calls.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+class B {
+public:
+ [[clang::disable_tail_calls]] virtual int m1() { return 1; }
+ virtual int m2() { return 2; }
+ int m3() { return 3; }
+ [[clang::disable_tail_calls]] int m4();
+};
+
+class D : public B {
+public:
+ int m1() override { return 11; }
+ [[clang::disable_tail_calls]] int m2() override { return 22; }
+};
+
+int foo1() {
+ B *b = new B;
+ D *d = new D;
+ int t = 0;
+ t += b->m1() + b->m2() + b->m3() + b->m4();
+ t += d->m1() + d->m2();
+ return t;
+}
+
+// CHECK: define linkonce_odr i32 @_ZN1B2m3Ev(%class.B* %this) [[ATTRFALSE:#[0-9]+]]
+// CHECK: declare i32 @_ZN1B2m4Ev(%class.B*) [[ATTRTRUE0:#[0-9]+]]
+// CHECK: define linkonce_odr i32 @_ZN1B2m1Ev(%class.B* %this) unnamed_addr [[ATTRTRUE1:#[0-9]+]]
+// CHECK: define linkonce_odr i32 @_ZN1B2m2Ev(%class.B* %this) unnamed_addr [[ATTRFALSE:#[0-9]+]]
+// CHECK: define linkonce_odr i32 @_ZN1D2m1Ev(%class.D* %this) unnamed_addr [[ATTRFALSE:#[0-9]+]]
+// CHECK: define linkonce_odr i32 @_ZN1D2m2Ev(%class.D* %this) unnamed_addr [[ATTRTRUE1:#[0-9]+]]
+
+// CHECK: attributes [[ATTRFALSE]] = { {{.*}}"disable-tail-calls"="false"{{.*}} }
+// CHECK: attributes [[ATTRTRUE0]] = { {{.*}}"disable-tail-calls"="true"{{.*}} }
+// CHECK: attributes [[ATTRTRUE1]] = { {{.*}}"disable-tail-calls"="true"{{.*}} }
diff --git a/test/CodeGenCXX/attr-x86-interrupt.cpp b/test/CodeGenCXX/attr-x86-interrupt.cpp
new file mode 100644
index 0000000..5000104
--- /dev/null
+++ b/test/CodeGenCXX/attr-x86-interrupt.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_LINUX
+// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_WIN
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_WIN
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_64_LINUX
+
+#ifdef __x86_64__
+typedef __UINT64_TYPE__ uword;
+#else
+typedef __UINT32_TYPE__ uword;
+#endif
+
+__attribute__((interrupt)) void foo7(int *a, uword b) {}
+namespace S {
+__attribute__((interrupt)) void foo8(int *a) {}
+}
+struct St {
+static void foo9(int *a) __attribute__((interrupt)) {}
+};
+// X86_64_LINUX: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i64)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_64_LINUX: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_LINUX: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_64_LINUX: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_LINUX: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i32)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_LINUX: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i32 %{{.+}})
+// X86_LINUX: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_LINUX: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_64_WIN: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i64)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_64_WIN: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i64 %{{.+}})
+// X86_64_WIN: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_64_WIN: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
+// X86_WIN: @llvm.used = appending global [3 x i8*] [i8* bitcast (void (i32*, i32)* @{{.*}}foo7{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo8{{.*}} to i8*), i8* bitcast (void (i32*)* @{{.*}}foo9{{.*}} to i8*)], section "llvm.metadata"
+// X86_WIN: define x86_intrcc void @{{.*}}foo7{{.*}}(i32* %{{.+}}, i32 %{{.+}})
+// X86_WIN: define x86_intrcc void @{{.*}}foo8{{.*}}(i32* %{{.+}})
+// X86_WIN: define linkonce_odr x86_intrcc void @{{.*}}foo9{{.*}}(i32* %{{.+}})
diff --git a/test/CodeGenCXX/attribute_internal_linkage.cpp b/test/CodeGenCXX/attribute_internal_linkage.cpp
new file mode 100644
index 0000000..21cd44e
--- /dev/null
+++ b/test/CodeGenCXX/attribute_internal_linkage.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+__attribute__((internal_linkage)) void f() {}
+// CHECK-DAG: define internal void @_ZL1fv
+
+class A {
+public:
+ static int y __attribute__((internal_linkage));
+ static int y2 [[clang::internal_linkage]];
+// CHECK-DAG: @_ZN1A1yE = internal global
+// CHECK-DAG: @_ZN1A2y2E = internal global
+ void f1() __attribute__((internal_linkage));
+// CHECK-DAG: define internal void @_ZN1A2f1Ev
+ void f2() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1A2f2Ev
+ static void f4() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1A2f4Ev
+ A() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1AC1Ev
+// CHECK-DAG: define internal void @_ZN1AC2Ev
+ ~A() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1AD1Ev
+// CHECK-DAG: define internal void @_ZN1AD2Ev
+};
+
+int A::y;
+int A::y2;
+
+void A::f1() {
+}
+
+// Forward declaration w/o an attribute.
+class B;
+
+// Internal_linkage on a class affects all its members.
+class __attribute__((internal_linkage)) B {
+public:
+ B() {}
+ // CHECK-DAG: define internal void @_ZNL1BC1Ev
+ // CHECK-DAG: define internal void @_ZNL1BC2Ev
+ ~B() {}
+ // CHECK-DAG: define internal void @_ZNL1BD1Ev
+ // CHECK-DAG: define internal void @_ZNL1BD2Ev
+ void f() {};
+ // CHECK-DAG: define internal void @_ZNL1B1fEv
+ static int x;
+ // CHECK-DAG: @_ZNL1B1xE = internal global
+};
+
+int B::x;
+
+// Forward declaration with the attribute.
+class __attribute__((internal_linkage)) C;
+class C {
+public:
+ static int x;
+ // CHECK-DAG: @_ZNL1C1xE = internal global
+};
+
+int C::x;
+
+__attribute__((internal_linkage)) void g();
+void g() {}
+// CHECK-DAG: define internal void @_ZL1gv()
+
+void use() {
+ A a;
+ a.f1();
+ a.f2();
+ A::f4();
+ f();
+ int &Y = A::y;
+ int &Y2 = A::y2;
+ B b;
+ b.f();
+ int &XX2 = B::x;
+ g();
+ int &XX3 = C::x;
+}
diff --git a/test/CodeGenCXX/builtins-systemz-zvector.cpp b/test/CodeGenCXX/builtins-systemz-zvector.cpp
new file mode 100644
index 0000000..aedb30f
--- /dev/null
+++ b/test/CodeGenCXX/builtins-systemz-zvector.cpp
@@ -0,0 +1,50 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
+// RUN: -fzvector -fno-lax-vector-conversions -std=c++11 \
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+
+bool gb;
+
+// There was an issue where we weren't properly converting constexprs to
+// vectors with elements of the appropriate width. (e.g.
+// (vector signed short)0 would be lowered as [4 x i32] in some cases)
+
+// CHECK-LABEL: @_Z8testIntsDv4_i
+void testInts(vector int VI) {
+ constexpr vector int CI1 = (vector int)0LL;
+ // CHECK: icmp
+ gb = (VI == CI1)[0];
+
+ // Likewise for float inits.
+ constexpr vector int CI2 = (vector int)char(0);
+ // CHECK: icmp
+ gb = (VI == CI2)[0];
+
+ constexpr vector int CF1 = (vector int)0.0;
+ // CHECK: icmp
+ gb = (VI == CF1)[0];
+
+ constexpr vector int CF2 = (vector int)0.0f;
+ // CHECK: icmp
+ gb = (VI == CF2)[0];
+}
+
+// CHECK-LABEL: @_Z10testFloatsDv2_d
+void testFloats(vector double VD) {
+ constexpr vector double CI1 = (vector double)0LL;
+ // CHECK: fcmp
+ gb = (VD == CI1)[0];
+
+ // Likewise for float inits.
+ constexpr vector double CI2 = (vector double)char(0);
+ // CHECK: fcmp
+ gb = (VD == CI2)[0];
+
+ constexpr vector double CF1 = (vector double)0.0;
+ // CHECK: fcmp
+ gb = (VD == CF1)[0];
+
+ constexpr vector double CF2 = (vector double)0.0f;
+ // CHECK: fcmp
+ gb = (VD == CF2)[0];
+}
diff --git a/test/CodeGenCXX/cfi-cast.cpp b/test/CodeGenCXX/cfi-cast.cpp
index 0b96cb6..845b955 100644
--- a/test/CodeGenCXX/cfi-cast.cpp
+++ b/test/CodeGenCXX/cfi-cast.cpp
@@ -8,6 +8,7 @@
struct A {
virtual void f();
+ int i() const;
};
struct B : A {
@@ -103,23 +104,31 @@
// CHECK-UCAST-LABEL: define void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define void @_Z3vcpPv
void vcp(void *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
+ // CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
static_cast<C*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3bcpP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z3bcpP1B
void bcp(B *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
+ // CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(C *)p;
}
// CHECK-UCAST-LABEL: define void @_Z8bcp_callP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z8bcp_callP1B
void bcp_call(B *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
+ // CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
((C *)p)->f();
}
+
+// CHECK-UCAST-LABEL: define i32 @_Z6a_callP1A
+// CHECK-UCAST-STRICT-LABEL: define i32 @_Z6a_callP1A
+int a_call(A *a) {
+ // CHECK-UCAST-NOT: @llvm.bitset.test
+ // CHECK-UCAST-STRICT-NOT: @llvm.bitset.test
+ return a->i();
+}
diff --git a/test/CodeGenCXX/cfi-cross-dso.cpp b/test/CodeGenCXX/cfi-cross-dso.cpp
new file mode 100644
index 0000000..fbe6fc8
--- /dev/null
+++ b/test/CodeGenCXX/cfi-cross-dso.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-cfi-cross-dso -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
+
+struct A {
+ A();
+ virtual void f();
+};
+
+A::A() {}
+void A::f() {}
+
+void caller(A* a) {
+ a->f();
+}
+
+namespace {
+struct B {
+ virtual void f();
+};
+
+void B::f() {}
+} // namespace
+
+void g() {
+ B b;
+ b.f();
+}
+
+// MS: @[[B_VTABLE:.*]] = private unnamed_addr constant [2 x i8*] {{.*}}@"\01??_R4B@?A@@6B@"{{.*}}@"\01?f@B@?A@@UEAAXXZ"
+
+// CHECK: %[[VT:.*]] = load void (%struct.A*)**, void (%struct.A*)***
+// CHECK: %[[VT2:.*]] = bitcast {{.*}}%[[VT]] to i8*, !nosanitize
+// ITANIUM: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"_ZTS1A"), !nosanitize
+// MS: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"?AUA@@"), !nosanitize
+// CHECK: br i1 %[[TEST]], label %[[CONT:.*]], label %[[SLOW:.*]], {{.*}} !nosanitize
+// CHECK: [[SLOW]]
+// ITANIUM: call void @__cfi_slowpath(i64 7004155349499253778, i8* %[[VT2]]) {{.*}} !nosanitize
+// MS: call void @__cfi_slowpath(i64 -8005289897957287421, i8* %[[VT2]]) {{.*}} !nosanitize
+// CHECK: br label %[[CONT]], !nosanitize
+// CHECK: [[CONT]]
+// CHECK: call void %{{.*}}(%struct.A* %{{.*}})
+
+// No hash-based bit set entry for (anonymous namespace)::B
+// ITANIUM-NOT: !{i64 {{.*}}, [3 x i8*]* @_ZTVN12_GLOBAL__N_11BE,
+// MS-NOT: !{i64 {{.*}}, [2 x i8*]* @[[B_VTABLE]],
diff --git a/test/CodeGenCXX/cfi-stats.cpp b/test/CodeGenCXX/cfi-stats.cpp
new file mode 100644
index 0000000..49c0677
--- /dev/null
+++ b/test/CodeGenCXX/cfi-stats.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck --check-prefix=CHECK %s
+
+// CHECK: [[STATS:@[^ ]*]] = internal global { i8*, i32, [5 x [2 x i8*]] } { i8* null, i32 5, [5 x [2 x i8*]]
+// CHECK: {{\[\[}}2 x i8*] zeroinitializer,
+// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 2305843009213693952 to i8*)],
+// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 4611686018427387904 to i8*)],
+// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 6917529027641081856 to i8*)],
+// CHECK: [2 x i8*] [i8* null, i8* inttoptr (i64 -9223372036854775808 to i8*)]] }
+
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* [[CTOR:@[^ ]*]], i8* null }]
+
+struct A {
+ virtual void vf();
+ void nvf();
+};
+struct B : A {};
+
+// CHECK: @vcall
+extern "C" void vcall(A *a) {
+ // CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 0
+ a->vf();
+}
+
+// CHECK: @nvcall
+extern "C" void nvcall(A *a) {
+ // CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 1
+ a->nvf();
+}
+
+// CHECK: @dcast
+extern "C" void dcast(A *a) {
+ // CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 2
+ static_cast<B *>(a);
+}
+
+// CHECK: @ucast
+extern "C" void ucast(void *a) {
+ // CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 3
+ reinterpret_cast<A *>(a);
+}
+
+// CHECK: @icall
+extern "C" void icall(void (*p)()) {
+ // CHECK: call void @__sanitizer_stat_report({{.*}}[[STATS]]{{.*}}i64 0, i32 2, i64 4
+ p();
+}
+
+// CHECK: define internal void [[CTOR]]()
+// CHECK-NEXT: call void @__sanitizer_stat_init(i8* bitcast ({ i8*, i32, [5 x [2 x i8*]] }* [[STATS]] to i8*))
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/crash.cpp b/test/CodeGenCXX/crash.cpp
index d34deb9..d12c021 100644
--- a/test/CodeGenCXX/crash.cpp
+++ b/test/CodeGenCXX/crash.cpp
@@ -1,4 +1,3 @@
-// XFAIL: hexagon
// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
// RUN: %clang_cc1 -emit-obj -o %t -debug-info-kind=line-tables-only -std=c++11 %s
// CHECK that we don't crash.
diff --git a/test/CodeGenCXX/cxx11-thread-local-reference.cpp b/test/CodeGenCXX/cxx11-thread-local-reference.cpp
index 2d74120..048a0bd 100644
--- a/test/CodeGenCXX/cxx11-thread-local-reference.cpp
+++ b/test/CodeGenCXX/cxx11-thread-local-reference.cpp
@@ -1,11 +1,14 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=LINUX %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-apple-darwin12 | FileCheck --check-prefix=CHECK --check-prefix=DARWIN %s
int &f();
-// CHECK: @r = thread_local global i32* null
+// LINUX: @r = thread_local global i32* null
+// DARWIN: @r = internal thread_local global i32* null
thread_local int &r = f();
-// CHECK: @_ZTH1r = alias void (), void ()* @__tls_init
+// LINUX: @_ZTH1r = alias void (), void ()* @__tls_init
+// DARWIN: @_ZTH1r = internal alias void (), void ()* @__tls_init
int &g() { return r; }
@@ -14,13 +17,18 @@
// CHECK: store i32* %{{.*}}, i32** @r, align 8
// CHECK-LABEL: define dereferenceable({{[0-9]+}}) i32* @_Z1gv()
-// CHECK: call i32* @_ZTW1r()
+// LINUX: call i32* @_ZTW1r()
+// DARWIN: call cxx_fast_tlscc i32* @_ZTW1r()
// CHECK: ret i32* %{{.*}}
-// CHECK: define weak_odr hidden i32* @_ZTW1r() {
+// LINUX: define weak_odr hidden i32* @_ZTW1r() [[ATTR0:#[0-9]+]] {
+// DARWIN: define cxx_fast_tlscc i32* @_ZTW1r() [[ATTR1:#[0-9]+]] {
// CHECK: call void @_ZTH1r()
// CHECK: load i32*, i32** @r, align 8
// CHECK: ret i32* %{{.*}}
// CHECK-LABEL: define internal void @__tls_init()
// CHECK: call void @[[R_INIT]]()
+
+// LINUX: attributes [[ATTR0]] = { {{.*}}"target-features"{{.*}} }
+// DARWIN: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}}"target-features"{{.*}} }
diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp
index e28447e..40f33e0 100644
--- a/test/CodeGenCXX/cxx11-thread-local.cpp
+++ b/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -1,11 +1,13 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=LINUX %s
// RUN: %clang_cc1 -std=c++11 -femulated-tls -emit-llvm %s -o - \
-// RUN: -triple x86_64-linux-gnu 2>&1 | FileCheck --check-prefix=CHECK %s
+// RUN: -triple x86_64-linux-gnu 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=LINUX %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-apple-darwin12 | FileCheck --check-prefix=CHECK --check-prefix=DARWIN %s
int f();
int g();
-// CHECK: @a = thread_local global i32 0
+// LINUX: @a = thread_local global i32 0
+// DARWIN: @a = internal thread_local global i32 0
thread_local int a = f();
extern thread_local int b;
// CHECK: @c = global i32 0
@@ -14,9 +16,22 @@
static thread_local int d = g();
struct U { static thread_local int m; };
-// CHECK: @_ZN1U1mE = thread_local global i32 0
+// LINUX: @_ZN1U1mE = thread_local global i32 0
+// DARWIN: @_ZN1U1mE = internal thread_local global i32 0
thread_local int U::m = f();
+namespace MismatchedInitType {
+ // Check that we don't crash here when we're forced to create a new global
+ // variable (with a different type) when we add the initializer.
+ union U {
+ int a;
+ float f;
+ constexpr U() : f(0.0) {}
+ };
+ static thread_local U u;
+ void *p = &u;
+}
+
template<typename T> struct V { static thread_local int m; };
template<typename T> thread_local int V<T>::m = g();
@@ -45,9 +60,11 @@
// CHECK: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]]
-// CHECK: @_ZTH1a = alias void (), void ()* @__tls_init
+// LINUX: @_ZTH1a = alias void (), void ()* @__tls_init
+// DARWIN: @_ZTH1a = internal alias void (), void ()* @__tls_init
// CHECK: @_ZTHL1d = internal alias void (), void ()* @__tls_init
-// CHECK: @_ZTHN1U1mE = alias void (), void ()* @__tls_init
+// LINUX: @_ZTHN1U1mE = alias void (), void ()* @__tls_init
+// DARWIN: @_ZTHN1U1mE = internal alias void (), void ()* @__tls_init
// CHECK: @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @__tls_init
@@ -74,17 +91,20 @@
}
// CHECK: define {{.*}} @[[C_INIT:.*]]()
-// CHECK: call i32* @_ZTW1b()
+// LINUX: call i32* @_ZTW1b()
+// DARWIN: call cxx_fast_tlscc i32* @_ZTW1b()
// CHECK-NEXT: load i32, i32* %{{.*}}, align 4
// CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4
-// CHECK-LABEL: define weak_odr hidden i32* @_ZTW1b()
-// CHECK: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
+// LINUX-LABEL: define weak_odr hidden i32* @_ZTW1b()
+// LINUX: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
// not null:
-// CHECK: call void @_ZTH1b()
-// CHECK: br label
+// LINUX: call void @_ZTH1b()
+// LINUX: br label
// finally:
-// CHECK: ret i32* @b
+// LINUX: ret i32* @b
+// DARWIN-LABEL: declare cxx_fast_tlscc i32* @_ZTW1b()
+// There is no definition of the thread wrapper on Darwin for external TLV.
// CHECK: define {{.*}} @[[D_INIT:.*]]()
// CHECK: call i32 @_Z1gv()
@@ -95,11 +115,13 @@
// CHECK-NEXT: store i32 %{{.*}}, i32* @_ZN1U1mE, align 4
// CHECK: define {{.*}} @[[E_INIT:.*]]()
-// CHECK: call i32* @_ZTWN1VIiE1mE()
+// LINUX: call i32* @_ZTWN1VIiE1mE()
+// DARWIN: call cxx_fast_tlscc i32* @_ZTWN1VIiE1mE()
// CHECK-NEXT: load i32, i32* %{{.*}}, align 4
// CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4
-// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
+// LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
+// DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1VIiE1mE()
// CHECK: call void @_ZTHN1VIiE1mE()
// CHECK: ret i32* @_ZN1VIiE1mE
@@ -111,24 +133,28 @@
void tls_dtor() {
// CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1s
// CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZZ8tls_dtorvE1s)
- // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle
+ // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle
+ // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle
// CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1s
static thread_local S s;
// CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1t
// CHECK-NOT: _ZN1T
- // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle
+ // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle
+ // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle
// CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1t
static thread_local T t;
// CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1u
// CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZGRZ8tls_dtorvE1u_)
- // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u_{{.*}} @__dso_handle
+ // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u_{{.*}} @__dso_handle
+ // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u_{{.*}} @__dso_handle
// CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1u
static thread_local const S &u = S();
}
-// CHECK: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
+// LINUX: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
+// DARWIN: declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*)
// CHECK: define {{.*}} @_Z7PR15991v(
int PR15991() {
@@ -143,7 +169,8 @@
};
// CHECK: define {{.*}} @_ZN7PR192541fEv(
int PR19254::f() {
- // CHECK: call void @_ZTHN7PR192541nE(
+ // LINUX: call void @_ZTHN7PR192541nE(
+ // DARWIN: call cxx_fast_tlscc i32* @_ZTWN7PR192541nE(
return this->n;
}
@@ -153,7 +180,8 @@
void set_anon_i() {
anon_i = 2;
}
-// CHECK-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
+// LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
+// DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWN12_GLOBAL__N_16anon_iE()
// CHECK: define {{.*}} @[[V_M_INIT:.*]]()
// CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
@@ -173,28 +201,33 @@
// CHECK: define {{.*}}@__tls_init()
// CHECK: load i8, i8* @__tls_guard
// CHECK: %[[NEED_TLS_INIT:.*]] = icmp eq i8 %{{.*}}, 0
-// CHECK: store i8 1, i8* @__tls_guard
// CHECK: br i1 %[[NEED_TLS_INIT]],
// init:
+// CHECK: store i8 1, i8* @__tls_guard
// CHECK: call void @[[A_INIT]]()
// CHECK: call void @[[D_INIT]]()
// CHECK: call void @[[U_M_INIT]]()
// CHECK: call void @[[V_M_INIT]]()
-// CHECK: define weak_odr hidden i32* @_ZTW1a() {
+// LIUNX: define weak_odr hidden i32* @_ZTW1a() {
+// DARWIN: define cxx_fast_tlscc i32* @_ZTW1a()
// CHECK: call void @_ZTH1a()
// CHECK: ret i32* @a
// CHECK: }
-// CHECK: declare extern_weak void @_ZTH1b()
+// LINUX: declare extern_weak void @_ZTH1b() [[ATTR:#[0-9]+]]
-// CHECK-LABEL: define internal i32* @_ZTWL1d()
+// LINUX-LABEL: define internal i32* @_ZTWL1d()
+// DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWL1d()
// CHECK: call void @_ZTHL1d()
// CHECK: ret i32* @_ZL1d
-// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
+// LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
+// DARWIN-LABEL: define cxx_fast_tlscc i32* @_ZTWN1U1mE()
// CHECK: call void @_ZTHN1U1mE()
// CHECK: ret i32* @_ZN1U1mE
+
+// LINUX: attributes [[ATTR]] = { {{.+}} }
diff --git a/test/CodeGenCXX/debug-info-anon-namespace.cpp b/test/CodeGenCXX/debug-info-anon-namespace.cpp
new file mode 100644
index 0000000..4e3e08a
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-anon-namespace.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-scei-ps4 -O0 %s -o - | FileCheck --check-prefix=PS4 %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-unknown-linux-gnu -O0 %s -o - | FileCheck --check-prefix=NON-PS4 %s
+
+namespace
+{
+ int a = 5;
+}
+int *b = &a;
+
+namespace
+{
+ namespace {
+ int a1 = 5;
+ }
+ int a2 = 7;
+}
+int *b1 = &a1;
+int *b2 = &a2;
+
+
+// PS4: [[NS:![0-9]+]] = !DINamespace
+// PS4: [[NS2:![0-9]+]] = !DINamespace
+// PS4: !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0, entity: [[NS]])
+// PS4: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[NS]], entity: [[NS2]], line: {{[0-9]+}})
+// NON-PS4-NOT: !DIImportedEntity
+
diff --git a/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/test/CodeGenCXX/debug-info-anon-union-vars.cpp
index 3d3dff7..5b0370e 100644
--- a/test/CodeGenCXX/debug-info-anon-union-vars.cpp
+++ b/test/CodeGenCXX/debug-info-anon-union-vars.cpp
@@ -29,11 +29,28 @@
i = 8;
}
+// A funky reinterpret cast idiom that we used to crash on.
+template <class T>
+unsigned char *buildBytes(const T v) {
+ static union {
+ unsigned char result[sizeof(T)];
+ T value;
+ };
+ value = v;
+ return result;
+}
+
+void instantiate(int x) {
+ buildBytes(x);
+}
+
// CHECK: [[FILE:.*]] = !DIFile(filename: "{{.*}}debug-info-anon-union-vars.cpp",
// CHECK: !DIGlobalVariable(name: "c",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true
// CHECK: !DIGlobalVariable(name: "d",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true
// CHECK: !DIGlobalVariable(name: "a",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true
// CHECK: !DIGlobalVariable(name: "b",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true
+// CHECK: !DIGlobalVariable(name: "result", {{.*}} isLocal: false, isDefinition: true
+// CHECK: !DIGlobalVariable(name: "value", {{.*}} isLocal: false, isDefinition: true
// CHECK: !DILocalVariable(name: "i", {{.*}}, flags: DIFlagArtificial
// CHECK: !DILocalVariable(name: "c", {{.*}}, flags: DIFlagArtificial
// CHECK: !DILocalVariable(
diff --git a/test/CodeGenCXX/debug-info-codeview-display-name.cpp b/test/CodeGenCXX/debug-info-codeview-display-name.cpp
new file mode 100644
index 0000000..1d0300c
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-codeview-display-name.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s -o - -triple=x86_64-pc-win32 -std=c++98 | \
+// RUN: grep 'DISubprogram' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | FileCheck %s
+
+void freefunc() { }
+// CHECK-DAG: "freefunc"
+
+namespace N {
+ int b() { return 0; }
+// CHECK-DAG: "N::b"
+ namespace { void func() { } }
+// CHECK-DAG: "N::`anonymous namespace'::func
+}
+
+void _c(void) {
+ N::func();
+}
+// CHECK-DAG: "_c"
+
+struct foo {
+ int operator+(int);
+ foo(){}
+// CHECK-DAG: "foo::foo"
+
+ ~foo(){}
+// CHECK-DAG: "foo::~foo"
+
+ foo(int i){}
+// CHECK-DAG: "foo::foo"
+
+ foo(char *q){}
+// CHECK-DAG: "foo::foo"
+
+ static foo* static_method() { return 0; }
+// CHECK-DAG: "foo::static_method"
+
+};
+
+void use_foo() {
+ foo f1, f2(1), f3((char*)0);
+ foo::static_method();
+}
+
+// CHECK-DAG: "foo::operator+"
+int foo::operator+(int a) { return a; }
+
+// PR17371
+struct OverloadedNewDelete {
+ // __cdecl
+ void *operator new(__SIZE_TYPE__);
+ void *operator new[](__SIZE_TYPE__);
+ void operator delete(void *);
+ void operator delete[](void *);
+ // __thiscall
+ int operator+(int);
+};
+
+void *OverloadedNewDelete::operator new(__SIZE_TYPE__ s) { return 0; }
+void *OverloadedNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; }
+void OverloadedNewDelete::operator delete(void *) { }
+void OverloadedNewDelete::operator delete[](void *) { }
+int OverloadedNewDelete::operator+(int x) { return x; };
+
+// CHECK-DAG: "OverloadedNewDelete::operator new"
+// CHECK-DAG: "OverloadedNewDelete::operator new[]"
+// CHECK-DAG: "OverloadedNewDelete::operator delete"
+// CHECK-DAG: "OverloadedNewDelete::operator delete[]"
+// CHECK-DAG: "OverloadedNewDelete::operator+"
+
+template <void (*)(void)>
+void fn_tmpl() {}
+
+template void fn_tmpl<freefunc>();
+// CHECK-DAG: "fn_tmpl"
diff --git a/test/CodeGenCXX/debug-info-limited.cpp b/test/CodeGenCXX/debug-info-limited.cpp
index d56e5b6..b209e3a 100644
--- a/test/CodeGenCXX/debug-info-limited.cpp
+++ b/test/CodeGenCXX/debug-info-limited.cpp
@@ -14,8 +14,7 @@
}
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B"
-// CHECK-NOT: DIFlagFwdDecl
-// CHECK-SAME: ){{$}}
+// CHECK-SAME: flags: DIFlagFwdDecl
class B {
public:
diff --git a/test/CodeGenCXX/debug-info-rvalue-ref.cpp b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
index 621cff7..edb93ae 100644
--- a/test/CodeGenCXX/debug-info-rvalue-ref.cpp
+++ b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
@@ -8,5 +8,5 @@
printf("%d\n", i);
}
-// CHECK: !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: ![[INT:[0-9]+]])
+// CHECK: !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: ![[INT:[0-9]+]], size: 64, align: 64)
// CHECK: ![[INT]] = !DIBasicType(name: "int"
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
deleted file mode 100644
index af78004..0000000
--- a/test/CodeGenCXX/default-destructor-synthesis.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O2 -o - | FileCheck %s
-static int count = 0;
-
-struct S {
- S() { count++; }
- ~S() { count--; }
-};
-
-struct P {
- P() { count++; }
- ~P() { count--; }
-};
-
-struct Q {
- Q() { count++; }
- ~Q() { count--; }
-};
-
-struct M : Q, P {
- S s;
- Q q;
- P p;
- P p_arr[3];
- Q q_arr[2][3];
-};
-
-// CHECK: define i32 @_Z1fv() [[NUW:#[0-9]+]]
-int f() {
- {
- count = 1;
- M a;
- }
-
- // CHECK: ret i32 1
- return count;
-}
-
-// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/duplicate-mangled-name.cpp b/test/CodeGenCXX/duplicate-mangled-name.cpp
index 104bb6e..8c8f6e0 100644
--- a/test/CodeGenCXX/duplicate-mangled-name.cpp
+++ b/test/CodeGenCXX/duplicate-mangled-name.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -verify -DTEST1
-// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -verify -DTEST2
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -verify -DTEST2 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -verify -DTEST3
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -verify -DTEST4
#ifdef TEST1
@@ -14,28 +16,61 @@
#elif TEST2
-// We expect no warnings here, as there is only declaration of _ZN1TD1Ev function, no definitions.
+// expected-no-diagnostics
+
+// We expect no warnings here, as there is only declaration of _ZN1TD1Ev
+// function, no definitions.
extern "C" void _ZN1TD1Ev();
struct T {
~T() {}
};
-void foo() {
- _ZN1TD1Ev();
- T t;
+// We expect no warnings here, as there is only declaration of _ZN2nm3abcE
+// global, no definitions.
+extern "C" {
+ int _ZN2nm3abcE;
}
+namespace nm {
+ float abc = 2;
+}
+// CHECK: @_ZN2nm3abcE = global float
+
+float foo() {
+ _ZN1TD1Ev();
+// CHECK: call void bitcast ({{.*}} (%struct.T*)* @_ZN1TD1Ev to void ()*)()
+ T t;
+// CHECK: call {{.*}} @_ZN1TD1Ev(%struct.T* %t)
+ return _ZN2nm3abcE + nm::abc;
+}
+
+#elif TEST3
+
extern "C" void _ZN2T2D2Ev() {}; // expected-note {{previous definition is here}}
struct T2 {
~T2() {} // expected-error {{definition with same mangled name as another definition}}
};
-void bar() {
+void foo() {
_ZN2T2D2Ev();
T2 t;
}
+#elif TEST4
+
+extern "C" {
+ int _ZN2nm3abcE = 1; // expected-note {{previous definition is here}}
+}
+
+namespace nm {
+ float abc = 2; // expected-error {{definition with same mangled name as another definition}}
+}
+
+float foo() {
+ return _ZN2nm3abcE + nm::abc;
+}
+
#else
#error Unknwon test
diff --git a/test/CodeGenCXX/exceptions-cxx-new.cpp b/test/CodeGenCXX/exceptions-cxx-new.cpp
index 182bda1..3767f33 100644
--- a/test/CodeGenCXX/exceptions-cxx-new.cpp
+++ b/test/CodeGenCXX/exceptions-cxx-new.cpp
@@ -14,18 +14,15 @@
// CHECK-LABEL: define void @"\01?test_catch@@YAXXZ"(
// CHECK: invoke i32 @"\01?f@@YAHH@Z"(i32 1)
-// CHECK: to label %[[NORMAL:.*]] unwind label %[[CATCH_INT:.*]]
+// CHECK: to label %[[NORMAL:.*]] unwind label %[[CATCHSWITCH:.*]]
+
+// CHECK: [[CATCHSWITCH]]
+// CHECK: %[[CATCHSWITCHPAD:.*]] = catchswitch within none [label %[[CATCH_INT:.*]], label %[[CATCH_DOUBLE:.*]]] unwind to caller
// CHECK: [[CATCH_INT]]
-// CHECK: %[[CATCHPAD_INT:.*]] = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
-// CHECK: to label %[[CATCH_INT_HANDLER:.*]] unwind label %[[CATCH_DOUBLE:.*]]
-
-// CHECK: [[CATCH_INT_HANDLER]]
-// CHECK: invoke i32 @"\01?f@@YAHH@Z"(i32 2)
-// CHECK: to label %[[CATCH_INT_DONE:.*]] unwind label %[[CATCHENDPAD:.*]]
-
-// CHECK: [[CATCH_INT_DONE]]
-// CHECK: catchret %[[CATCHPAD_INT]] to label %[[LEAVE_INT_CATCH:.*]]
+// CHECK: %[[CATCHPAD_INT:.*]] = catchpad within %[[CATCHSWITCHPAD]] [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+// CHECK: call i32 @"\01?f@@YAHH@Z"(i32 2)
+// CHECK: catchret from %[[CATCHPAD_INT]] to label %[[LEAVE_INT_CATCH:.*]]
// CHECK: [[LEAVE_INT_CATCH]]
// CHECK: br label %[[LEAVE_FUNC:.*]]
@@ -34,22 +31,13 @@
// CHECK: ret void
// CHECK: [[CATCH_DOUBLE]]
-// CHECK: %[[CATCHPAD_DOUBLE:.*]] = catchpad [%rtti.TypeDescriptor2* @"\01??_R0N@8", i32 0, i8* null]
-// CHECK: to label %[[CATCH_DOUBLE_HANDLER:.*]] unwind label %[[CATCHENDPAD]]
-
-// CHECK: [[CATCH_DOUBLE_HANDLER]]
-// CHECK: invoke i32 @"\01?f@@YAHH@Z"(i32 3)
-// CHECK: to label %[[CATCH_DOUBLE_DONE:.*]] unwind label %[[CATCHENDPAD]]
-
-// CHECK: [[CATCH_DOUBLE_DONE]]
-// CHECK: catchret %[[CATCHPAD_DOUBLE]] to label %[[LEAVE_DOUBLE_CATCH:.*]]
+// CHECK: %[[CATCHPAD_DOUBLE:.*]] = catchpad within %[[CATCHSWITCHPAD]] [%rtti.TypeDescriptor2* @"\01??_R0N@8", i32 0, i8* null]
+// CHECK: call i32 @"\01?f@@YAHH@Z"(i32 3)
+// CHECK: catchret from %[[CATCHPAD_DOUBLE]] to label %[[LEAVE_DOUBLE_CATCH:.*]]
// CHECK: [[LEAVE_DOUBLE_CATCH]]
// CHECK: br label %[[LEAVE_FUNC]]
-// CHECK: [[CATCHENDPAD]]
-// CHECK: catchendpad unwind to caller
-
// CHECK: [[NORMAL]]
// CHECK: br label %[[LEAVE_FUNC]]
@@ -71,9 +59,9 @@
// CHECK: ret void
// CHECK: [[CLEANUP]]
-// CHECK: %[[CLEANUPPAD:.*]] = cleanuppad []
+// CHECK: %[[CLEANUPPAD:.*]] = cleanuppad within none []
// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"(
-// CHECK: cleanupret %[[CLEANUPPAD]] unwind to caller
+// CHECK: cleanupret from %[[CLEANUPPAD]] unwind to caller
// CHECK-LABEL: define {{.*}} void @"\01??1Cleanup@@QAE@XZ"(
@@ -84,5 +72,6 @@
// CHECK: ret void
// CHECK: [[TERMINATE]]
-// CHECK: terminatepad [void ()* @"\01?terminate@@YAXXZ"] unwind to caller
+// CHECK: cleanuppad within none []
+// CHECK-NEXT: call void @"\01?terminate@@YAXXZ"()
diff --git a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
index 26ef90f..ab75a87 100644
--- a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
+++ b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
@@ -21,9 +21,10 @@
// CHECK: invoke void @might_crash()
// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_freefunc@@"(i8* %exception_pointers, i8* %frame_pointer)
-// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 0)
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer)
+// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %[[fp]], i32 0)
// CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32*
-// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 1)
+// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %[[fp]], i32 1)
// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32*
// CHECK: %[[s1:[^ ]*]] = load i32, i32* @"\01?s1@?1??test_freefunc@@9@4HA", align 4
// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]]
@@ -50,7 +51,8 @@
// CHECK: invoke void @might_crash()
// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_method@S@@"(i8* %exception_pointers, i8* %frame_pointer)
-// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer, i32 0)
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer)
+// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %[[fp]], i32 0)
// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32*
// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]]
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]])
@@ -68,13 +70,14 @@
lambda();
}
-// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this)
+// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ"(%class.anon* %this)
// CHECK: @llvm.localescape(i32* %[[l2_addr:[^, ]*]])
// CHECK: store i32 42, i32* %[[l2_addr]], align 4
// CHECK: invoke void @might_crash()
-// CHECK-LABEL: define internal i32 @"\01?filt$0@0@?R<lambda_0>@?test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer)
-// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ" to i8*), i8* %frame_pointer, i32 0)
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@?R<lambda_0>@?0??test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer)
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %frame_pointer)
+// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 0)
// CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32*
// CHECK: %[[l2:[^ ]*]] = load i32, i32* %[[l2_ptr]]
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l2]])
diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp
index c6120b8..589bc22 100644
--- a/test/CodeGenCXX/exceptions-seh.cpp
+++ b/test/CodeGenCXX/exceptions-seh.cpp
@@ -61,7 +61,10 @@
// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[lpad]]
-// CHECK-NEXT: catchpad
+// CHECK-NEXT: %[[switch:.*]] = catchswitch within none [label %[[cpad:.*]]] unwind to caller
+//
+// CHECK: [[cpad]]
+// CHECK-NEXT: catchpad within %[[switch]]
// CHECK: catchret {{.*}} label %[[except:[^ ]*]]
//
// CHECK: [[except]]
@@ -92,7 +95,7 @@
// NOCXX-NOT: invoke
// NOCXX: ret void
-// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?use_seh_in_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this)
+// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?0??use_seh_in_lambda@@YAXXZ@QEBA@XZ"(%class.anon* %this)
// CXXEH-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
// CHECK: invoke void @might_throw() #[[NOINLINE]]
// CHECK: catchpad
@@ -119,7 +122,7 @@
// CHECK-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
// CHECK: invoke void @might_throw()
//
-// CHECK: catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_seh_in_inline_func@@" to i8*)]
+// CHECK: catchpad {{.*}} [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_seh_in_inline_func@@" to i8*)]
//
// CHECK: invoke void @might_throw()
//
@@ -129,7 +132,7 @@
//
// CHECK: cleanuppad
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
-// CHECK: invoke void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]])
+// CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]])
// CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
// CHECK: icmp eq i32 %{{.*}}, 424242
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index 2ea0561..f59d360 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -10,10 +10,27 @@
// CHECK: @cvar = global
extern "C" auto cvar = []{};
+// CHECK-LABEL: define i32 @_Z9ARBSizeOfi(i32
+int ARBSizeOf(int n) {
+ typedef double(T)[8][n];
+ using TT = double[8][n];
+ return [&]() -> int {
+ typedef double(T1)[8][n];
+ using TT1 = double[8][n];
+ return [&n]() -> int {
+ typedef double(T2)[8][n];
+ using TT2 = double[8][n];
+ return sizeof(T) + sizeof(T1) + sizeof(T2) + sizeof(TT) + sizeof(TT1) + sizeof(TT2);
+ }();
+ }();
+}
+
+// CHECK-LABEL: define internal i32 @"_ZZ9ARBSizeOfiENK3$_0clEv"
+
int a() { return []{ return 1; }(); }
// CHECK-LABEL: define i32 @_Z1av
-// CHECK: call i32 @"_ZZ1avENK3$_0clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_0clEv"
+// CHECK: call i32 @"_ZZ1avENK3$_1clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_1clEv"
// CHECK: ret i32 1
int b(int x) { return [x]{return x;}(); }
@@ -21,8 +38,8 @@
// CHECK: store i32
// CHECK: load i32, i32*
// CHECK: store i32
-// CHECK: call i32 @"_ZZ1biENK3$_1clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_1clEv"
+// CHECK: call i32 @"_ZZ1biENK3$_2clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_2clEv"
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -30,8 +47,8 @@
// CHECK-LABEL: define i32 @_Z1ci
// CHECK: store i32
// CHECK: store i32*
-// CHECK: call i32 @"_ZZ1ciENK3$_2clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_2clEv"
+// CHECK: call i32 @"_ZZ1ciENK3$_3clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_3clEv"
// CHECK: load i32*, i32**
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -43,8 +60,8 @@
// CHECK: call void @_ZN1DC1Ev
// CHECK: icmp ult i64 %{{.*}}, 10
// CHECK: call void @_ZN1DC1ERKS_
-// CHECK: call i32 @"_ZZ1diENK3$_3clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_3clEv"
+// CHECK: call i32 @"_ZZ1diENK3$_4clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_4clEv"
// CHECK: load i32, i32*
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -54,18 +71,18 @@
// CHECK-LABEL: define i32 @_Z1e1ES_b
// CHECK: call void @_ZN1EC1ERKS_
// CHECK: invoke void @_ZN1EC1ERKS_
-// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv"
-// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
-// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
+// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_5clEv"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev"
-// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_5clEv"
// CHECK: trunc i8
// CHECK: load i32, i32*
// CHECK: ret i32
void f() {
// CHECK-LABEL: define void @_Z1fv()
- // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv"
+ // CHECK: @"_ZZ1fvENK3$_6cvPFiiiEEv"
// CHECK-NEXT: store i32 (i32, i32)*
// CHECK-NEXT: ret void
int (*fp)(int, int) = [](int x, int y){ return x + y; };
@@ -74,7 +91,7 @@
static int k;
int g() {
int &r = k;
- // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_6clEv"(
+ // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_7clEv"(
// CHECK-NOT: }
// CHECK: load i32, i32* @_ZL1k,
return [] { return r; } ();
@@ -91,7 +108,7 @@
}();
}
-// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_8clEv"
+// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_9clEv"
// CHECK: ret i32* @PR22071_var
int PR22071_var;
int *PR22071_fun() {
@@ -99,19 +116,19 @@
return [&] { return &y; }();
}
-// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
+// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_5D2Ev"
-// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
+// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_68__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
// CHECK-NEXT: load i32, i32*
// CHECK-NEXT: load i32, i32*
-// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii"
+// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii"
// CHECK-NEXT: ret i32
-// CHECK-LABEL: define internal void @"_ZZ1hvEN3$_98__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
+// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_108__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
// CHECK-NOT: =
-// CHECK: call void @"_ZZ1hvENK3$_9clEv"(%struct.A* sret %agg.result,
+// CHECK: call void @"_ZZ1hvENK4$_10clEv"(%struct.A* sret %agg.result,
// CHECK-NEXT: ret void
struct A { ~A(); };
void h() {
diff --git a/test/CodeGenCXX/main-norecurse.cpp b/test/CodeGenCXX/main-norecurse.cpp
new file mode 100644
index 0000000..0f36402
--- /dev/null
+++ b/test/CodeGenCXX/main-norecurse.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define {{.*}} @main({{.*}}) #0
+int main(int argc, char **argv) {
+ return 1;
+}
+
+// CHECK: attributes #0 = { norecurse{{.*}} }
diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp
index 999def8..9938444 100644
--- a/test/CodeGenCXX/mangle-ms-cxx11.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp
@@ -166,14 +166,14 @@
static auto lambda = [] { static int local; ++local; return local; };
// First, we have the static local variable of type "<lambda_1>" inside of
// "define_lambda".
-// CHECK-DAG: @"\01?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@?1@YAHXZ@A"
+// CHECK-DAG: @"\01?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@?0??1@YAHXZ@A"
// Next, we have the "operator()" for "<lambda_1>" which is inside of
// "define_lambda".
-// CHECK-DAG: @"\01??R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ"
+// CHECK-DAG: @"\01??R<lambda_1>@?0??define_lambda@@YAHXZ@QBE@XZ"
// Finally, we have the local which is inside of "<lambda_1>" which is inside of
// "define_lambda". Hooray.
-// MSVC2013-DAG: @"\01?local@?2???R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ@4HA"
-// MSVC2015-DAG: @"\01?local@?1???R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ@4HA"
+// MSVC2013-DAG: @"\01?local@?2???R<lambda_1>@?0??define_lambda@@YAHXZ@QBE@XZ@4HA"
+// MSVC2015-DAG: @"\01?local@?1???R<lambda_1>@?0??define_lambda@@YAHXZ@QBE@XZ@4HA"
return lambda();
}
@@ -182,12 +182,12 @@
inline void call_with_lambda_arg1() {
use_lambda_arg([]{});
- // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?call_with_lambda_arg1@@YAXXZ@@@YAXV<lambda_1>@?call_with_lambda_arg1@@YAXXZ@@Z"
+ // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?0??call_with_lambda_arg1@@YAXXZ@@@YAXV<lambda_1>@?0??call_with_lambda_arg1@@YAXXZ@@Z"
}
inline void call_with_lambda_arg2() {
use_lambda_arg([]{});
- // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?call_with_lambda_arg2@@YAXXZ@@@YAXV<lambda_1>@?call_with_lambda_arg2@@YAXXZ@@Z"
+ // CHECK-DAG: @"\01??$use_lambda_arg@V<lambda_1>@?0??call_with_lambda_arg2@@YAXXZ@@@YAXV<lambda_1>@?0??call_with_lambda_arg2@@YAXXZ@@Z"
}
int call_lambda() {
@@ -286,3 +286,10 @@
};
// CHECK-DAG: @"\01??$f@T<unnamed-type-$S1>@PR18204@@@PR18204@@YAHPAT<unnamed-type-$S1>@0@@Z"
}
+
+int PR26105() {
+ auto add = [](int x) { return ([x](int y) { return x + y; }); };
+ return add(3)(4);
+}
+// CHECK-DAG: @"\01??R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z"
+// CHECK-DAG: @"\01??R<lambda_1>@?0???R<lambda_0>@?0??PR26105@@YAHXZ@QBE@H@Z@QBE@H@Z"
diff --git a/test/CodeGenCXX/mangle-ms-cxx14.cpp b/test/CodeGenCXX/mangle-ms-cxx14.cpp
index 51627dd..084eb7d 100644
--- a/test/CodeGenCXX/mangle-ms-cxx14.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx14.cpp
@@ -3,27 +3,27 @@
template <typename> int x = 0;
-// CHECK: "\01??$x@X@@3HA"
+// CHECK-DAG: "\01??$x@X@@3HA"
template <> int x<void>;
-// CHECK: "\01??$x@H@@3HA"
+// CHECK-DAG: "\01??$x@H@@3HA"
template <> int x<int>;
-// CHECK: "\01?FunctionWithLocalType@@YA?A?<auto>@@XZ"
+// CHECK-DAG: "\01?FunctionWithLocalType@@YA?A?<auto>@@XZ"
auto FunctionWithLocalType() {
struct LocalType {};
return LocalType{};
}
-// CHECK: "\01?ValueFromFunctionWithLocalType@@3ULocalType@?1??FunctionWithLocalType@@YA?A?<auto>@@XZ@A"
+// CHECK-DAG: "\01?ValueFromFunctionWithLocalType@@3ULocalType@?1??FunctionWithLocalType@@YA?A?<auto>@@XZ@A"
auto ValueFromFunctionWithLocalType = FunctionWithLocalType();
-// CHECK: "\01??R<lambda_0>@@QBE?A?<auto>@@XZ"
+// CHECK-DAG: "\01??R<lambda_0>@@QBE?A?<auto>@@XZ"
auto LambdaWithLocalType = [] {
struct LocalType {};
return LocalType{};
};
-// CHECK: "\01?ValueFromLambdaWithLocalType@@3ULocalType@?1???R<lambda_0>@@QBE?A?<auto>@@XZ@A"
+// CHECK-DAG: "\01?ValueFromLambdaWithLocalType@@3ULocalType@?1???R<lambda_0>@@QBE?A?<auto>@@XZ@A"
auto ValueFromLambdaWithLocalType = LambdaWithLocalType();
template <typename T>
@@ -35,10 +35,23 @@
return LocalLambdaWithLocalType();
}
-// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
-// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
-// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
-// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
-// CHECK: "\01??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z"
-// CHECK: "\01??R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?1@XZ"
+// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// CHECK-DAG: "\01??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z"
+// CHECK-DAG: "\01??R<lambda_1>@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?1@XZ"
auto ValueFromTemplateFuncionWithLocalLambda = TemplateFuncionWithLocalLambda(0);
+
+struct S;
+template <int S::*>
+int WithPMD = 0;
+
+template <> int WithPMD<nullptr>;
+// CHECK-DAG: "\01??$WithPMD@$GA@A@?0@@3HA"
+
+template <const int *, const int *>
+struct Foo {};
+
+Foo<&x<int>, &x<int>> Zoo;
+// CHECK-DAG: "\01?Zoo@@3U?$Foo@$1??$x@H@@3HA$1?1@3HA@@A"
diff --git a/test/CodeGenCXX/mangle-ms-vector-types.cpp b/test/CodeGenCXX/mangle-ms-vector-types.cpp
index 5aca455..53a1a43 100644
--- a/test/CodeGenCXX/mangle-ms-vector-types.cpp
+++ b/test/CodeGenCXX/mangle-ms-vector-types.cpp
@@ -27,11 +27,11 @@
// We have a custom mangling for vector types not standardized by Intel.
void foov8hi(__v8hi) {}
-// CHECK: define void @"\01?foov8hi@@YAXT__clang_vec8_F@@@Z"
+// CHECK: define void @"\01?foov8hi@@YAXT?$__vector@F$07@__clang@@@Z"
typedef __attribute__((ext_vector_type(4))) int vi4b;
void foovi4b(vi4b) {}
-// CHECK: define void @"\01?foovi4b@@YAXT__clang_vec4_H@@@Z"
+// CHECK: define void @"\01?foovi4b@@YAXT?$__vector@H$03@__clang@@@Z"
// Clang does not support vectors of complex types, so we can't test the
// mangling of them.
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index 54855ec..c82fca4 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -21,6 +21,10 @@
// CHECK-DAG: @"\01?_c@@YAHXZ"
// X64-DAG: @"\01?_c@@YAHXZ"
+const int &NeedsReferenceTemporary = 2;
+// CHECK-DAG: @"\01?NeedsReferenceTemporary@@3ABHB" = constant i32* @"\01?$RT1@NeedsReferenceTemporary@@3ABHB"
+// X64-DAG: @"\01?NeedsReferenceTemporary@@3AEBHEB" = constant i32* @"\01?$RT1@NeedsReferenceTemporary@@3AEBHEB"
+
class foo {
static const short d;
// CHECK-DAG: @"\01?d@foo@@0FB"
@@ -418,3 +422,60 @@
// X64-DAG: @"\01?f@UnnamedType@@YAXUT5@S@1@@Z"
// X64-DAG: @"\01?f@UnnamedType@@YAXPEAU<unnamed-type-T6>@S@1@@Z"
}
+
+namespace PassObjectSize {
+// NOTE: This mangling is subject to change.
+// Reiterating from the comment in MicrosoftMangle, the scheme is pretend a
+// parameter of type __clang::__pass_object_sizeN exists after each pass object
+// size param P, where N is the Type of the pass_object_size attribute on P.
+//
+// e.g. we want to mangle:
+// void foo(void *const __attribute__((pass_object_size(0))));
+// as if it were
+// namespace __clang { enum __pass_object_size0 : size_t {}; }
+// void foo(void *const, __clang::__pass_object_size0);
+// where __clang is a top-level namespace.
+
+// CHECK-DAG: define i32 @"\01?foo@PassObjectSize@@YAHQAHW4__pass_object_size0@__clang@@@Z"
+int foo(int *const i __attribute__((pass_object_size(0)))) { return 0; }
+// CHECK-DAG: define i32 @"\01?bar@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@@Z"
+int bar(int *const i __attribute__((pass_object_size(1)))) { return 0; }
+// CHECK-DAG: define i32 @"\01?qux@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@0W4__pass_object_size0@3@@Z"
+int qux(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(0)))) { return 0; }
+// CHECK-DAG: define i32 @"\01?zot@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@01@Z"
+int zot(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(1)))) { return 0; }
+}
+
+namespace Atomic {
+// CHECK-DAG: define void @"\01?f@Atomic@@YAXU?$_Atomic@H@__clang@@@Z"(
+void f(_Atomic(int)) {}
+}
+namespace Complex {
+// CHECK-DAG: define void @"\01?f@Complex@@YAXU?$_Complex@H@__clang@@@Z"(
+void f(_Complex int) {}
+}
+
+namespace PR26029 {
+template <class>
+struct L {
+ L() {}
+};
+template <class>
+class H;
+struct M : L<H<int *> > {};
+
+template <class>
+struct H {};
+
+template <class GT>
+void m_fn3() {
+ (H<GT *>());
+ M();
+}
+
+void runOnFunction() {
+ L<H<int *> > b;
+ m_fn3<int>();
+}
+// CHECK-DAG: call {{.*}} @"\01??0?$L@V?$H@PAH@PR26029@@@PR26029@@QAE@XZ"
+}
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
deleted file mode 100644
index c98e6bf..0000000
--- a/test/CodeGenCXX/member-initializers.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck %s
-
-struct A {
- virtual int f() { return 1; }
-};
-
-struct B : A {
- B() : i(f()) { }
-
- virtual int f() { return 2; }
-
- int i;
-};
-
-// CHECK-LABEL: define i32 @_Z1fv() #0
-int f() {
- B b;
-
- // CHECK: ret i32 2
- return b.i;
-}
-
-// Test that we don't try to fold the default value of j when initializing i.
-// CHECK: define i32 @_Z9test_foldv() [[NUW_RN:#[0-9]+]]
-int test_fold() {
- struct A {
- A(const int j = 1) : i(j) { }
- int i;
- };
-
- // CHECK: ret i32 2
- return A(2).i;
-}
-
-// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/microsoft-abi-arg-order.cpp b/test/CodeGenCXX/microsoft-abi-arg-order.cpp
index e13ed5a..68c141f 100644
--- a/test/CodeGenCXX/microsoft-abi-arg-order.cpp
+++ b/test/CodeGenCXX/microsoft-abi-arg-order.cpp
@@ -52,7 +52,7 @@
// X86: ret void
//
// lpad2:
-// X86: cleanuppad []
+// X86: cleanuppad within none []
// X86: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg2]])
// X86: cleanupret
//
@@ -68,7 +68,7 @@
// X64: ret void
//
// lpad2:
-// X64: cleanuppad []
+// X64: cleanuppad within none []
// X64: call void @"\01??1A@@QEAA@XZ"(%struct.A* %[[arg2]])
// X64: cleanupret
//
diff --git a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
index 49ba950..e9eba6e 100644
--- a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
+++ b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O1 -o - -fexceptions -triple=i386-pc-win32 %s | FileCheck %s
struct S { char a; };
struct V { virtual void f(); };
@@ -122,3 +122,22 @@
// CHECK: [[RET:%.*]] = phi i8*
// CHECK-NEXT: ret i8* [[RET]]
+namespace PR25606 {
+struct Cleanup {
+ ~Cleanup();
+};
+struct S1 { virtual ~S1(); };
+struct S2 : virtual S1 {};
+struct S3 : S2 {};
+
+S3 *f(S2 &s) {
+ Cleanup c;
+ return dynamic_cast<S3 *>(&s);
+}
+// CHECK-LABEL: define %"struct.PR25606::S3"* @"\01?f@PR25606@@YAPAUS3@1@AAUS2@1@@Z"(
+// CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast
+
+// CHECK: [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"*
+// CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAE@XZ"(
+// CHECK: ret %"struct.PR25606::S3"* [[BC]]
+}
diff --git a/test/CodeGenCXX/microsoft-abi-eh-catch.cpp b/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
index e742f8b..69ec347 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
@@ -19,15 +19,15 @@
// WIN64-LABEL: define void @catch_all()
// WIN64: invoke void @might_throw()
-// WIN64-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+// WIN64-NEXT: to label %[[cont:[^ ]*]] unwind label %[[catchswitch_lpad:[^ ]*]]
//
-// WIN64: [[lpad]]
-// WIN64: catchpad [i8* null, i32 64, i8* null]
-// WIN64: to label %[[catchit:[^ ]*]] unwind label %{{.*}}
+// WIN64: [[catchswitch_lpad]]
+// WIN64: %[[catchswitch:[^ ]*]] = catchswitch within none [label %[[catchpad_lpad:[^ ]*]]] unwind to caller
//
-// WIN64: [[catchit]]
+// WIN64: [[catchpad_lpad]]
+// WIN64: catchpad within %[[catchswitch]] [i8* null, i32 64, i8* null]
// WIN64: call void @recover()
-// WIN64: catchret %{{.*}} to label %[[catchret:[^ ]*]]
+// WIN64: catchret from %{{.*}} to label %[[catchret:[^ ]*]]
//
// WIN64: [[catchret]]
// WIN64-NEXT: br label %[[ret:[^ ]*]]
@@ -47,7 +47,7 @@
}
// WIN64-LABEL: define void @catch_int()
-// WIN64: catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %[[e_addr:[^\]]*]]]
+// WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %[[e_addr:[^\]]*]]]
//
// The catchpad instruction starts the lifetime of 'e'. Unfortunately, that
// leaves us with nowhere to put lifetime.start, so we don't emit lifetime
@@ -69,7 +69,7 @@
}
// WIN64-LABEL: define void @catch_int_unnamed()
-// WIN64: catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+// WIN64: catchpad within %{{.*}} [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
// WIN64: catchret
struct A {
@@ -96,7 +96,7 @@
// WIN64-LABEL: define void @catch_a_byval()
// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A
-// WIN64: catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, %struct.A* %[[e_addr]]]
+// WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, %struct.A* %[[e_addr]]]
// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8*
// WIN64: call void @handle_exception(i8* %[[e_i8]])
// WIN64: catchret
@@ -111,7 +111,7 @@
// WIN64-LABEL: define void @catch_a_ref()
// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A*
-// WIN64: catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 8, %struct.A** %[[e_addr]]]
+// WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 8, %struct.A** %[[e_addr]]]
// WIN64: %[[eptr:[^ ]*]] = load %struct.A*, %struct.A** %[[e_addr]]
// WIN64: %[[eptr_i8:[^ ]*]] = bitcast %struct.A* %[[eptr]] to i8*
// WIN64: call void @handle_exception(i8* %[[eptr_i8]])
@@ -139,25 +139,22 @@
// WIN64-LABEL: define void @catch_nested()
// WIN64: invoke void @might_throw()
-// WIN64-NEXT: to label %{{.*}} unwind label %[[lp1:[^ ]*]]
+// WIN64-NEXT: to label %{{.*}} unwind label %[[catchswitch_outer:[^ ]*]]
//
-// WIN64: [[lp1]]
-// WIN64: catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
-// WIN64: to label %[[catchit:[^ ]*]] unwind label %{{.*}}
+// WIN64: [[catchswitch_outer]]
+// WIN64: %[[catchswitch_outer_scope:[^ ]*]] = catchswitch within none [label %[[catch_int_outer:[^ ]*]]] unwind to caller
//
-// WIN64: [[catchit]]
+// WIN64: [[catch_int_outer]]
+// WIN64: %[[catchpad:[^ ]*]] = catchpad within %[[catchswitch_outer_scope]] [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
// WIN64: invoke void @might_throw()
-// WIN64-NEXT: to label %[[cont2:[^ ]*]] unwind label %[[lp2:[^ ]*]]
+// WIN64-NEXT: to label %[[cont2:[^ ]*]] unwind label %[[catchswitch_inner:[^ ]*]]
//
-// WIN64: [[lp2]]
-// WIN64: catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
-// WIN64: to label %[[catchit2:[^ ]*]] unwind label %[[endcatch2:[^ ]*]]
+// WIN64: [[catchswitch_inner]]
+// WIN64: %[[catchswitch_inner_scope:[^ ]*]] = catchswitch within %[[catchpad]] [label %[[catch_int_inner:[^ ]*]]] unwind to caller
//
-// WIN64: [[catchit2]]
-// WIN64-NEXT: invoke void @might_throw()
-// WIN64-NEXT: to label %[[catchret1:[^ ]*]] unwind label %[[endcatch2]]
-//
-// WIN64: [[catchret1]]
+// WIN64: [[catch_int_inner]]
+// WIN64: catchpad within %[[catchswitch_inner_scope]] [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+// WIN64-NEXT: call void @might_throw()
// WIN64: catchret {{.*}} to label %[[catchret2:[^ ]*]]
//
// WIN64: [[catchret2]]
@@ -165,6 +162,3 @@
//
// WIN64: [[mainret]]
// WIN64: ret void
-//
-// WIN64: [[endcatch2]]
-// WIN64: catchendpad unwind label %{{.*}}
diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
index c4a0d1c..bf05c69 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
@@ -27,7 +27,7 @@
//
// There should be one dtor call for unwinding from the second getA.
// WIN32: cleanuppad
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) #[[noinline:[0-9]+]]
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
// WIN32-NOT: @"\01??1A@@QAE@XZ"
// WIN32: }
@@ -62,7 +62,7 @@
// Conditionally destroy arg1.
// WIN32: %[[cond:.*]] = load i1, i1* %[[isactive]]
// WIN32: br i1 %[[cond]]
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) #[[noinline]]
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
// WIN32: }
// Test putting the cleanups inside a conditional.
@@ -85,7 +85,7 @@
// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()
//
// Only one dtor in the invoke for arg1
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) #[[noinline]]
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
// WIN32: }
@@ -126,7 +126,7 @@
// Somewhere in the landing pad soup, we conditionally destroy arg1.
// WIN32: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
// WIN32: br i1 %[[isactive]]
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) #[[noinline]]
+// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
// WIN32: }
namespace crash_on_partial_destroy {
@@ -164,7 +164,7 @@
// WIN32: getelementptr inbounds i8, i8* %{{.*}}, i32 4
// WIN32-NOT: load
// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*
-// WIN32: call x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"({{.*}}) #[[noinline]]
+// WIN32: call x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"({{.*}})
// WIN32: }
}
@@ -187,7 +187,7 @@
//
// WIN32: [[lpad]]
// WIN32-NEXT: cleanuppad
-// WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}}) #[[noinline]]
+// WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
}
namespace noexcept_false_dtor {
@@ -204,9 +204,5 @@
// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
// WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
// WIN32: cleanuppad
-// WIN32: invoke x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}}) #[[invoke_noinline:[0-9]+]]
+// WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
// WIN32: cleanupret
-// WIN32: cleanupendpad
-
-// WIN32: attributes #[[noinline]] = { noinline nounwind }
-// WIN32: attributes #[[invoke_noinline]] = { noinline }
diff --git a/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp b/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp
index 6d462bf..0b8d270 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-terminate.cpp
@@ -9,6 +9,7 @@
// CHECK-LABEL: define void @"\01?never_throws@@YAXXZ"()
// CHECK-SAME: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
// CHECK: invoke void @"\01?may_throw@@YAXXZ"()
-// MSVC2013: terminatepad [void ()* @"\01?terminate@@YAXXZ"]
-// MSVC2015: terminatepad [void ()* @__std_terminate]
+// CHECK: cleanuppad within none []
+// MSVC2013: call void @"\01?terminate@@YAXXZ"()
+// MSVC2015: call void @__std_terminate()
// CHECK-NEXT: unreachable
diff --git a/test/CodeGenCXX/microsoft-abi-structors-alias.cpp b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp
index 6007e5a..08df374 100644
--- a/test/CodeGenCXX/microsoft-abi-structors-alias.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp
@@ -24,3 +24,19 @@
}
// CHECK-DAG: @"\01??1B@test2@@UAE@XZ" = alias void (%"struct.test2::B"*), bitcast (void (%"struct.test2::A"*)* @"\01??1A@test2@@UAE@XZ" to void (%"struct.test2::B"*)*)
}
+
+namespace test3 {
+struct A { virtual ~A(); };
+A::~A() {}
+}
+// CHECK-DAG: define x86_thiscallcc void @"\01??1A@test3@@UAE@XZ"(
+namespace test3 {
+template <typename T>
+struct B : A {
+ virtual ~B() { }
+};
+template struct B<int>;
+}
+// This has to be weak, and emitting weak aliases is fragile, so we don't do the
+// aliasing.
+// CHECK-DAG: define weak_odr x86_thiscallcc void @"\01??1?$B@H@test3@@UAE@XZ"(
diff --git a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
index dadc656..29b434e 100644
--- a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
+++ b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
@@ -39,7 +39,7 @@
// CHECK-NEXT: ret %struct.S* @"\01?s@?1??f@@YAAAUS@@XZ@4U2@A"
// CHECK: [[lpad:.*]]:
-// CHECK-NEXT: cleanuppad []
+// CHECK-NEXT: cleanuppad within none []
// CHECK: %[[guard:.*]] = load i32, i32* @"\01??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT: %[[mask:.*]] = and i32 %[[guard]], -2
// CHECK-NEXT: store i32 %[[mask]], i32* @"\01??__J?1??f@@YAAAUS@@XZ@51"
@@ -75,7 +75,7 @@
// CHECK-NEXT: ret %struct.S* @"\01?s@?1??g@@YAAAUS@@XZ@4U2@A"
//
// CHECK: [[lpad]]:
-// CHECK-NEXT: cleanuppad []
+// CHECK-NEXT: cleanuppad within none []
// CHECK: call void @_Init_thread_abort(i32* @"\01?$TSS0@?1??g@@YAAAUS@@XZ")
// CHECK-NEXT: cleanupret {{.*}} unwind to caller
return s;
diff --git a/test/CodeGenCXX/microsoft-abi-try-throw.cpp b/test/CodeGenCXX/microsoft-abi-try-throw.cpp
index b87d9e1..6b1d2bf 100644
--- a/test/CodeGenCXX/microsoft-abi-try-throw.cpp
+++ b/test/CodeGenCXX/microsoft-abi-try-throw.cpp
@@ -19,7 +19,7 @@
external(); // TRY: invoke void @"\01?external@@YAXXZ"
} catch (int) {
rv = 1;
- // TRY: catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ // TRY: catchpad within {{.*}} [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
// TRY: catchret
}
#endif
@@ -39,7 +39,7 @@
external();
} catch (const int *) {
}
- // TRY: catchpad [%rtti.TypeDescriptor4* @"\01??_R0PAH@8", i32 1, i8* null]
+ // TRY: catchpad within {{.*}} [%rtti.TypeDescriptor4* @"\01??_R0PAH@8", i32 1, i8* null]
// TRY: catchret
}
#endif
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
index baed351..aa39d6d 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -299,3 +299,18 @@
};
S::S() {}
+
+struct T {
+ struct U {};
+};
+struct V : T {
+ // CHECK-LABEL: VFTable for 'V' (2 entries).
+ // CHECK-NEXT: 0 | void V::U()
+ // CHECK-NEXT: 1 | void V::f()
+ using T::U;
+ virtual void f();
+ virtual void U();
+ V();
+};
+
+V::V() {}
diff --git a/test/CodeGenCXX/ms-inline-asm-fields.cpp b/test/CodeGenCXX/ms-inline-asm-fields.cpp
index a78d511..6f32933 100644
--- a/test/CodeGenCXX/ms-inline-asm-fields.cpp
+++ b/test/CodeGenCXX/ms-inline-asm-fields.cpp
@@ -29,3 +29,28 @@
__asm mov eax, asdf::a_global.a3.b2
}
+template <bool Signed>
+struct make_storage_type {
+ struct type {
+ struct B {
+ int a;
+ int x;
+ } b;
+ };
+};
+
+template <bool Signed>
+struct msvc_dcas_x86 {
+ typedef typename make_storage_type<Signed>::type storage_type;
+ void store() __asm("PR26001") {
+ storage_type p;
+ __asm mov edx, p.b.x;
+ }
+};
+
+template void msvc_dcas_x86<false>::store();
+// CHECK: define weak_odr void @"\01PR26001"(
+// CHECK: %[[P:.*]] = alloca %"struct.make_storage_type<false>::type", align 4
+// CHECK: %[[B:.*]] = getelementptr inbounds %"struct.make_storage_type<false>::type", %"struct.make_storage_type<false>::type"* %[[P]], i32 0, i32 0
+// CHECK: %[[X:.*]] = getelementptr inbounds %"struct.make_storage_type<false>::type::B", %"struct.make_storage_type<false>::type::B"* %[[B]], i32 0, i32 1
+// CHECK: call void asm sideeffect inteldialect "mov edx, dword ptr $0", "*m,~{edx},~{dirflag},~{fpsr},~{flags}"(i32* %[[X]])
diff --git a/test/CodeGenCXX/ms-property.cpp b/test/CodeGenCXX/ms-property.cpp
index afeb5f0..49e957b 100644
--- a/test/CodeGenCXX/ms-property.cpp
+++ b/test/CodeGenCXX/ms-property.cpp
@@ -1,8 +1,15 @@
// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
class Test1 {
private:
int x_;
+ double y_;
public:
Test1(int x) : x_(x) {}
@@ -11,9 +18,96 @@
static Test1 *GetTest1() { return new Test1(10); }
};
+class S {
+public:
+ __declspec(property(get=GetX,put=PutX)) int x[];
+ int GetX(int i, int j) { return i+j; }
+ void PutX(int i, int j, int k) { j = i = k; }
+};
+
+template <typename T>
+class St {
+public:
+ __declspec(property(get=GetX,put=PutX)) T x[];
+ T GetX(T i, T j) { return i+j; }
+ T GetX() { return 0; }
+ T PutX(T i, T j, T k) { return j = i = k; }
+ __declspec(property(get=GetY,put=PutY)) T y[];
+ char GetY(char i, Test1 j) { return i+j.get_x(); }
+ void PutY(char i, int j, double k) { j = i = k; }
+};
+
+template <typename T>
+void foo(T i, T j) {
+ St<T> bar;
+ Test1 t(i);
+ bar.x[i][j] = bar.x[i][j];
+ bar.y[t.X][j] = bar.x[i][j];
+ bar.x[i][j] = bar.y[bar.x[i][j]][t];
+}
+
+int idx() { return 7; }
+
// CHECK-LABEL: main
int main(int argc, char **argv) {
+ Test1 t(argc);
+ S *p1 = 0;
+ St<float> *p2 = 0;
+ // CHECK: call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* %{{.+}}, i32 223, i32 11)
+ int j = p1->x[223][11];
+ // CHECK: [[J:%.+]] = load i32, i32* %
+ // CHECK-NEXT: call void @"\01?PutX@S@@QEAAXHHH@Z"(%class.S* %{{.+}}, i32 23, i32 1, i32 [[J]])
+ p1->x[23][1] = j;
+ // CHECK: call float @"\01?GetX@?$St@M@@QEAAMMM@Z"(%class.St* %{{.+}}, float 2.230000e+02, float 1.100000e+01)
+ float j1 = p2->x[223][11];
+ // CHECK: [[J1:%.+]] = load float, float* %
+ // CHECK-NEXT: [[CALL:%.+]] = call float @"\01?PutX@?$St@M@@QEAAMMMM@Z"(%class.St* %{{.+}}, float 2.300000e+01, float 1.000000e+00, float [[J1]])
+ // CHECK-NEXT: [[CONV:%.+]] = fptosi float [[CALL]] to i32
+ // CHECK-NEXT: store i32 [[CONV]], i32*
+ argc = p2->x[23][1] = j1;
+ // CHECK: [[IDX:%.+]] = call i32 @"\01?idx@@YAHXZ"()
+ // CHECK-NEXT: [[CONV:%.+]] = sitofp i32 [[IDX]] to float
+ // CHECK-NEXT: [[GET:%.+]] = call float @"\01?GetX@?$St@M@@QEAAMMM@Z"(%class.St* %{{.+}}, float [[CONV]], float 1.000000e+00)
+ // CHECK-NEXT: [[INC:%.+]] = fadd float [[GET]], 1.000000e+00
+ // CHECK-NEXT: [[CONV:%.+]] = sitofp i32 [[IDX]] to float
+ // CHECK-NEXT: call float @"\01?PutX@?$St@M@@QEAAMMMM@Z"(%class.St* %{{.+}}, float [[CONV]], float 1.000000e+00, float [[INC]])
+ ++p2->x[idx()][1];
+ // CHECK: call void @"\01??$foo@H@@YAXHH@Z"(i32 %{{.+}}, i32 %{{.+}})
+ foo(argc, (int)argv[0][0]);
+ // CHECK: [[P2:%.+]] = load %class.St*, %class.St** %
+ // CHECK: [[T_X:%.+]] = call i32 @"\01?get_x@Test1@@QEBAHXZ"(%class.Test1* %{{.+}})
+ // CHECK: [[P1:%.+]] = load %class.S*, %class.S** %
+ // CHECK: [[P1_X_22_33:%.+]] = call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* [[P1]], i32 22, i32 33)
+ // CHECK: [[CAST:%.+]] = sitofp i32 [[P1_X_22_33]] to double
+ // CHECK: [[ARGC:%.+]] = load i32, i32* %
+ // CHECK: [[CAST2:%.+]] = trunc i32 [[T_X]] to i8
+ // CHECK: call void @"\01?PutY@?$St@M@@QEAAXDHN@Z"(%class.St* [[P2]], i8 [[CAST2]], i32 [[ARGC]], double [[CAST]])
+ p2->y[t.X][argc] = p1->x[22][33];
+ // CHECK: [[P2_1:%.+]] = load %class.St*, %class.St**
+ // CHECK: [[P2_2:%.+]] = load %class.St*, %class.St**
+ // CHECK: [[P1:%.+]] = load %class.S*, %class.S**
+ // CHECK: [[ARGC:%.+]] = load i32, i32* %
+ // CHECK: [[P1_X_ARGC_0:%.+]] = call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* [[P1]], i32 [[ARGC]], i32 0)
+ // CHECK: [[CAST:%.+]] = trunc i32 [[P1_X_ARGC_0]] to i8
+ // CHECK: [[P2_Y_p1_X_ARGC_0_T:%.+]] = call i8 @"\01?GetY@?$St@M@@QEAADDVTest1@@@Z"(%class.St* [[P2_2]], i8 [[CAST]], %class.Test1* %{{.+}})
+ // CHECK: [[CAST:%.+]] = sitofp i8 [[P2_Y_p1_X_ARGC_0_T]] to float
+ // CHECK: [[J:%.+]] = load i32, i32* %
+ // CHECK: [[CAST1:%.+]] = sitofp i32 [[J]] to float
+ // CHECK: [[J:%.+]] = load i32, i32* %
+ // CHECK: [[CAST2:%.+]] = sitofp i32 [[J]] to float
+ // CHECK: call float @"\01?PutX@?$St@M@@QEAAMMMM@Z"(%class.St* [[P2_1]], float [[CAST2]], float [[CAST1]], float [[CAST]])
+ p2->x[j][j] = p2->y[p1->x[argc][0]][t];
// CHECK: [[CALL:%.+]] = call %class.Test1* @"\01?GetTest1@Test1@@SAPEAV1@XZ"()
// CHECK-NEXT: call i32 @"\01?get_x@Test1@@QEBAHXZ"(%class.Test1* [[CALL]])
return Test1::GetTest1()->X;
}
+
+// CHECK: define linkonce_odr void @"\01??$foo@H@@YAXHH@Z"(i32 %{{.+}}, i32 %{{.+}})
+// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR:%.+]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call i32 @"\01?PutX@?$St@H@@QEAAHHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}})
+// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call void @"\01?PutY@?$St@H@@QEAAXDHN@Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, i32 %{{.+}}, double %{{.+}}
+// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call i8 @"\01?GetY@?$St@H@@QEAADDVTest1@@@Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, %class.Test1* %{{.+}})
+// CHECK: call i32 @"\01?PutX@?$St@H@@QEAAHHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}})
+#endif //HEADER
diff --git a/test/CodeGenCXX/observe-noexcept.cpp b/test/CodeGenCXX/observe-noexcept.cpp
new file mode 100644
index 0000000..76046a6
--- /dev/null
+++ b/test/CodeGenCXX/observe-noexcept.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -std=c++11 -fopenmp -fexceptions -fcxx-exceptions -O0 -emit-llvm %s -o - | FileCheck %s
+
+// Check that regions that install a terminate scope in the exception stack can
+// correctly generate complex arithmetic.
+
+// CHECK-LABEL: ffcomplex
+void ffcomplex (int a) {
+ double _Complex dc = (double)a;
+
+ // CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}})
+ dc *= dc;
+ // CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME1:@.*]] to void (i32*, i32*, ...)*), { double, double }* %{{.+}})
+ #pragma omp parallel
+ {
+ dc *= dc;
+ }
+ // CHECK: ret void
+}
+
+// CHECK: define internal {{.+}}[[REGNAME1]](
+// CHECK-NOT: invoke
+// CHECK: call { double, double } @__muldc3(double %{{.+}}, double %{{.+}}, double %{{.+}}, double %{{.+}})
+// CHECK-NOT: invoke
+// CHECK: ret void
+
+// Check if we are observing the function pointer attribute regardless what is
+// in the exception specification of the callees.
+void fnoexcp(void) noexcept;
+
+// CHECK-LABEL: foo
+void foo(int a, int b) {
+
+ void (*fptr)(void) noexcept = fnoexcp;
+
+ // CHECK: call {{.+}} @__kmpc_fork_call({{.+}} [[REGNAME2:@.*]] to void (i32*, i32*, ...)*), void ()** %{{.+}})
+ #pragma omp parallel
+ {
+ fptr();
+ }
+ // CHECK: ret void
+}
+
+// CHECK: define internal {{.+}}[[REGNAME2]](
+// CHECK-NOT: invoke
+// CHECK: call void %{{[0-9]+}}()
+// CHECK-NOT: invoke
+// CHECK: ret void
diff --git a/test/CodeGenCXX/optnone-and-attributes.cpp b/test/CodeGenCXX/optnone-and-attributes.cpp
new file mode 100644
index 0000000..56173b5
--- /dev/null
+++ b/test/CodeGenCXX/optnone-and-attributes.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 < %s -triple i386-mingw32 -fms-extensions -emit-llvm -x c++ | FileCheck %s
+
+// optnone wins over inlinehint.
+// Test that both func1 and func2 are marked optnone and noinline.
+
+// Definition with both optnone and inlinehint.
+__attribute__((optnone))
+inline int func1(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_Z5func1i({{.*}}) [[OPTNONE:#[0-9]+]]
+
+// optnone declaration, inlinehint definition.
+__attribute__((optnone))
+int func2(int a);
+
+inline int func2(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_Z5func2i({{.*}}) [[OPTNONE]]
+
+// Keep alive the definitions of func1 and func2.
+int foo() {
+ int val = func1(1);
+ return val + func2(2);
+}
+
+// optnone wins over minsize.
+__attribute__((optnone))
+int func3(int a);
+
+__attribute__((minsize))
+int func3(int a) {
+ return a + a + a + a;
+}
+// Same attribute set as everything else, therefore no 'minsize'.
+// CHECK: @_Z5func3i({{.*}}) [[OPTNONE]]
+
+
+// Verify that noreturn is compatible with optnone.
+__attribute__((noreturn))
+extern void exit_from_function();
+
+__attribute__((noreturn)) __attribute((optnone))
+extern void noreturn_function(int a) { exit_from_function(); }
+// CHECK: @_Z17noreturn_functioni({{.*}}) [[NORETURN:#[0-9]+]]
+
+
+// Verify that __declspec(noinline) is compatible with optnone.
+__declspec(noinline) __attribute__((optnone))
+void func4() { return; }
+// CHECK: @_Z5func4v() [[OPTNONE]]
+
+__declspec(noinline)
+extern void func5();
+
+__attribute__((optnone))
+void func5() { return; }
+// CHECK: @_Z5func5v() [[OPTNONE]]
+
+
+// Verify also that optnone can be used on dllexport functions.
+// Adding attribute optnone on a dllimport function has no effect.
+
+__attribute__((dllimport))
+__attribute__((optnone))
+int imported_optnone_func(int a);
+
+__attribute__((dllexport))
+__attribute__((optnone))
+int exported_optnone_func(int a) {
+ return imported_optnone_func(a); // use of imported func
+}
+// CHECK: @_Z21exported_optnone_funci({{.*}}) [[OPTNONE]]
+// CHECK: declare dllimport {{.*}} @_Z21imported_optnone_funci({{.*}}) [[DLLIMPORT:#[0-9]+]]
+
+
+// CHECK: attributes [[OPTNONE]] = { noinline {{.*}} optnone
+// CHECK: attributes [[NORETURN]] = { noinline noreturn {{.*}} optnone
+
+// CHECK: attributes [[DLLIMPORT]] =
+// CHECK-SAME-NOT: optnone
diff --git a/test/CodeGenCXX/optnone-class-members.cpp b/test/CodeGenCXX/optnone-class-members.cpp
new file mode 100644
index 0000000..147b821
--- /dev/null
+++ b/test/CodeGenCXX/optnone-class-members.cpp
@@ -0,0 +1,164 @@
+// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -x c++ | FileCheck %s
+
+// Test attribute 'optnone' on methods:
+// -- member functions;
+// -- static member functions.
+
+// Verify that all methods of struct A are associated to the same attribute set.
+// The attribute set shall contain attributes 'noinline' and 'optnone'.
+
+struct A {
+ // Definition of an optnone static method.
+ __attribute__((optnone))
+ static int static_optnone_method(int a) {
+ return a + a;
+ }
+ // CHECK: @_ZN1A21static_optnone_methodEi({{.*}}) [[OPTNONE:#[0-9]+]]
+
+ // Definition of an optnone normal method.
+ __attribute__((optnone))
+ int optnone_method(int a) {
+ return a + a + a + a;
+ }
+ // CHECK: @_ZN1A14optnone_methodEi({{.*}}) [[OPTNONE]]
+
+ // Declaration of an optnone method with out-of-line definition
+ // that doesn't say optnone.
+ __attribute__((optnone))
+ int optnone_decl_method(int a);
+
+ // Methods declared without attribute optnone; the definitions will
+ // have attribute optnone, and we verify optnone wins.
+ __forceinline static int static_forceinline_method(int a);
+ __attribute__((always_inline)) int alwaysinline_method(int a);
+ __attribute__((noinline)) int noinline_method(int a);
+ __attribute__((minsize)) int minsize_method(int a);
+};
+
+void foo() {
+ A a;
+ A::static_optnone_method(4);
+ a.optnone_method(14);
+ a.optnone_decl_method(12);
+ A::static_forceinline_method(5);
+ a.alwaysinline_method(5);
+ a.noinline_method(6);
+ a.minsize_method(7);
+}
+
+// No attribute here, should still be on the definition.
+int A::optnone_decl_method(int a) {
+ return a;
+}
+// CHECK: @_ZN1A19optnone_decl_methodEi({{.*}}) [[OPTNONE]]
+
+// optnone implies noinline; therefore attribute noinline is added to
+// the set of function attributes.
+// forceinline is instead translated as 'always_inline'.
+// However 'noinline' wins over 'always_inline' and therefore
+// the resulting attributes for this method are: noinline + optnone
+__attribute__((optnone))
+int A::static_forceinline_method(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_ZN1A25static_forceinline_methodEi({{.*}}) [[OPTNONE]]
+
+__attribute__((optnone))
+int A::alwaysinline_method(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_ZN1A19alwaysinline_methodEi({{.*}}) [[OPTNONE]]
+
+// 'noinline' + 'noinline and optnone' = 'noinline and optnone'
+__attribute__((optnone))
+int A::noinline_method(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_ZN1A15noinline_methodEi({{.*}}) [[OPTNONE]]
+
+// 'optnone' wins over 'minsize'
+__attribute__((optnone))
+int A::minsize_method(int a) {
+ return a + a + a + a;
+}
+// CHECK: @_ZN1A14minsize_methodEi({{.*}}) [[OPTNONE]]
+
+
+// Test attribute 'optnone' on methods:
+// -- pure virtual functions
+// -- base virtual and derived virtual
+// -- base virtual but not derived virtual
+// -- optnone methods redefined in override
+
+// A method defined in override doesn't inherit the function attributes of the
+// superclass method.
+
+struct B {
+ virtual int pure_virtual(int a) = 0;
+ __attribute__((optnone))
+ virtual int pure_virtual_with_optnone(int a) = 0;
+
+ virtual int base(int a) {
+ return a + a + a + a;
+ }
+
+ __attribute__((optnone))
+ virtual int optnone_base(int a) {
+ return a + a + a + a;
+ }
+
+ __attribute__((optnone))
+ virtual int only_base_virtual(int a) {
+ return a + a;
+ }
+};
+
+struct C : public B {
+ __attribute__((optnone))
+ virtual int pure_virtual(int a) {
+ return a + a + a + a;
+ }
+
+ virtual int pure_virtual_with_optnone(int a) {
+ return a + a + a + a;
+ }
+
+ __attribute__((optnone))
+ virtual int base(int a) {
+ return a + a;
+ }
+
+ virtual int optnone_base(int a) {
+ return a + a;
+ }
+
+ int only_base_virtual(int a) {
+ return a + a + a + a;
+ }
+};
+
+int bar() {
+ C c;
+ int result;
+ result = c.pure_virtual(3);
+ result += c.pure_virtual_with_optnone(2);
+ result += c.base(5);
+ result += c.optnone_base(7);
+ result += c.only_base_virtual(9);
+ return result;
+}
+
+// CHECK: @_ZN1C12pure_virtualEi({{.*}}) {{.*}} [[OPTNONE]]
+// CHECK: @_ZN1C25pure_virtual_with_optnoneEi({{.*}}) {{.*}} [[NORMAL:#[0-9]+]]
+// CHECK: @_ZN1C4baseEi({{.*}}) {{.*}} [[OPTNONE]]
+// CHECK: @_ZN1C12optnone_baseEi({{.*}}) {{.*}} [[NORMAL]]
+// CHECK: @_ZN1C17only_base_virtualEi({{.*}}) {{.*}} [[NORMAL]]
+// CHECK: @_ZN1B4baseEi({{.*}}) {{.*}} [[NORMAL]]
+// CHECK: @_ZN1B12optnone_baseEi({{.*}}) {{.*}} [[OPTNONE]]
+// CHECK: @_ZN1B17only_base_virtualEi({{.*}}) {{.*}} [[OPTNONE]]
+
+
+// CHECK: attributes [[NORMAL]] =
+// CHECK-SAME-NOT: noinline
+// CHECK-SAME-NOT: optnone
+// CHECK: attributes [[OPTNONE]] = {{.*}} noinline {{.*}} optnone
diff --git a/test/CodeGenCXX/optnone-def-decl.cpp b/test/CodeGenCXX/optnone-def-decl.cpp
index ab6eb3f..cb3a677 100644
--- a/test/CodeGenCXX/optnone-def-decl.cpp
+++ b/test/CodeGenCXX/optnone-def-decl.cpp
@@ -90,5 +90,6 @@
// CHECK: @_Z28forceinline_optnone_functionii({{.*}}) [[OPTNONE]]
// CHECK: attributes [[OPTNONE]] = { noinline nounwind optnone {{.*}} }
-// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} }
-
+// CHECK: attributes [[NORMAL]] =
+// CHECK-SAME-NOT: noinline
+// CHECK-SAME-NOT: optnone
diff --git a/test/CodeGenCXX/optnone-templates.cpp b/test/CodeGenCXX/optnone-templates.cpp
new file mode 100644
index 0000000..45a72b3
--- /dev/null
+++ b/test/CodeGenCXX/optnone-templates.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -std=c++11 -emit-llvm -o - | FileCheck %s
+
+// Test optnone on template instantiations.
+
+//-- Effect of optnone on generic add template function.
+
+template <typename T> T template_normal(T a)
+{
+ return a + a;
+}
+
+template <typename T> __attribute__((optnone)) T template_optnone(T a)
+{
+ return a + a + a;
+}
+
+// This function should cause instantiations of each template, one marked
+// with the 'optnone' attribute.
+int container(int i)
+{
+ return template_normal<int>(i) + template_optnone<int>(i);
+}
+
+// CHECK: @_Z15template_normalIiET_S0_({{.*}}) [[NORMAL:#[0-9]+]]
+// CHECK: @_Z16template_optnoneIiET_S0_({{.*}}) [[OPTNONE:#[0-9]+]]
+
+
+//-- Effect of optnone on a partial specialization.
+// FIRST TEST: a method becomes marked with optnone in the specialization.
+
+template <typename T, typename U> class template_normal_base {
+public:
+ T method(T t, U u)
+ {
+ return t + static_cast<T>(u);
+ }
+};
+
+template <typename U> class template_normal_base<int, U>
+{
+public:
+ __attribute__((optnone)) int method (int t, U u)
+ {
+ return t - static_cast<int>(u);
+ }
+};
+
+// This function should cause an instantiation of the full template (whose
+// method is not marked optnone) and an instantiation of the partially
+// specialized template (whose method is marked optnone).
+void container2()
+{
+ int y = 2;
+ float z = 3.0;
+ template_normal_base<float, int> class_normal;
+ template_normal_base<int, float> class_optnone;
+ float r1 = class_normal.method(z, y);
+ float r2 = class_optnone.method(y, z);
+}
+
+// CHECK: @_ZN20template_normal_baseIfiE6methodEfi({{.*}}) [[NORMAL]]
+// CHECK: @_ZN20template_normal_baseIifE6methodEif({{.*}}) [[OPTNONE]]
+
+
+//-- Effect of optnone on a partial specialization.
+// SECOND TEST: a method loses optnone in the specialization.
+
+template <typename T, typename U> class template_optnone_base {
+public:
+ __attribute__((optnone)) T method(T t, U u)
+ {
+ return t + static_cast<T>(u);
+ }
+};
+
+template <typename U> class template_optnone_base<int, U>
+{
+public:
+ int method (int t, U u)
+ {
+ return t - static_cast<int>(u);
+ }
+};
+
+// This function should cause an instantiation of the full template (whose
+// method is marked optnone) and an instantiation of the partially
+// specialized template (whose method is not marked optnone).
+void container3()
+{
+ int y = 2;
+ float z = 3.0;
+ template_optnone_base<float, int> class_optnone;
+ template_optnone_base<int, float> class_normal;
+ float r1 = class_optnone.method(z, y);
+ float r2 = class_normal.method(y, z);
+}
+
+// CHECK: @_ZN21template_optnone_baseIfiE6methodEfi({{.*}}) [[OPTNONE]]
+// CHECK: @_ZN21template_optnone_baseIifE6methodEif({{.*}}) [[NORMAL]]
+
+
+// CHECK: attributes [[NORMAL]] =
+// CHECK-SAME-NOT: optnone
+// CHECK: attributes [[OPTNONE]] = {{.*}} optnone
diff --git a/test/CodeGenCXX/pass-object-size.cpp b/test/CodeGenCXX/pass-object-size.cpp
new file mode 100644
index 0000000..2c7f974
--- /dev/null
+++ b/test/CodeGenCXX/pass-object-size.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 -std=c++11 | FileCheck %s
+
+int gi;
+
+namespace lambdas {
+// CHECK-LABEL: define void @_ZN7lambdas7LambdasEPc
+void Lambdas(char *ptr) {
+ auto L1 = [](void *const p __attribute__((pass_object_size(0)))) {
+ return __builtin_object_size(p, 0);
+ };
+
+ int i = 0;
+ auto L2 = [&i](void *const p __attribute__((pass_object_size(0)))) {
+ return __builtin_object_size(p, 0) + i;
+ };
+
+ // CHECK: @llvm.objectsize
+ gi = L1(ptr);
+ // CHECK: @llvm.objectsize
+ gi = L2(ptr);
+}
+
+// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_0clEPvU17pass_object_size0"
+// CHECK-NOT: call i64 @llvm.objectsize
+// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_1clEPvU17pass_object_size0"
+// CHECK-NOT: call i64 @llvm.objectsize
+}
+
+// This is here instead of in Sema/ because we need to check to make sure the
+// proper function is called. If it's not, we'll end up with assertion errors.
+namespace addrof {
+void OvlFoo(void *const __attribute__((pass_object_size(0)))) {}
+void OvlFoo(int *const) {}
+
+// CHECK: define void @_ZN6addrof4TestEv
+void Test() {
+ // Treating parens-only calls as though they were direct is consistent with
+ // how we handle other implicitly unaddressable functions (e.g. builtins).
+ // CHECK: call void @_ZN6addrof6OvlFooEPvU17pass_object_size0
+ (OvlFoo)(nullptr);
+
+ // CHECK: call void @_ZN6addrof6OvlFooEPi
+ (&OvlFoo)(nullptr);
+}
+}
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 94337d9..fd1b9b8 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -1,8 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10
// RUN: FileCheck %s < %t.ll
// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t.ll
-// RUN: %clang_cc1 %s -emit-llvm -o %t-opt.ll -triple=x86_64-apple-darwin10 -O3
-// RUN: FileCheck --check-prefix=CHECK-O3 %s < %t-opt.ll
struct A { int a; int b; };
struct B { int b; };
@@ -131,40 +129,6 @@
}
-namespace PR7139 {
-
-struct pair {
- int first;
- int second;
-};
-
-typedef int pair::*ptr_to_member_type;
-
-struct ptr_to_member_struct {
- ptr_to_member_type data;
- int i;
-};
-
-struct A {
- ptr_to_member_struct a;
-
- A() : a() {}
-};
-
-// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() [[NUW:#[0-9]+]]
-bool check() {
- // CHECK-O3: ret i1 true
- return A().a.data == 0;
-}
-
-// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() [[NUW]]
-bool check2() {
- // CHECK-O3: ret i1 true
- return ptr_to_member_type() == 0;
-}
-
-}
-
namespace VirtualBases {
struct A {
@@ -294,5 +258,3 @@
U u;
// CHECK-GLOBAL: @_ZN11IndirectPDM1uE = global %"union.IndirectPDM::U" { %union.anon { i64 -1 } }, align 8
}
-
-// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/pr20719.cpp b/test/CodeGenCXX/pr20719.cpp
index 208d111..1c3b21b 100644
--- a/test/CodeGenCXX/pr20719.cpp
+++ b/test/CodeGenCXX/pr20719.cpp
@@ -2,8 +2,8 @@
// Make sure that we emit H's constructor twice: once with the first lambda
// inside of 'lep' and again with the second lambda inside of 'lep'.
-// CHECK-DAG: @"\01??0?$H@V<lambda_1>@??$lep@X@@YAXXZ@@@QAE@XZ"
-// CHECK-DAG: @"\01??0?$H@V<lambda_2>@??$lep@X@@YAXXZ@@@QAE@XZ"
+// CHECK-DAG: @"\01??0?$H@V<lambda_1>@?0???$lep@X@@YAXXZ@@@QAE@XZ"
+// CHECK-DAG: @"\01??0?$H@V<lambda_2>@?0???$lep@X@@YAXXZ@@@QAE@XZ"
template <typename>
struct H {
diff --git a/test/CodeGenCXX/tls-init-funcs.cpp b/test/CodeGenCXX/tls-init-funcs.cpp
index d47329c..a2a563b 100644
--- a/test/CodeGenCXX/tls-init-funcs.cpp
+++ b/test/CodeGenCXX/tls-init-funcs.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8 -std=c++1y -S -emit-llvm %s -o - | FileCheck %s
// CHECK: @a = internal thread_local global
-// CHECK: @_Z2vtIiE = internal thread_local global i32 5
+// CHECK: @_Z2vtIiE = linkonce_odr thread_local global i32 5
// CHECK: @_ZZ3inlvE3loc = linkonce_odr thread_local global i32 0
// CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev
-// CHECK: call i32* @_ZTW3ext()
-// CHECK: declare i32* @_ZTW3ext()
-// CHECK: define weak i32* @_ZTW2vtIiE()
-// CHECK: define weak i32* @_ZTW2vtIvE()
+// CHECK: call cxx_fast_tlscc i32* @_ZTW3ext()
+// CHECK: declare cxx_fast_tlscc i32* @_ZTW3ext()
+// CHECK: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIiE()
+// CHECK: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIvE()
// CHECK: define {{.*}} @_ZTW1a
struct A {
diff --git a/test/CodeGenCXX/vector-splat-conversion.cpp b/test/CodeGenCXX/vector-splat-conversion.cpp
index 410df3d..805f9f5 100644
--- a/test/CodeGenCXX/vector-splat-conversion.cpp
+++ b/test/CodeGenCXX/vector-splat-conversion.cpp
@@ -1,19 +1,51 @@
// RUN: %clang_cc1 %s -triple arm64-apple-ios8.1.0 -std=c++11 -emit-llvm -o - | FileCheck %s
-// rdar://20000762
typedef __attribute__((__ext_vector_type__(8))) float vector_float8;
typedef vector_float8 float8;
-void MandelbrotPolyCalcSIMD8()
-{
- constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded
- float8 vABS;
- auto vLT = vABS < v4;
+// rdar://20000762
+// CHECK-LABEL: define void @_Z23MandelbrotPolyCalcSIMD8v
+void MandelbrotPolyCalcSIMD8() {
+ constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded
+ float8 vABS;
+ auto vLT = vABS < v4;
+ // CHECK: store <8 x float>
+ // CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]]
+ // CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]]
+ // CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32>
+ // CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]]
}
-// CHECK: store <8 x float>
-// CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]]
-// CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]]
-// CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32>
-// CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]]
+typedef __attribute__((__ext_vector_type__(4))) int int4;
+typedef __attribute__((__ext_vector_type__(4))) float float4;
+typedef __attribute__((__ext_vector_type__(4))) __int128 bigint4;
+
+// CHECK-LABEL: define void @_Z14BoolConversionv
+void BoolConversion() {
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ int4 intsT = (int4)true;
+ // CHECK: store <4 x i32> zeroinitializer
+ int4 intsF = (int4)false;
+ // CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ float4 floatsT = (float4)true;
+ // CHECK: store <4 x float> zeroinitializer
+ float4 floatsF = (float4)false;
+ // CHECK: store <4 x i128> <i128 -1, i128 -1, i128 -1, i128 -1>
+ bigint4 bigintsT = (bigint4)true;
+ // CHECK: store <4 x i128> zeroinitializer
+ bigint4 bigintsF = (bigint4)false;
+
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ constexpr int4 cIntsT = (int4)true;
+ // CHECK: store <4 x i32> zeroinitializer
+ constexpr int4 cIntsF = (int4)false;
+ // CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ constexpr float4 cFloatsT = (float4)true;
+ // CHECK: store <4 x float> zeroinitializer
+ constexpr float4 cFloatsF = (float4)false;
+ // CHECK: store <4 x i128> <i128 -1, i128 -1, i128 -1, i128 -1>
+ constexpr bigint4 cBigintsT = (bigint4)true;
+ // CHECK: store <4 x i128> zeroinitializer
+ constexpr bigint4 cBigintsF = (bigint4)false;
+}
diff --git a/test/CodeGenObjC/2010-02-01-utf16-with-null.m b/test/CodeGenObjC/2010-02-01-utf16-with-null.m
index 46ce3b2..7c103f2 100644
--- a/test/CodeGenObjC/2010-02-01-utf16-with-null.m
+++ b/test/CodeGenObjC/2010-02-01-utf16-with-null.m
@@ -2,6 +2,6 @@
// rdar://7589850
// CHECK: @.str = private unnamed_addr constant [9 x i16] [i16 103, i16 111, i16 111, i16 100, i16 0, i16 98, i16 121, i16 101, i16 0], section "__TEXT,__ustring", align 2
-// CHECK: @_unnamed_cfstring_ = private constant %struct.NSConstantString { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 2000, i8* bitcast ([9 x i16]* @.str to i8*), i32 8 }, section "__DATA,__cfstring"
-// CHECK: @P = global i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), align 4
+// CHECK: @_unnamed_cfstring_ = private constant %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 2000, i8* bitcast ([9 x i16]* @.str to i8*), i32 8 }, section "__DATA,__cfstring"
+// CHECK: @P = global i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*), align 4
void *P = @"good\0bye";
diff --git a/test/CodeGenObjC/arc-i386.m b/test/CodeGenObjC/arc-i386.m
new file mode 100644
index 0000000..7693a8f
--- /dev/null
+++ b/test/CodeGenObjC/arc-i386.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-iossimulator6.0 -emit-llvm -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// <rdar://24531556>: implement objc_retainAutoreleasedReturnValue on i386
+
+// CHECK-LABEL: define i8* @test0()
+id test0(void) {
+ extern id test0_helper(void);
+ // CHECK: [[T0:%.*]] = call i8* @test0_helper()
+ // CHECK-NEXT: ret i8* [[T0]]
+ return test0_helper();
+}
+
+// CHECK-LABEL: define void @test1()
+void test1(void) {
+ extern id test1_helper(void);
+ // CHECK: [[T0:%.*]] = call i8* @test1_helper()
+ // CHECK-NEXT: call void asm sideeffect "mov
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]],
+ // CHECK-NEXT: call void @objc_storeStrong(
+ // CHECK-NEXT: ret void
+ id x = test1_helper();
+}
+
+// rdar://problem/12133032
+// CHECK-LABEL: define {{.*}} @test2()
+@class A;
+A *test2(void) {
+ extern A *test2_helper(void);
+ // CHECK: [[T0:%.*]] = call [[A:%.*]]* @test2_helper()
+ // CHECK-NEXT: ret [[A]]* [[T0]]
+ return test2_helper();
+}
+
+// CHECK-LABEL: define i8* @test3()
+id test3(void) {
+ extern A *test3_helper(void);
+ // CHECK: [[T0:%.*]] = call [[A]]* @test3_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+ // CHECK-NEXT: ret i8* [[T1]]
+ return test3_helper();
+}
diff --git a/test/CodeGenObjC/arc-linetable.m b/test/CodeGenObjC/arc-linetable.m
index 94acec4..877dfdc 100644
--- a/test/CodeGenObjC/arc-linetable.m
+++ b/test/CodeGenObjC/arc-linetable.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-arc -debug-info-kind=standalone -dwarf-version=4 -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-arc -debug-info-kind=standalone -dwarf-version=4 -disable-llvm-passes -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
// Legend: EXP = Return expression, RET = ret instruction
@@ -35,7 +35,7 @@
// CHECK: define {{.*}}testCleanupVoid
// CHECK: icmp ne {{.*}}!dbg ![[SKIP1:[0-9]+]]
// CHECK: store i32 0, i32* {{.*}}, !dbg ![[RET8:[0-9]+]]
-// CHECK: @objc_storeStrong{{.*}}, !dbg ![[ARC8:[0-9]+]]
+// CHECK: @objc_storeStrong{{.*}}, !dbg ![[RET8]]
// CHECK: ret {{.*}} !dbg ![[RET8]]
typedef signed char BOOL;
@@ -112,8 +112,7 @@
[delegate testVoid :s];
}
}
- // CHECK: ![[RET8]] = !DILocation(line: [[@LINE+2]], scope:
- // CHECK: ![[ARC8]] = !DILocation(line: [[@LINE+1]], scope:
+ // CHECK: ![[RET8]] = !DILocation(line: [[@LINE+1]], scope:
}
diff --git a/test/CodeGenObjC/arc-no-arc-exceptions.m b/test/CodeGenObjC/arc-no-arc-exceptions.m
index 82977b0..f147b64 100644
--- a/test/CodeGenObjC/arc-no-arc-exceptions.m
+++ b/test/CodeGenObjC/arc-no-arc-exceptions.m
@@ -34,7 +34,7 @@
void NSLog(id, ...);
// CHECK-LABEL: define void @test2(
-// CHECK: invoke void (i8*, ...) @NSLog(i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), i32* %{{.*}})
+// CHECK: invoke void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*), i32* %{{.*}})
// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
// NO-METADATA-LABEL: define void @test2(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
diff --git a/test/CodeGenObjC/arc-unsafeclaim.m b/test/CodeGenObjC/arc-unsafeclaim.m
new file mode 100644
index 0000000..cda00b0
--- /dev/null
+++ b/test/CodeGenObjC/arc-unsafeclaim.m
@@ -0,0 +1,231 @@
+// Make sure it works on x86-64.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime=macosx-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED
+
+// Make sure it works on ARM.
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED
+
+// Make sure it works on ARM64.
+// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED
+// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED
+
+// Make sure that it's implicitly disabled if the runtime version isn't high enough.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED
+// RUN: %clang_cc1 -triple arm64-apple-ios8 -fobjc-runtime=ios-8 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED -check-prefix=DISABLED-MARKED
+
+@class A;
+
+A *makeA(void);
+
+void test_assign() {
+ __unsafe_unretained id x;
+ x = makeA();
+}
+// CHECK-LABEL: define void @test_assign()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A:.*]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+// DISABLED-LABEL: define void @test_assign()
+// DISABLED: [[T0:%.*]] = call [[A:.*]]* @makeA()
+// DISABLED-MARKED-NEXT: call void asm sideeffect
+// DISABLED-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// DISABLED-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+
+void test_assign_assign() {
+ __unsafe_unretained id x, y;
+ x = y = makeA();
+}
+// CHECK-LABEL: define void @test_assign_assign()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_strong_assign_assign() {
+ __strong id x;
+ __unsafe_unretained id y;
+ x = y = makeA();
+}
+// CHECK-LABEL: define void @test_strong_assign_assign()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[OLD]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_assign_strong_assign() {
+ __unsafe_unretained id x;
+ __strong id y;
+ x = y = makeA();
+}
+// CHECK-LABEL: define void @test_assign_strong_assign()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT: call void @objc_release(i8* [[OLD]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[Y]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_init() {
+ __unsafe_unretained id x = makeA();
+}
+// CHECK-LABEL: define void @test_init()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_init_assignment() {
+ __unsafe_unretained id x;
+ __unsafe_unretained id y = x = makeA();
+}
+// CHECK-LABEL: define void @test_init_assignment()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_strong_init_assignment() {
+ __unsafe_unretained id x;
+ __strong id y = x = makeA();
+}
+// CHECK-LABEL: define void @test_strong_init_assignment()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[Y]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_init_strong_assignment() {
+ __strong id x;
+ __unsafe_unretained id y = x = makeA();
+}
+// CHECK-LABEL: define void @test_init_strong_assignment()
+// CHECK: [[X:%.*]] = alloca i8*
+// CHECK: [[Y:%.*]] = alloca i8*
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
+// CHECK-NEXT: store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[OLD]])
+// CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_ignored() {
+ makeA();
+}
+// CHECK-LABEL: define void @test_ignored()
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: ret void
+
+void test_cast_to_void() {
+ (void) makeA();
+}
+// CHECK-LABEL: define void @test_cast_to_void()
+// CHECK: [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT: ret void
+
+
+
+// This is always at the end of the module.
+
+// CHECK-OPTIMIZED: !clang.arc.retainAutoreleasedReturnValueMarker = !{!0}
diff --git a/test/CodeGenObjC/arc-weak.m b/test/CodeGenObjC/arc-weak.m
new file mode 100644
index 0000000..59f8d1d
--- /dev/null
+++ b/test/CodeGenObjC/arc-weak.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck %s
+
+__attribute((objc_root_class)) @interface A @end
+@interface B : A @end
+
+// rdar://problem/23559789
+// Ensure that type differences don't cause an assert here.
+void test0(__weak B **src) {
+ __weak A *dest = *src;
+}
+// CHECK-LABEL: define void @test0
+// CHECK: [[SRC:%.*]] = alloca [[B:%.*]]**, align 8
+// CHECK: [[DEST:%.*]] = alloca [[A:%.*]]*, align 8
+// CHECK: [[T0:%.*]] = load [[B]]**, [[B]]*** [[SRC]], align 8
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]** [[T0]] to [[A]]**
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[A]]** [[T1]] to i8**
+// CHECK-NEXT: call void @objc_copyWeak(i8** [[T2]], i8** [[T3]])
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK: call void @objc_destroyWeak(i8** [[T0]])
diff --git a/test/CodeGenObjC/debug-info-property-class-extension.m b/test/CodeGenObjC/debug-info-property-class-extension.m
new file mode 100644
index 0000000..ea25517
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property-class-extension.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -S -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s
+
+// Checks debug info for properties from class extensions for a few cases.
+
+
+// Readonly property in interface made readwrite in a category, with @impl
+// The interesting bit is that when the ivar debug info is generated, the corresponding
+// property is looked up and also gets debug info. If the debug info from the interface's
+// declaration and from the ivar doesn't match, this will end up with two DIObjCProperty
+// entries which would be bad.
+@interface FooROWithImpl
+// CHECK-NOT: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
+@property (readonly) int evolvingpropwithimpl;
+@end
+@interface FooROWithImpl ()
+// CHECK: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
+@property int evolvingpropwithimpl;
+@end
+@implementation FooROWithImpl
+@synthesize evolvingpropwithimpl = _evolvingpropwithimpl;
+@end
+
+
+// Simple property from a class extension:
+@interface Foo
+@end
+@interface Foo()
+// CHECK: !DIObjCProperty(name: "myprop"{{.*}}line: [[@LINE+1]]
+@property int myprop;
+@end
+// There's intentionally no @implementation for Foo, because that would
+// generate debug info for the property via the backing ivar.
+
+
+// Readonly property in interface made readwrite in a category:
+@interface FooRO
+// Shouldn't be here but in the class extension below.
+// CHECK-NOT: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
+@property (readonly) int evolvingprop;
+@end
+@interface FooRO ()
+// CHECK: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
+@property int evolvingprop;
+@end
+
+
+// This references types in this file to force emission of their debug info.
+void foo(Foo *f, FooRO *g, FooROWithImpl* h) { }
diff --git a/test/CodeGenObjC/metadata-class-properties.m b/test/CodeGenObjC/metadata-class-properties.m
new file mode 100644
index 0000000..9355766
--- /dev/null
+++ b/test/CodeGenObjC/metadata-class-properties.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck -check-prefix=CHECK-FRAGILE %s
+
+// CHECK: @"\01l_OBJC_$_CLASS_PROP_LIST_Proto" = private global {{.*}} section "__DATA, __objc_const", align 8
+// CHECK: @"\01l_OBJC_PROTOCOL_$_Proto" = {{.*}} global %struct._protocol_t { {{.*}} i32 96, i32 {{.*}} @"\01l_OBJC_$_CLASS_PROP_LIST_Proto" {{.*}} }
+// CHECK: @"\01l_OBJC_$_CLASS_PROP_LIST_Foo_$_Category" = private global {{.*}} section "__DATA, __objc_const", align 8
+// CHECK: @"\01l_OBJC_$_CATEGORY_Foo_$_Category" = private global %struct._category_t { {{.*}} @"\01l_OBJC_$_CLASS_PROP_LIST_Foo_$_Category" {{.*}} }, section "__DATA, __objc_const", align 8
+
+// CHECK: !{i32 1, !"Objective-C Class Properties", i32 64}
+
+// CHECK-FRAGILE: @"OBJC_$_CLASS_PROP_PROTO_LIST_Proto" = private global {{.*}} section "__OBJC,__property,regular,no_dead_strip", align 8
+// CHECK-FRAGILE: @"\01l_OBJC_PROTOCOLEXT_Proto" = private global %struct._objc_protocol_extension { i32 48, {{.*}} @"OBJC_$_CLASS_PROP_PROTO_LIST_Proto" {{.*}} }, align 8
+// CHECK-FRAGILE: @"\01l_OBJC_$_CLASS_PROP_LIST_Foo_Category" = private global {{.*}} section "__OBJC,__property,regular,no_dead_strip", align 8
+// CHECK-FRAGILE: @OBJC_CATEGORY_Foo_Category = private global %struct._objc_category { {{.*}}, i32 64, {{.*}} @"\01l_OBJC_$_CLASS_PROP_LIST_Foo_Category" {{.*}} }, section "__OBJC,__category,regular,no_dead_strip", align 8
+
+// CHECK-FRAGILE: !{i32 1, !"Objective-C Class Properties", i32 64}
+
+@interface Foo @end
+
+@protocol Proto
+@property (class, readonly) int proto_property;
+@end
+
+@interface Foo (Category) <Proto> @end
+
+@implementation Foo (Category)
++(int)proto_property { return 0; }
+@end
diff --git a/test/CodeGenObjC/mrc-weak.m b/test/CodeGenObjC/mrc-weak.m
index f9c4ff1..e2c78f0 100644
--- a/test/CodeGenObjC/mrc-weak.m
+++ b/test/CodeGenObjC/mrc-weak.m
@@ -6,6 +6,26 @@
- (void) run;
@end
+// The ivars in HighlyAlignedSubclass should be placed in the tail-padding
+// of the superclass. Ensure that they're still covered by layouts.
+@interface HighlyAligned : Object {
+ __attribute__((aligned(32))) void *array[2];
+}
+@end
+// CHECK-MODERN: @"OBJC_IVAR_$_HighlyAlignedSubclass.ivar2" = global i64 24,
+// CHECK-MODERN: @"OBJC_IVAR_$_HighlyAlignedSubclass.ivar" = global i64 16,
+// CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\02\00"
+// CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_HighlyAlignedSubclass" = {{.*}} {
+// CHECK-FRAGILE: @OBJC_INSTANCE_VARIABLES_HighlyAlignedSubclass = {{.*}}, i32 8 }, {{.*}}, i32 12 }]
+// CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\02\00"
+// CHECK-FRAGILE: @OBJC_CLASS_HighlyAlignedSubclass
+@interface HighlyAlignedSubclass : HighlyAligned {
+ __weak id ivar;
+ __weak id ivar2;
+}
+@end
+@implementation HighlyAlignedSubclass @end
+
// CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00"
// CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772
// 772 == 0x304
@@ -140,3 +160,32 @@
// CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define void @test9_baseline()
+// CHECK: define internal void @__copy_helper
+// CHECK: define internal void @__destroy_helper
+void test9_baseline(void) {
+ Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+
+// CHECK-LABEL: define void @test9()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @test9_fin()
+void test9(void) {
+ __unsafe_unretained Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+void test9_fin() {}
+
+// CHECK-LABEL: define void @test10()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @test10_fin()
+void test10(void) {
+ typedef __unsafe_unretained Foo *UnsafeFooPtr;
+ UnsafeFooPtr p = get_object();
+ use_block(^{ [p run]; });
+}
+void test10_fin() {}
diff --git a/test/CodeGenObjC/objc-literal-tests.m b/test/CodeGenObjC/objc-literal-tests.m
index c53ee64..03286e2 100644
--- a/test/CodeGenObjC/objc-literal-tests.m
+++ b/test/CodeGenObjC/objc-literal-tests.m
@@ -94,4 +94,4 @@
bar(^(void) { return YES; });
}
-// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { {{(norecurse )?}}nounwind{{.*}} }
diff --git a/test/CodeGenObjC/objc2-protocol-metadata.m b/test/CodeGenObjC/objc2-protocol-metadata.m
index 191016b..8e186fc 100644
--- a/test/CodeGenObjC/objc2-protocol-metadata.m
+++ b/test/CodeGenObjC/objc2-protocol-metadata.m
@@ -14,4 +14,4 @@
+ ClsP { return 0; }
@end
-// CHECK: %struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8* }
+// CHECK: %struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* }
diff --git a/test/CodeGenObjC/optimize-ivar-offset-load.m b/test/CodeGenObjC/optimize-ivar-offset-load.m
index 0317c09..6a073db 100644
--- a/test/CodeGenObjC/optimize-ivar-offset-load.m
+++ b/test/CodeGenObjC/optimize-ivar-offset-load.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Os -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -O0 -emit-llvm %s -o - | FileCheck %s
// rdar://16095748
@interface NSObject
@@ -31,7 +31,7 @@
// CHECK: [[ADDPTR:%.*]] = getelementptr inbounds i8, i8* [[THREE]], i64 [[IVAR]]
// CHECK: [[FOUR:%.*]] = bitcast i8* [[ADDPTR]] to i32*
// CHECK: [[FIVE:%.*]] = load i32, i32* [[FOUR]], align 4
-// CHECK: tail call void @foo(i32 [[FIVE]])
+// CHECK: call void @foo(i32 [[FIVE]])
@implementation SampleClass
+ (SampleClass*) new { return 0; }
diff --git a/test/CodeGenObjC/property-list-in-extension.m b/test/CodeGenObjC/property-list-in-extension.m
new file mode 100644
index 0000000..878745e
--- /dev/null
+++ b/test/CodeGenObjC/property-list-in-extension.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-weak -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck %s
+
+// Checks metadata for properties in a few cases.
+
+
+// Property from a class extension:
+__attribute__((objc_root_class))
+@interface Foo
+@end
+
+@interface Foo()
+@property int myprop;
+@end
+
+@implementation Foo
+@synthesize myprop = _myprop;
+@end
+// Metadata for _myprop should be present, and PROP_LIST for Foo should have
+// only one entry.
+// CHECK: = private global [12 x i8] c"Ti,V_myprop\00",
+// CHECK: @"\01l_OBJC_$_PROP_LIST_Foo" = private global { i32, i32, [1 x %struct._prop_t] }
+
+// Readonly property in interface made readwrite in a category:
+__attribute__((objc_root_class))
+@interface FooRO
+@property (readonly) int evolvingprop;
+@property (nonatomic,readonly,getter=isBooleanProp) int booleanProp;
+@property (nonatomic,readonly,weak) Foo *weakProp;
+@end
+
+@interface FooRO ()
+@property int evolvingprop;
+@property int booleanProp;
+@property Foo *weakProp;
+@end
+
+@implementation FooRO
+@synthesize evolvingprop = _evolvingprop;
+@end
+// Metadata for _evolvingprop should be present, and PROP_LIST for FooRO should
+// still have only one entry, and the one entry should point to the version of
+// the property with a getter and setter.
+// CHECK: [[evolvinggetter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [13 x i8] c"evolvingprop\00"
+// CHECK: [[evolvingsetter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [18 x i8] c"Ti,V_evolvingprop\00",
+// CHECK: [[booleanmetadata:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [34 x i8] c"Ti,N,GisBooleanProp,V_booleanProp\00"
+// CHECK: [[weakmetadata:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [23 x i8] c"T@\22Foo\22,W,N,V_weakProp\00"
+// CHECK: @"\01l_OBJC_$_PROP_LIST_FooRO" = private global { i32, i32, [3 x %struct._prop_t] }{{.*}}[[evolvinggetter]]{{.*}}[[evolvingsetter]]{{.*}}[[booleanmetadata]]
diff --git a/test/CodeGenObjC/tentative-cfconstantstring.m b/test/CodeGenObjC/tentative-cfconstantstring.m
index 5b3c3bd..9ff1a0a 100644
--- a/test/CodeGenObjC/tentative-cfconstantstring.m
+++ b/test/CodeGenObjC/tentative-cfconstantstring.m
@@ -32,12 +32,11 @@
@end
// CHECK: @__CFConstantStringClassReference = common global [24 x i32] zeroinitializer, align 16
-// CHECK: @_unnamed_cfstring_{{.*}} = private constant %struct.NSConstantString { i32* getelementptr inbounds ([24 x i32], [24 x i32]* @__CFConstantStringClassReference, i32 0, i32 0)
+// CHECK: @_unnamed_cfstring_{{.*}} = private constant %struct.__NSConstantString_tag { i32* getelementptr inbounds ([24 x i32], [24 x i32]* @__CFConstantStringClassReference, i32 0, i32 0)
// CHECK-LABEL: define internal void @_inlineFunction()
// CHECK: [[ZERO:%.*]] = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_
// CHECK-NEXT: [[ONE:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[TWO:%.*]] = bitcast %struct._class_t* [[ZERO]] to i8*
-// CHECK-NEXT: call void (i8*, i8*, [[T:%.*]]*, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, [[T:%.*]]*, ...)*)(i8* [[TWO]], i8* [[ONE]], [[T:%.*]]* bitcast (%struct.NSConstantString* @_unnamed_cfstring_{{.*}} to [[T:%.*]]*))
+// CHECK-NEXT: call void (i8*, i8*, [[T:%.*]]*, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, [[T:%.*]]*, ...)*)(i8* [[TWO]], i8* [[ONE]], [[T:%.*]]* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_{{.*}} to [[T:%.*]]*))
// CHECK-NEXT: ret void
-
diff --git a/test/CodeGenObjCXX/arc-weak.mm b/test/CodeGenObjCXX/arc-weak.mm
new file mode 100644
index 0000000..8fd0337
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-weak.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s
+
+__attribute((objc_root_class)) @interface A @end
+@interface B : A @end
+
+// rdar://problem/23559789
+// Ensure that type differences don't cause an assert here.
+void test0(__weak B **src) {
+ __weak A *dest = *src;
+}
+// CHECK-LABEL: define void @_Z5test0PU6__weakP1B(
+// CHECK: [[SRC:%.*]] = alloca [[B:%.*]]**, align 8
+// CHECK: [[DEST:%.*]] = alloca [[A:%.*]]*, align 8
+// CHECK: [[T0:%.*]] = load [[B]]**, [[B]]*** [[SRC]], align 8
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]** [[T0]] to [[A]]**
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[A]]** [[T1]] to i8**
+// CHECK-NEXT: call void @objc_copyWeak(i8** [[T2]], i8** [[T3]])
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK: call void @objc_destroyWeak(i8** [[T0]])
+
+void test1(__weak B **src) {
+ __weak A *dest = static_cast<__weak B*&&>(*src);
+}
+// CHECK-LABEL: define void @_Z5test1PU6__weakP1B(
+// CHECK: [[SRC:%.*]] = alloca [[B:%.*]]**, align 8
+// CHECK: [[DEST:%.*]] = alloca [[A:%.*]]*, align 8
+// CHECK: [[T0:%.*]] = load [[B]]**, [[B]]*** [[SRC]], align 8
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]** [[T0]] to [[A]]**
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[A]]** [[T1]] to i8**
+// CHECK-NEXT: call void @objc_moveWeak(i8** [[T2]], i8** [[T3]])
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]** [[DEST]] to i8**
+// CHECK: call void @objc_destroyWeak(i8** [[T0]])
diff --git a/test/CodeGenObjCXX/blocks.mm b/test/CodeGenObjCXX/blocks.mm
index fd93437..63a1b33 100644
--- a/test/CodeGenObjCXX/blocks.mm
+++ b/test/CodeGenObjCXX/blocks.mm
@@ -68,3 +68,18 @@
takeBlock(^{ useValues(ptr, this); });
}
};
+
+// rdar://problem/23713871
+// Check that we don't crash when using BLOCK_LAYOUT_STRONG.
+#pragma clang assume_nonnull begin
+@interface NSUUID @end
+#pragma clang assume_nonnull end
+
+struct Wrapper1 { NSUUID *Ref; };
+struct Wrapper2 { Wrapper1 W1; };
+
+@implementation B
+- (void) captureStrongRef {
+ __block Wrapper2 W2;
+}
+@end
diff --git a/test/CodeGenObjCXX/mrc-weak.mm b/test/CodeGenObjCXX/mrc-weak.mm
new file mode 100644
index 0000000..17ceb31
--- /dev/null
+++ b/test/CodeGenObjCXX/mrc-weak.mm
@@ -0,0 +1,183 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MODERN
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-FRAGILE
+
+@interface Object
+- (instancetype) retain;
+- (void) run;
+@end
+
+// CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00"
+// CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772
+// 772 == 0x304
+// ^ HasMRCWeakIvars
+// ^ HasCXXDestructorOnly
+// ^ HasCXXStructors
+
+// CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00"
+// CHECK-FRAGILE: @OBJC_CLASS_Foo = {{.*}} i32 134225921,
+// 134225921 == 0x08002001
+// ^ HasMRCWeakIvars
+// ^ HasCXXStructors
+// ^ Factory
+@interface Foo : Object {
+ __weak id ivar;
+}
+@end
+
+@implementation Foo
+// CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]"
+// CHECK: call void @objc_destroyWeak
+@end
+
+
+void test1(__weak id x) {}
+// CHECK-LABEL: define void @_Z5test1P11objc_object(
+// CHECK: [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: objc_initWeak
+// CHECK-NEXT: objc_destroyWeak
+// CHECK-NEXT: ret void
+
+void test2(id y) {
+ __weak id z = y;
+}
+// CHECK-LABEL: define void @_Z5test2P11objc_object(
+// CHECK: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Z:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[Z]], i8* [[T0]])
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]])
+// CHECK-NEXT: ret void
+
+void test3(id y) {
+ __weak id z;
+ z = y;
+}
+// CHECK-LABEL: define void @_Z5test3P11objc_object(
+// CHECK: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Z:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: store i8* null, i8** [[Z]]
+// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[Z]], i8* [[T0]])
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]])
+// CHECK-NEXT: ret void
+
+void test4(__weak id *p) {
+ id y = *p;
+}
+// CHECK-LABEL: define void @_Z5test4PU6__weakP11objc_object(
+// CHECK: [[P:%.*]] = alloca i8**,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
+// CHECK-NEXT: ret void
+
+void test5(__weak id *p) {
+ id y = [*p retain];
+}
+// CHECK-LABEL: define void @_Z5test5PU6__weakP11objc_object
+// CHECK: [[P:%.*]] = alloca i8**,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
+// CHECK-NEXT: ret void
+
+void test6(__weak Foo **p) {
+ Foo *y = [*p retain];
+}
+// CHECK-LABEL: define void @_Z5test6PU6__weakP3Foo
+// CHECK: [[P:%.*]] = alloca [[FOO:%.*]]**,
+// CHECK-NEXT: [[Y:%.*]] = alloca [[FOO]]*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load [[FOO]]**, [[FOO]]*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[FOO]]** [[T0]] to i8**
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[FOO]]*
+// CHECK-NEXT: store [[FOO]]* [[T3]], [[FOO]]** [[Y]]
+// CHECK-NEXT: ret void
+
+extern "C" id get_object(void);
+extern "C" void use_block(void (^)(void));
+
+void test7(void) {
+ __weak Foo *p = get_object();
+ use_block(^{ [p run ]; });
+}
+// CHECK-LABEL: define void @_Z5test7v
+// CHECK: [[P:%.*]] = alloca [[FOO]]*,
+// CHECK: [[T0:%.*]] = call i8* @get_object()
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[FOO]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[FOO]]** [[P]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[FOO]]* [[T1]] to i8*
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]])
+// CHECK: call void @objc_copyWeak
+// CHECK: call void @use_block
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK: @objc_copyWeak
+
+// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK: @objc_destroyWeak
+
+void test8(void) {
+ __block __weak Foo *p = get_object();
+ use_block(^{ [p run ]; });
+}
+// CHECK-LABEL: define void @_Z5test8v
+// CHECK: call i8* @objc_initWeak
+// CHECK-NOT: call void @objc_copyWeak
+// CHECK: call void @use_block
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define internal void @__Block_byref_object_copy
+// CHECK: call void @objc_moveWeak
+
+// CHECK-LABEL: define internal void @__Block_byref_object_dispose
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define void @_Z14test9_baselinev()
+// CHECK: define internal void @__copy_helper
+// CHECK: define internal void @__destroy_helper
+void test9_baseline(void) {
+ Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+
+// CHECK-LABEL: define void @_Z5test9v()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @_Z9test9_finv()
+void test9(void) {
+ __unsafe_unretained Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+void test9_fin() {}
+
+// CHECK-LABEL: define void @_Z6test10v()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @_Z10test10_finv()
+void test10(void) {
+ typedef __unsafe_unretained Foo *UnsafeFooPtr;
+ UnsafeFooPtr p = get_object();
+ use_block(^{ [p run]; });
+}
+void test10_fin() {}
+
+// CHECK-LABEL: define weak_odr void @_Z6test11ILj0EEvv()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @_Z10test11_finv()
+template <unsigned i> void test11(void) {
+ typedef __unsafe_unretained Foo *UnsafeFooPtr;
+ UnsafeFooPtr p = get_object();
+ use_block(^{ [p run]; });
+}
+template void test11<0>();
+void test11_fin() {}
diff --git a/test/CodeGenOpenCL/address-spaces.cl b/test/CodeGenOpenCL/address-spaces.cl
index e030c77..68fa02d 100644
--- a/test/CodeGenOpenCL/address-spaces.cl
+++ b/test/CodeGenOpenCL/address-spaces.cl
@@ -1,27 +1,47 @@
-// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefix=CL20
-void f__p(__private int *arg) { }
-// CHECK: i32* nocapture %arg
+// CHECK: i32* %arg
+void f__p(__private int *arg) {}
-void f__g(__global int *arg) { }
-// CHECK: i32 addrspace(1)* nocapture %arg
+// CHECK: i32 addrspace(1)* %arg
+void f__g(__global int *arg) {}
-void f__l(__local int *arg) { }
-// CHECK: i32 addrspace(2)* nocapture %arg
+// CHECK: i32 addrspace(2)* %arg
+void f__l(__local int *arg) {}
-void f__c(__constant int *arg) { }
-// CHECK: i32 addrspace(3)* nocapture %arg
+// CHECK: i32 addrspace(3)* %arg
+void f__c(__constant int *arg) {}
+// CHECK: i32* %arg
+void fp(private int *arg) {}
-void fp(private int *arg) { }
-// CHECK: i32* nocapture %arg
+// CHECK: i32 addrspace(1)* %arg
+void fg(global int *arg) {}
-void fg(global int *arg) { }
-// CHECK: i32 addrspace(1)* nocapture %arg
+// CHECK: i32 addrspace(2)* %arg
+void fl(local int *arg) {}
-void fl(local int *arg) { }
-// CHECK: i32 addrspace(2)* nocapture %arg
+// CHECK: i32 addrspace(3)* %arg
+void fc(constant int *arg) {}
-void fc(constant int *arg) { }
-// CHECK: i32 addrspace(3)* nocapture %arg
+#ifdef CL20
+int i;
+// CL20-DAG: @i = common addrspace(1) global i32 0
+int *ptr;
+// CL20-DAG: @ptr = common addrspace(1) global i32 addrspace(4)* null
+#endif
+// CHECK: i32* %arg
+// CL20-DAG: i32 addrspace(4)* %arg
+void f(int *arg) {
+
+ int i;
+// CHECK: %i = alloca i32,
+// CL20-DAG: %i = alloca i32,
+
+#ifdef CL20
+ static int ii;
+// CL20-DAG: @f.ii = internal addrspace(1) global i32 0
+#endif
+}
diff --git a/test/CodeGenOpenCL/bool_cast.cl b/test/CodeGenOpenCL/bool_cast.cl
index d63431b..8c86b06 100644
--- a/test/CodeGenOpenCL/bool_cast.cl
+++ b/test/CodeGenOpenCL/bool_cast.cl
@@ -2,7 +2,9 @@
typedef unsigned char uchar4 __attribute((ext_vector_type(4)));
typedef unsigned int int4 __attribute((ext_vector_type(4)));
+typedef float float4 __attribute((ext_vector_type(4)));
+// CHECK-LABEL: define void @ker()
void kernel ker() {
bool t = true;
int4 vec4 = (int4)t;
@@ -24,4 +26,8 @@
unsigned char c;
c = (unsigned char)true;
// CHECK: store i8 1, i8* %c, align 1
+
+ float4 vf;
+ vf = (float4)true;
+// CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
}
diff --git a/test/CodeGenOpenCL/pipe_types.cl b/test/CodeGenOpenCL/pipe_types.cl
new file mode 100644
index 0000000..547071c
--- /dev/null
+++ b/test/CodeGenOpenCL/pipe_types.cl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+
+// CHECK: %opencl.pipe_t = type opaque
+typedef unsigned char __attribute__((ext_vector_type(3))) uchar3;
+typedef int __attribute__((ext_vector_type(4))) int4;
+
+void test1(read_only pipe int p) {
+// CHECK: define void @test1(%opencl.pipe_t* %p)
+ reserve_id_t rid;
+// CHECK: %rid = alloca %opencl.reserve_id_t
+}
+
+void test2(write_only pipe float p) {
+// CHECK: define void @test2(%opencl.pipe_t* %p)
+}
+
+void test3(read_only pipe const int p) {
+// CHECK: define void @test3(%opencl.pipe_t* %p)
+}
+
+void test4(read_only pipe uchar3 p) {
+// CHECK: define void @test4(%opencl.pipe_t* %p)
+}
+
+void test5(read_only pipe int4 p) {
+// CHECK: define void @test5(%opencl.pipe_t* %p)
+}
diff --git a/test/CoverageMapping/ir.c b/test/CoverageMapping/ir.c
index 5ac3495..f94d34c 100644
--- a/test/CoverageMapping/ir.c
+++ b/test/CoverageMapping/ir.c
@@ -9,4 +9,4 @@
return 0;
}
-// CHECK: @__llvm_coverage_mapping = internal constant { i32, i32, i32, i32, [2 x <{ i8*, i32, i32, i64 }>], [{{[0-9]+}} x i8] } { i32 2, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 0, [2 x <{ i8*, i32, i32, i64 }>] [<{ i8*, i32, i32, i64 }> <{ i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i32 3, i32 9, i64 {{[0-9]+}} }>, <{ i8*, i32, i32, i64 }> <{ i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i32 4, i32 9, i64 {{[0-9]+}} }>]
+// CHECK: @__llvm_coverage_mapping = internal constant { { i32, i32, i32, i32 }, [2 x <{ i8*, i32, i32, i64 }>], [{{[0-9]+}} x i8] } { { i32, i32, i32, i32 } { i32 2, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 0 }, [2 x <{ i8*, i32, i32, i64 }>] [<{ i8*, i32, i32, i64 }> <{ i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i32 3, i32 9, i64 {{[0-9]+}} }>, <{ i8*, i32, i32, i64 }> <{ i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__profn_main, i32 0, i32 0), i32 4, i32 9, i64 {{[0-9]+}} }>]
diff --git a/test/CoverageMapping/unused_names.c b/test/CoverageMapping/unused_names.c
index d229492..00941b8 100644
--- a/test/CoverageMapping/unused_names.c
+++ b/test/CoverageMapping/unused_names.c
@@ -4,11 +4,11 @@
// Since foo is never emitted, there should not be a profile name for it.
-// CHECK-DAG: @__llvm_profile_name_bar = {{.*}} [3 x i8] c"bar", section "{{.*}}__llvm_prf_names"
-// CHECK-DAG: @__llvm_profile_name_baz = {{.*}} [3 x i8] c"baz", section "{{.*}}__llvm_prf_names"
-// CHECK-DAG: @"__llvm_profile_name_unused_names.c:qux" = {{.*}} [18 x i8] c"unused_names.c:qux", section "{{.*}}__llvm_prf_names"
+// CHECK-DAG: @__profn_bar = {{.*}} [3 x i8] c"bar", section "{{.*}}__llvm_prf_names"
+// CHECK-DAG: @__profn_baz = {{.*}} [3 x i8] c"baz", section "{{.*}}__llvm_prf_names"
+// CHECK-DAG: @__profn_unused_names.c_qux = {{.*}} [18 x i8] c"unused_names.c:qux", section "{{.*}}__llvm_prf_names"
-// SYSHEADER-NOT: @__llvm_profile_name_foo =
+// SYSHEADER-NOT: @__profn_foo =
#ifdef IS_SYSHEADER
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/CUDA/usr/local/cuda/bin/.keep
similarity index 100%
rename from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
rename to test/Driver/Inputs/CUDA/usr/local/cuda/bin/.keep
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/libdevice.compute_20.10.bc
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/libdevice.compute_20.10.bc
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/libdevice.compute_35.10.bc
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/libdevice.compute_35.10.bc
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtend.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtend.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crti.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crti.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtn.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtn.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/basic_myriad_tree/sparc-myriad-elf/lib/crt0.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/basic_myriad_tree/sparc-myriad-elf/lib/crt0.o
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as
deleted file mode 100755
index 331ef4a..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as
+++ /dev/null
@@ -1 +0,0 @@
-# placeholder for testing purposes
\ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc
deleted file mode 100755
index 331ef4a..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc
+++ /dev/null
@@ -1 +0,0 @@
-# placeholder for testing purposes
\ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld
deleted file mode 100755
index 331ef4a..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld
+++ /dev/null
@@ -1 +0,0 @@
-# placeholder for testing purposes
\ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios
deleted file mode 100644
index 777a4ec..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios
+++ /dev/null
@@ -1 +0,0 @@
-// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h
deleted file mode 100644
index 777a4ec..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h
+++ /dev/null
@@ -1 +0,0 @@
-// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h
deleted file mode 100644
index 777a4ec..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h
+++ /dev/null
@@ -1 +0,0 @@
-// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h
deleted file mode 100644
index 777a4ec..0000000
--- a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h
+++ /dev/null
@@ -1 +0,0 @@
-// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder b/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder
deleted file mode 100644
index 777a4ec..0000000
--- a/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder
+++ /dev/null
@@ -1 +0,0 @@
-// placeholder for testing purposes
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mips-r2-hard-musl/lib/linux/libclang_rt.builtins-mips.a
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mips-r2-hard-musl/lib/linux/libclang_rt.builtins-mips.a
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mips-r2-hard-musl/lib/linux/libclang_rt.builtins-mips.so
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mips-r2-hard-musl/lib/linux/libclang_rt.builtins-mips.so
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mipsel-r2-hard-musl/lib/linux/libclang_rt.builtins-mipsel.a
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mipsel-r2-hard-musl/lib/linux/libclang_rt.builtins-mipsel.a
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mipsel-r2-hard-musl/lib/linux/libclang_rt.builtins-mipsel.so
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/lib/clang/3.8.0/mipsel-r2-hard-musl/lib/linux/libclang_rt.builtins-mipsel.so
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crt1.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crti.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crti.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crtn.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mips-r2-hard-musl/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crt1.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crti.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crti.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crtn.o
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/mips_mti_linux/sysroot/mipsel-r2-hard-musl/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/multilib_arm_linux_tree/usr/include/arm-linux-gnueabi/.keep
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/multilib_arm_linux_tree/usr/include/arm-linux-gnueabi/.keep
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/multilib_armeb_linux_tree/usr/include/armeb-linux-gnueabi/.keep
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/multilib_armeb_linux_tree/usr/include/armeb-linux-gnueabi/.keep
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/multilib_armebhf_linux_tree/usr/include/armeb-linux-gnueabihf/.keep
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/multilib_armebhf_linux_tree/usr/include/armeb-linux-gnueabihf/.keep
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Driver/Inputs/multilib_armhf_linux_tree/usr/include/arm-linux-gnueabihf/.keep
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Driver/Inputs/multilib_armhf_linux_tree/usr/include/arm-linux-gnueabihf/.keep
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index ab1afea..7b0fac4 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -18,6 +18,21 @@
// RUN: %clang -target arm64-apple-darwin -arch arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-DARWIN %s
// ARM64-DARWIN: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cyclone"
+// RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// CA35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a35"
+
+// RUN: %clang -target arm64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
+// RUN: %clang -target arm64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
+// ARM64-CA35: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a35"
+
+
// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
@@ -59,11 +74,33 @@
// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s
// ARM64-CA72: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a72"
+// RUN: %clang -target aarch64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// M1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "exynos-m1"
+
+// RUN: %clang -target arm64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
+// RUN: %clang -target arm64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
+// ARM64-M1: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m1"
+
// RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// RUN: %clang -target aarch64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// GENERIC-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
+// RUN: %clang -target aarch64_be -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// CA35-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a35"
+
// RUN: %clang -target aarch64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
@@ -88,6 +125,14 @@
// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
// CA72-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a72"
+// RUN: %clang -target aarch64_be -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64_be -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// M1-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m1"
+
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
@@ -114,6 +159,24 @@
// RUN: %clang -target aarch64 -mbig-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+
+// RUN: %clang -target aarch64 -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// RUN: %clang -target aarch64 -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// RUN: %clang -target aarch64 -mlittle-endian -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// RUN: %clang -target aarch64 -mlittle-endian -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// RUN: %clang -target aarch64_be -mlittle-endian -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// RUN: %clang -target aarch64_be -mlittle-endian -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A %s
+// GENERICV82A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.2a"
+
+// RUN: %clang -target aarch64 -march=armv8.2-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16 %s
+// GENERICV82A-FP16: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.2a" "-target-feature" "+fullfp16"
+
+// RUN: %clang -target aarch64 -march=armv8.2-a+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-SPE %s
+// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.2a" "-target-feature" "+spe"
+//
+// RUN: %clang -target aarch64 -march=armv8.2-a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s
+// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.2a" "-target-feature" "+fullfp16" "-target-feature" "+spe"
+
// ================== Check whether -march accepts mixed-case values.
// RUN: %clang -target aarch64_be -march=ARMV8.1A -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
// RUN: %clang -target aarch64_be -march=ARMV8.1-A -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
diff --git a/test/Driver/aarch64-fixed-x18.c b/test/Driver/aarch64-fixed-x18.c
index a79ac6c..631865f 100644
--- a/test/Driver/aarch64-fixed-x18.c
+++ b/test/Driver/aarch64-fixed-x18.c
@@ -1,9 +1,4 @@
// RUN: %clang -target aarch64-none-gnu -ffixed-x18 -### %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-FIXED-X18 < %t %s
-// RUN: %clang -target aarch64-none-gnu -### %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-NO-FIXED-X18 < %t %s
-// RUN: %clang -target -arm64-apple-ios -### %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-FIXED-X18 < %t %s
// CHECK-FIXED-X18: "-target-feature" "+reserve-x18"
-// CHECK-NO-FIXED-X18-NOT: "-target-feature" "+reserve-x18"
diff --git a/test/Driver/amdgpu-toolchain.c b/test/Driver/amdgpu-toolchain.c
index b6e05f8..c84a154 100644
--- a/test/Driver/amdgpu-toolchain.c
+++ b/test/Driver/amdgpu-toolchain.c
@@ -1,3 +1,3 @@
// RUN: %clang -### -target amdgcn--amdhsa -x assembler -mcpu=kaveri %s 2>&1 | FileCheck -check-prefix=AS_LINK %s
// AS_LINK: clang{{.*}} "-cc1as"
-// AS_LINK: lld{{.*}} "-flavor" "gnu" "-target" "amdgcn--amdhsa"
+// AS_LINK: ld.lld{{.*}}
diff --git a/test/Driver/appletvos-version-min.c b/test/Driver/appletvos-version-min.c
index 9ff8297..7cbb200 100644
--- a/test/Driver/appletvos-version-min.c
+++ b/test/Driver/appletvos-version-min.c
@@ -2,6 +2,7 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang -target i386-apple-darwin10 -mappletvsimulator-version-min=9.0 -arch x86_64 -S -o - %s | FileCheck %s
// RUN: %clang -target armv7s-apple-darwin10 -mappletvos-version-min=9.0 -arch arm64 -S -o - %s | FileCheck %s
+// RUN: env TVOS_DEPLOYMENT_TARGET=9.0 %clang -isysroot SDKs/MacOSX10.9.sdk -target i386-apple-darwin10 -arch x86_64 -S -o - %s | FileCheck %s
int main() { return 0; }
// CHECK: .tvos_version_min 9, 0
diff --git a/test/Driver/arch-armv7k.c b/test/Driver/arch-armv7k.c
index 190d899..5ebdd38 100644
--- a/test/Driver/arch-armv7k.c
+++ b/test/Driver/arch-armv7k.c
@@ -1,5 +1,14 @@
-// Tests that make sure armv7k is mapped to the correct CPU
+// Tests that make sure armv7k is mapped to the correct CPU and ABI choices
// RUN: %clang -target x86_64-apple-macosx10.9 -arch armv7k -c %s -### 2>&1 | FileCheck %s
// CHECK: "-cc1"{{.*}} "-target-cpu" "cortex-a7"
// CHECK-NOT: "-fsjlj-exceptions"
+
+// "thumbv7k-apple-ios" is a bit of a weird triple, but since the backend is
+// going to choose to use dwarf-based exceptions for it, the front-end needs to
+// match.
+
+// RUN: %clang -target x86_64-apple-macosx10.9 -arch armv7k -miphoneos-version-min=9.0 -c %s -### 2>&1 | FileCheck %s
+
+// RUN: %clang -target x86_64-apple-macosx10.9 -arch armv7 -mwatchos-version-min=9.0 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SJLJ
+// CHECK-SJLJ: "-fsjlj-exceptions"
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index b2103e2..6a4d2d6 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -57,11 +57,11 @@
// FIXME %clang -target armv6j -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6J %s
// RUN: %clang -target arm -march=armv6j -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6J %s
-// CHECK-V6J: "-cc1"{{.*}} "-triple" "armv6-{{.*}} "-target-cpu" "arm1136j-s"
+// CHECK-V6J: "-cc1"{{.*}} "-triple" "armv6-{{.*}} "-target-cpu" "arm1136jf-s"
// FIXME %clang -target armv6j -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6J-THUMB %s
// RUN: %clang -target arm -march=armv6j -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6J-THUMB %s
-// CHECK-V6J-THUMB: "-cc1"{{.*}} "-triple" "thumbv6-{{.*}} "-target-cpu" "arm1136j-s"
+// CHECK-V6J-THUMB: "-cc1"{{.*}} "-triple" "thumbv6-{{.*}} "-target-cpu" "arm1136jf-s"
// FIXME %clang -target armv6z -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6Z %s
// FIXME %clang -target arm -march=armv6z -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6Z %s
@@ -73,11 +73,11 @@
// RUN: %clang -target armv6k -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6K %s
// RUN: %clang -target arm -march=armv6k -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6K %s
-// CHECK-V6K: "-cc1"{{.*}} "-triple" "armv6k-{{.*}} "-target-cpu" "arm1176jzf-s"
+// CHECK-V6K: "-cc1"{{.*}} "-triple" "armv6k-{{.*}} "-target-cpu" "arm1176j-s"
// RUN: %clang -target armv6k -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6K-THUMB %s
// RUN: %clang -target arm -march=armv6k -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6K-THUMB %s
-// CHECK-V6K-THUMB: "-cc1"{{.*}} "-triple" "thumbv6k-{{.*}} "-target-cpu" "arm1176jzf-s"
+// CHECK-V6K-THUMB: "-cc1"{{.*}} "-triple" "thumbv6k-{{.*}} "-target-cpu" "arm1176j-s"
// RUN: %clang -target armv6t2 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6T2 %s
// RUN: %clang -target arm -march=armv6t2 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6T2 %s
@@ -249,12 +249,14 @@
// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1136jf-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6 %s
// CHECK-CPUV6: "-cc1"{{.*}} "-triple" "armv6-{{.*}}
-// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1176jz-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6K %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1176jzf-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6K %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=mpcore -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6K %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=mpcorenovfp -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6K %s
// CHECK-CPUV6K: "-cc1"{{.*}} "-triple" "armv6k-{{.*}}
+// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1176jz-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6KZ %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1176jzf-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6KZ %s
+// CHECK-CPUV6KZ: "-cc1"{{.*}} "-triple" "armv6kz-{{.*}}
+
// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1156t2-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6T2 %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=arm1156t2f-s -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6T2 %s
// CHECK-CPUV6T2: "-cc1"{{.*}} "-triple" "armv6t2-{{.*}}
@@ -392,36 +394,52 @@
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// CHECK-BE-CPUV7R-THUMB: "-cc1"{{.*}} "-triple" "thumbebv7r-{{.*}}
+// RUN: %clang -target arm -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a35 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a53 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a72 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// CHECK-CPUV8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}
+// RUN: %clang -target armeb -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
+// RUN: %clang -target armeb -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a35 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a53 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a72 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// CHECK-BE-CPUV8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}
+// RUN: %clang -target arm -mcpu=cortex-a35 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a53 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a72 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a35 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a53 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a72 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// CHECK-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}
+// RUN: %clang -target armeb -mcpu=cortex-a35 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a53 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a57 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a72 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
+// RUN: %clang -target armeb -mcpu=exynos-m1 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a35 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a53 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a72 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=exynos-m1 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// CHECK-BE-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}
// ================== Check whether -mcpu accepts mixed-case values.
diff --git a/test/Driver/arm-features.c b/test/Driver/arm-features.c
new file mode 100644
index 0000000..eb197da
--- /dev/null
+++ b/test/Driver/arm-features.c
@@ -0,0 +1,13 @@
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic+crc -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CRC %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic -march=armv8a+crc -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CRC %s
+// CHECK-CRC: "-cc1"{{.*}} "-triple" "armv8-{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+crc"
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic+crypto -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CRYPTO %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic -march=armv8a+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CRYPTO %s
+// CHECK-CRYPTO: "-cc1"{{.*}} "-triple" "armv8-{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+crypto"
+
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic+nocrc -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-NOCRC %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic -march=armv8a+nocrc -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-NOCRC %s
+// CHECK-NOCRC: "-cc1"{{.*}} "-triple" "armv8-{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "-crc"
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic+nocrypto -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-NOCRYPTO %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=generic -march=armv8a+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-NOCRYPTO %s
+// CHECK-NOCRYPTO: "-cc1"{{.*}} "-triple" "armv8-{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "-crypto"
diff --git a/test/Driver/arm-multilibs.c b/test/Driver/arm-multilibs.c
new file mode 100644
index 0000000..bd9c80e
--- /dev/null
+++ b/test/Driver/arm-multilibs.c
@@ -0,0 +1,17 @@
+// RUN: %clang -target armv7-linux-gnueabi --sysroot=%S/Inputs/multilib_arm_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARM %s
+// RUN: %clang -target thumbv7-linux-gnueabi --sysroot=%S/Inputs/multilib_arm_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARM %s
+
+// RUN: %clang -target armv7-linux-gnueabihf --sysroot=%S/Inputs/multilib_armhf_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMHF %s
+// RUN: %clang -target thumbv7-linux-gnueabihf --sysroot=%S/Inputs/multilib_armhf_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMHF %s
+
+// RUN: %clang -target armv7eb-linux-gnueabi --sysroot=%S/Inputs/multilib_armeb_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMEB %s
+// RUN: %clang -target thumbv7eb-linux-gnueabi --sysroot=%S/Inputs/multilib_armeb_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMEB %s
+
+// RUN: %clang -target armv7eb-linux-gnueabihf --sysroot=%S/Inputs/multilib_armebhf_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMEBHF %s
+// RUN: %clang -target thumbv7eb-linux-gnueabihf --sysroot=%S/Inputs/multilib_armebhf_linux_tree -### -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-ARMEBHF %s
+
+// CHECK-ARM: "-internal-externc-isystem" "{{.*}}/usr/include/arm-linux-gnueabi"
+// CHECK-ARMHF: "-internal-externc-isystem" "{{.*}}/usr/include/arm-linux-gnueabihf"
+// CHECK-ARMEB: "-internal-externc-isystem" "{{.*}}/usr/include/armeb-linux-gnueabi"
+// CHECK-ARMEBHF: "-internal-externc-isystem" "{{.*}}/usr/include/armeb-linux-gnueabihf"
+
diff --git a/test/Driver/arm-no-movt.c b/test/Driver/arm-no-movt.c
index 9684d0e..6908593 100644
--- a/test/Driver/arm-no-movt.c
+++ b/test/Driver/arm-no-movt.c
@@ -4,6 +4,11 @@
// RUN: %clang -target armv7-apple-darwin -mkernel -### %s 2>&1 \
// RUN: | FileCheck %s -check-prefix CHECK-KERNEL
+// RUN: %clang -target armv7-none-gnueabi -mno-movt -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-MOVT
+
// CHECK-DEFAULT-NOT: "-target-feature" "+no-movt"
// CHECK-KERNEL: "-target-feature" "+no-movt"
+
+// CHECK-NO-MOVT: "-target-feature" "+no-movt"
diff --git a/test/Driver/arm-xscale.c b/test/Driver/arm-xscale.c
new file mode 100644
index 0000000..9b00b83
--- /dev/null
+++ b/test/Driver/arm-xscale.c
@@ -0,0 +1,3 @@
+// RUN: %clang -target arm-freebsd -mcpu=xscale -### -c %s 2>&1 | FileCheck %s
+// CHECK-NOT: error: the clang compiler does not support '-mcpu=xscale'
+// CHECK: "-cc1"{{.*}} "-target-cpu" "xscale"{{.*}}
diff --git a/test/Driver/biarch.c b/test/Driver/biarch.c
index 18825f4..c2b2e4e 100644
--- a/test/Driver/biarch.c
+++ b/test/Driver/biarch.c
@@ -1,44 +1,33 @@
-// RUN: %clang -target i386--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "i386--netbsd"' %t
+// RUN: %clang -target i386--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=I386 %s
+// RUN: %clang -target x86_64--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=I386 %s
+// I386: "-cc1" "-triple" "i386--netbsd"
-// RUN: %clang -target i386--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "x86_64--netbsd"' %t
+// RUN: %clang -target i386--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=X86_64 %s
+// RUN: %clang -target x86_64--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=X86_64 %s
+// X86_64: "-cc1" "-triple" "x86_64--netbsd"
-// RUN: %clang -target x86_64--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "i386--netbsd"' %t
+// r196538 set arm1176jzf-s as default CPU for ARMv6 on NetBSD
+// RUN: %clang -target armv6--netbsd-eabihf -m32 %s -### 2>&1 | FileCheck -check-prefix=ARMV6 %s
+// ARMV6: "-cc1" "-triple" "armv6kz--netbsd-eabihf"
-// RUN: %clang -target x86_64--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "x86_64--netbsd"' %t
+// RUN: %clang -target sparcv9--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=SPARC %s
+// RUN: %clang -target sparc--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=SPARC %s
+// SPARC: "-cc1" "-triple" "sparc--netbsd"
-// RUN: %clang -target armv6--netbsd-eabihf -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "armv6k--netbsd-eabihf"' %t
+// RUN: %clang -target sparcv9--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=SPARCV9 %s
+// RUN: %clang -target sparc--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=SPARCV9 %s
+// SPARCV9: "-cc1" "-triple" "sparcv9--netbsd"
-// RUN: %clang -target sparcv9--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "sparc--netbsd"' %t
+// RUN: %clang -target sparc64--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=SPARC64 %s
+// SPARC64: "-cc1" "-triple" "sparc64--netbsd"
-// RUN: %clang -target sparcv9--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "sparcv9--netbsd"' %t
+// RUN: %clang -target sparcel -o foo %s -### 2>&1 | FileCheck -check-prefix=SPARCEL %s
+// SPARCEL: gcc{{(\.exe)?}}" "-EL" "-o" "foo"
-// RUN: %clang -target sparc64--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "sparc64--netbsd"' %t
+// RUN: %clang -target mips64--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=MIPS %s
+// RUN: %clang -target mips--netbsd -m32 %s -### 2>&1 | FileCheck -check-prefix=MIPS %s
+// MIPS: "-cc1" "-triple" "mips--netbsd"
-// RUN: %clang -target sparc--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "sparc--netbsd"' %t
-
-// RUN: %clang -target sparc--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "sparcv9--netbsd"' %t
-
-// RUN: %clang -target sparcel -o foo %s -### 2> %t
-// RUN: grep 'gcc\(\.exe\)\?" "-EL" "-o" "foo"' %t
-
-// RUN: %clang -target mips64--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "mips--netbsd"' %t
-
-// RUN: %clang -target mips64--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "mips64--netbsd"' %t
-
-// RUN: %clang -target mips--netbsd -m32 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "mips--netbsd"' %t
-
-// RUN: %clang -target mips--netbsd -m64 %s -### 2> %t
-// RUN: grep '"-cc1" "-triple" "mips64--netbsd"' %t
+// RUN: %clang -target mips64--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=MIPS64 %s
+// RUN: %clang -target mips--netbsd -m64 %s -### 2>&1 | FileCheck -check-prefix=MIPS64 %s
+// MIPS64: "-cc1" "-triple" "mips64--netbsd"
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 180b15e..c5985a9 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -14,9 +14,14 @@
// C_P: "-E"
// C_P: "-C"
-// RUN: %clang_cl /Dfoo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
-// RUN: %clang_cl /D foo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
+// RUN: %clang_cl /Dfoo=bar /D bar=baz /DMYDEF#value /DMYDEF2=foo#bar /DMYDEF3#a=b /DMYDEF4# \
+// RUN: -### -- %s 2>&1 | FileCheck -check-prefix=D %s
// D: "-D" "foo=bar"
+// D: "-D" "bar=baz"
+// D: "-D" "MYDEF=value"
+// D: "-D" "MYDEF2=foo#bar"
+// D: "-D" "MYDEF3=a=b"
+// D: "-D" "MYDEF4="
// RUN: %clang_cl /E -### -- %s 2>&1 | FileCheck -check-prefix=E %s
// E: "-E"
@@ -173,9 +178,10 @@
// RUN: %clang_cl /W1 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
// RUN: %clang_cl /W2 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
// RUN: %clang_cl /W3 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
-// RUN: %clang_cl /W4 -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
-// RUN: %clang_cl /Wall -### -- %s 2>&1 | FileCheck -check-prefix=W1 %s
+// RUN: %clang_cl /W4 -### -- %s 2>&1 | FileCheck -check-prefix=W4 %s
+// RUN: %clang_cl /Wall -### -- %s 2>&1 | FileCheck -check-prefix=W4 %s
// W1: -Wall
+// W4: -WCL4
// RUN: %clang_cl /WX -### -- %s 2>&1 | FileCheck -check-prefix=WX %s
// WX: -Werror
@@ -215,11 +221,12 @@
// NOSTRICT: "-relaxed-aliasing"
// For some warning ids, we can map from MSVC warning to Clang warning.
-// RUN: %clang_cl -wd4005 -wd4996 -wd4910 -### -- %s 2>&1 | FileCheck -check-prefix=Wno %s
+// RUN: %clang_cl -wd4005 -wd4100 -wd4910 -wd4996 -### -- %s 2>&1 | FileCheck -check-prefix=Wno %s
// Wno: "-cc1"
// Wno: "-Wno-macro-redefined"
-// Wno: "-Wno-deprecated-declarations"
+// Wno: "-Wno-unused-parameter"
// Wno: "-Wno-dllexport-explicit-instantiation-decl"
+// Wno: "-Wno-deprecated-declarations"
// Ignored options. Check that we don't get "unused during compilation" errors.
// RUN: %clang_cl /c \
@@ -374,6 +381,15 @@
// Z7: "-gcodeview"
// Z7: "-debug-info-kind=line-tables-only"
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=BreproDefault %s
+// BreproDefault: "-mincremental-linker-compatible"
+
+// RUN: %clang_cl /Brepro- /Brepro /c '-###' -- %s 2>&1 | FileCheck -check-prefix=Brepro %s
+// Brepro: "-mincremental-linker-compatible"
+
+// RUN: %clang_cl /Brepro /Brepro- /c '-###' -- %s 2>&1 | FileCheck -check-prefix=Brepro_ %s
+// Brepro_-NOT: "-mincremental-linker-compatible"
+
// This test was super sneaky: "/Z7" means "line-tables", but "-gdwarf" occurs
// later on the command line, so it should win. Interestingly the cc1 arguments
// came out right, but had wrong semantics, because an invariant assumed by
diff --git a/test/Driver/crash-report-modules.m b/test/Driver/crash-report-modules.m
index 0e1d81a..16af75c 100644
--- a/test/Driver/crash-report-modules.m
+++ b/test/Driver/crash-report-modules.m
@@ -1,9 +1,9 @@
// RUN: rm -rf %t
-// RUN: mkdir %t
+// RUN: mkdir -p %t/i %t/m %t
// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \
-// RUN: %clang -fsyntax-only %s -I %S/Inputs/module -isysroot /tmp/ \
-// RUN: -fmodules -fmodules-cache-path=/tmp/ -DFOO=BAR 2>&1 | FileCheck %s
+// RUN: %clang -fsyntax-only %s -I %S/Inputs/module -isysroot %/t/i/ \
+// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | FileCheck %s
// RUN: FileCheck --check-prefix=CHECKSRC %s -input-file %t/crash-report-*.m
// RUN: FileCheck --check-prefix=CHECKSH %s -input-file %t/crash-report-*.sh
@@ -30,8 +30,8 @@
// CHECKSH-SAME: "-D" "FOO=BAR"
// CHECKSH-NEXT: # Original command: {{.*$}}
// CHECKSH-NEXT: "-cc1"
-// CHECKSH: "-isysroot" "/tmp/"
+// CHECKSH: "-isysroot" "{{[^"]*}}/i/"
// CHECKSH: "-D" "FOO=BAR"
-// CHECKSH-NOT: "-fmodules-cache-path=/tmp/"
+// CHECKSH-NOT: "-fmodules-cache-path="
// CHECKSH: "crash-report-modules-{{[^ ]*}}.m"
// CHECKSH: "-ivfsoverlay" "crash-report-modules-{{[^ ]*}}.cache/vfs/vfs.yaml"
diff --git a/test/Driver/cuda-arch-translation.cu b/test/Driver/cuda-arch-translation.cu
new file mode 100644
index 0000000..64ddb31
--- /dev/null
+++ b/test/Driver/cuda-arch-translation.cu
@@ -0,0 +1,37 @@
+// Tests that "sm_XX" gets correctly converted to "compute_YY" when we invoke
+// fatbinary.
+//
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// CHECK:fatbinary
+
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_20 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_21 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM21 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_30 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM30 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_32 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM32 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_35 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM35 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_37 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM37 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_50 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM50 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_52 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM52 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_53 %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM53 %s
+
+// SM20:--image=profile=sm_20{{.*}}--image=profile=compute_20
+// SM21:--image=profile=sm_21{{.*}}--image=profile=compute_20
+// SM30:--image=profile=sm_30{{.*}}--image=profile=compute_30
+// SM32:--image=profile=sm_32{{.*}}--image=profile=compute_32
+// SM35:--image=profile=sm_35{{.*}}--image=profile=compute_35
+// SM37:--image=profile=sm_37{{.*}}--image=profile=compute_37
+// SM50:--image=profile=sm_50{{.*}}--image=profile=compute_50
+// SM52:--image=profile=sm_52{{.*}}--image=profile=compute_52
+// SM53:--image=profile=sm_53{{.*}}--image=profile=compute_53
diff --git a/test/Driver/cuda-bad-arch.cu b/test/Driver/cuda-bad-arch.cu
new file mode 100644
index 0000000..f92bdce
--- /dev/null
+++ b/test/Driver/cuda-bad-arch.cu
@@ -0,0 +1,22 @@
+// Checks errors generated by passing a bad value for --cuda-gpu-arch.
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=compute_20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_19 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+
+// BAD: error: Unsupported CUDA gpu architecture
+
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_52 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+// RUN: %clang -### -target x86_64-linux-gnu -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+
+// OK-NOT: error: Unsupported CUDA gpu architecture
diff --git a/test/Driver/cuda-detect.cu b/test/Driver/cuda-detect.cu
index 31e8494..d8fba06 100644
--- a/test/Driver/cuda-detect.cu
+++ b/test/Driver/cuda-detect.cu
@@ -1,10 +1,64 @@
// REQUIRES: clang-driver
// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
//
+// # Check that we properly detect CUDA installation.
// RUN: %clang -v --target=i386-unknown-linux \
-// RUN: --sysroot=/tmp/no-cuda-there 2>&1 | FileCheck %s -check-prefix NOCUDA
+// RUN: --sysroot=%S/no-cuda-there 2>&1 | FileCheck %s -check-prefix NOCUDA
+// RUN: %clang -v --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/CUDA 2>&1 | FileCheck %s
// RUN: %clang -v --target=i386-unknown-linux \
// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 | FileCheck %s
+// Make sure we map libdevice bitcode files to proper GPUs.
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_21 \
+// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON \
+// RUN: -check-prefix LIBDEVICE -check-prefix LIBDEVICE21
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_35 \
+// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON -check-prefix CUDAINC \
+// RUN: -check-prefix LIBDEVICE -check-prefix LIBDEVICE35
+// Verify that -nocudainc prevents adding include path to CUDA headers.
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_35 \
+// RUN: -nocudainc --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON -check-prefix NOCUDAINC \
+// RUN: -check-prefix LIBDEVICE -check-prefix LIBDEVICE35
+// We should not add any CUDA include paths if there's no valid CUDA installation
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_35 \
+// RUN: --cuda-path=%S/no-cuda-there %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON -check-prefix NOCUDAINC
+
+// Verify that no options related to bitcode linking are passes if
+// there's no bitcode file.
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_30 \
+// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON -check-prefix NOLIBDEVICE
+// .. or if we explicitly passed -nocudalib
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_35 \
+// RUN: -nocudalib --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON -check-prefix NOLIBDEVICE
+// Verify that we don't add include paths, link with libdevice or
+// -include __clang_cuda_runtime_wrapper.h without valid CUDA installation.
+// RUN: %clang -### -v --target=i386-unknown-linux --cuda-gpu-arch=sm_35 \
+// RUN: --cuda-path=%S/no-cuda-there %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix COMMON \
+// RUN: -check-prefix NOCUDAINC -check-prefix NOLIBDEVICE
+
// CHECK: Found CUDA installation: {{.*}}/Inputs/CUDA/usr/local/cuda
// NOCUDA-NOT: Found CUDA installation:
+
+// COMMON: "-triple" "nvptx-nvidia-cuda"
+// COMMON-SAME: "-fcuda-is-device"
+// LIBDEVICE-SAME: "-mlink-cuda-bitcode"
+// NOLIBDEVICE-NOT: "-mlink-cuda-bitcode"
+// LIBDEVICE21-SAME: libdevice.compute_20.10.bc
+// LIBDEVICE35-SAME: libdevice.compute_35.10.bc
+// NOLIBDEVICE-NOT: libdevice.compute_{{.*}}.bc
+// LIBDEVICE-SAME: "-target-feature" "+ptx42"
+// NOLIBDEVICE-NOT: "-target-feature" "+ptx42"
+// CUDAINC-SAME: "-internal-isystem" "{{.*}}/Inputs/CUDA/usr/local/cuda/include"
+// NOCUDAINC-NOT: "-internal-isystem" "{{.*}}/cuda/include"
+// CUDAINC-SAME: "-include" "__clang_cuda_runtime_wrapper.h"
+// NOCUDAINC-NOT: "-include" "__clang_cuda_runtime_wrapper.h"
+// COMMON-SAME: "-x" "cuda"
diff --git a/test/Driver/cuda-external-tools.cu b/test/Driver/cuda-external-tools.cu
new file mode 100644
index 0000000..801b491
--- /dev/null
+++ b/test/Driver/cuda-external-tools.cu
@@ -0,0 +1,70 @@
+// Tests that ptxas and fatbinary are correctly during CUDA compilation.
+//
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// Regular compile with -O2.
+// RUN: %clang -### -target x86_64-linux-gnu -O2 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 -check-prefix OPT2 %s
+
+// Regular compile without -O. This should result in us passing -O0 to ptxas.
+// RUN: %clang -### -target x86_64-linux-gnu -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 -check-prefix OPT0 %s
+
+// Regular compile targeting sm_35.
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_35 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM35 %s
+
+// 32-bit compile.
+// RUN: %clang -### -target x86_32-linux-gnu -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH32 -check-prefix SM20 %s
+
+// Compile with -fintegrated-as. This should still cause us to invoke ptxas.
+// RUN: %clang -### -target x86_64-linux-gnu -fintegrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 -check-prefix OPT0 %s
+
+// Check -Xcuda-ptxas and -Xcuda-fatbinary
+// RUN: %clang -### -target x86_64-linux-gnu -c -Xcuda-ptxas -foo1 \
+// RUN: -Xcuda-fatbinary -bar1 -Xcuda-ptxas -foo2 -Xcuda-fatbinary -bar2 %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM20 -check-prefix PTXAS-EXTRA \
+// RUN: -check-prefix FATBINARY-EXTRA %s
+
+// Match clang job that produces PTX assembly.
+// CHECK: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// SM20: "-target-cpu" "sm_20"
+// SM35: "-target-cpu" "sm_35"
+// SM20: "-o" "[[PTXFILE:[^"]*]]"
+// SM35: "-o" "[[PTXFILE:[^"]*]]"
+
+// Match the call to ptxas (which assembles PTX to SASS).
+// CHECK:ptxas
+// ARCH64: "-m64"
+// ARCH32: "-m32"
+// OPT0: "-O0"
+// OPT2: "-O2"
+// SM20: "--gpu-name" "sm_20"
+// SM35: "--gpu-name" "sm_35"
+// SM20: "--output-file" "[[CUBINFILE:[^"]*]]"
+// SM35: "--output-file" "[[CUBINFILE:[^"]*]]"
+// PTXAS-EXTRA: "-foo1"
+// PTXAS-EXTRA-SAME: "-foo2"
+// CHECK-SAME: "[[PTXFILE]]"
+
+// Match the call to fatbinary (which combines all our PTX and SASS into one
+// blob).
+// CHECK:fatbinary
+// CHECK-DAG: "--cuda"
+// ARCH64-DAG: "-64"
+// ARCH32-DAG: "-32"
+// CHECK-DAG: "--create" "[[FATBINARY:[^"]*]]"
+// SM20-DAG: "--image=profile=compute_20,file=[[PTXFILE]]"
+// SM35-DAG: "--image=profile=compute_35,file=[[PTXFILE]]"
+// SM20-DAG: "--image=profile=sm_20,file=[[CUBINFILE]]"
+// SM35-DAG: "--image=profile=sm_35,file=[[CUBINFILE]]"
+// FATBINARY-EXTRA: "-bar1"
+// FATBINARY-EXTRA-SAME: "-bar2"
+
+// Match the clang job for host compilation.
+// CHECK: "-cc1" "-triple" "x86_64--linux-gnu"
+// CHECK-SAME: "-fcuda-include-gpubinary" "[[FATBINARY]]"
diff --git a/test/Driver/cuda-options.cu b/test/Driver/cuda-options.cu
index 23ba296..9030090 100644
--- a/test/Driver/cuda-options.cu
+++ b/test/Driver/cuda-options.cu
@@ -3,188 +3,143 @@
// REQUIRES: x86-registered-target
// REQUIRES: nvptx-registered-target
-// Simple compilation case:
+// Simple compilation case. Compile device-side to PTX assembly and make sure
+// we use it on the host side.
// RUN: %clang -### -target x86_64-linux-gnu -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix NOLINK %s
-// Typical compilation + link case:
+// Typical compilation + link case.
// RUN: %clang -### -target x86_64-linux-gnu %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Then link things.
-// RUN: -check-prefix CUDA-L %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix LINK %s
-// Verify that --cuda-host-only disables device-side compilation and linking
+// Verify that --cuda-host-only disables device-side compilation, but doesn't
+// disable host-side compilation/linking.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only %s 2>&1 \
-// Make sure we didn't run device-side compilation.
-// RUN: | FileCheck -check-prefix CUDA-ND \
-// Then compile host side and make sure we don't attempt to incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-NI \
-// Linking is allowed to happen, even if we're missing GPU code.
-// RUN: -check-prefix CUDA-L %s
+// RUN: | FileCheck -check-prefix NODEVICE -check-prefix HOST \
+// RUN: -check-prefix NOINCLUDES-DEVICE -check-prefix LINK %s
-// Same test as above, but with preceeding --cuda-device-only to make
-// sure only last option has effect.
+// Same test as above, but with preceeding --cuda-device-only to make sure only
+// the last option has an effect.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only --cuda-host-only %s 2>&1 \
-// Make sure we didn't run device-side compilation.
-// RUN: | FileCheck -check-prefix CUDA-ND \
-// Then compile host side and make sure we don't attempt to incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-NI \
-// Linking is allowed to happen, even if we're missing GPU code.
-// RUN: -check-prefix CUDA-L %s
+// RUN: | FileCheck -check-prefix NODEVICE -check-prefix HOST \
+// RUN: -check-prefix NOINCLUDES-DEVICE -check-prefix LINK %s
-// Verify that --cuda-device-only disables host-side compilation and linking
+// Verify that --cuda-device-only disables host-side compilation and linking.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Make sure there are no host cmpilation or linking.
-// RUN: -check-prefix CUDA-NH -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix NOHOST -check-prefix NOLINK %s
-// Same test as above, but with preceeding --cuda-host-only to make
-// sure only last option has effect.
+// Same test as above, but with preceeding --cuda-host-only to make sure only
+// the last option has an effect.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only --cuda-device-only %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Make sure there are no host cmpilation or linking.
-// RUN: -check-prefix CUDA-NH -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix NOHOST -check-prefix NOLINK %s
-// Verify that with -S we compile host and device sides to assembly
-// and incorporate device code on the host side.
-// RUN: %clang -### -target x86_64-linux-gnu -S -c %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Verify that --cuda-gpu-arch option passes correct GPU
-// archtecture info to device compilation.
+// Verify that --cuda-gpu-arch option passes the correct GPU archtecture to
+// device compilation.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_35 -c %s 2>&1 \
-// Compile device-side to PTX assembly.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS \
-// RUN: -check-prefix CUDA-D1-SM35 \
-// Then compile host side and incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix DEVICE-SM35 -check-prefix HOST \
+// RUN: -check-prefix INCLUDES-DEVICE -check-prefix NOLINK %s
-// Verify that there is device-side compilation per --cuda-gpu-arch args
+// Verify that there is one device-side compilation per --cuda-gpu-arch args
// and that all results are included on the host side.
// RUN: %clang -### -target x86_64-linux-gnu \
-// RUN: --cuda-gpu-arch=sm_35 --cuda-gpu-arch=sm_30 -c %s 2>&1 \
-// Compile both device-sides to PTX assembly
-// RUN: | FileCheck \
-// RUN: -check-prefix CUDA-D1 -check-prefix CUDA-D1NS -check-prefix CUDA-D1-SM35 \
-// RUN: -check-prefix CUDA-D2 -check-prefix CUDA-D2-SM30 \
-// Then compile host side and incorporate both device-side outputs
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HNS \
-// RUN: -check-prefix CUDA-H-I1 -check-prefix CUDA-H-I2 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
+// RUN: --cuda-gpu-arch=sm_35 --cuda-gpu-arch=sm_30 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix DEVICE2 -check-prefix DEVICE-SM35 \
+// RUN: -check-prefix DEVICE2-SM30 -check-prefix HOST \
+// RUN: -check-prefix HOST-NOSAVE -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix NOLINK %s
-// Verify that device-side results are passed to correct tool when
-// -save-temps is used
+// Verify that device-side results are passed to the correct tool when
+// -save-temps is used.
// RUN: %clang -### -target x86_64-linux-gnu -save-temps -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1S \
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HS -check-prefix CUDA-HS-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-SAVE \
+// RUN: -check-prefix HOST -check-prefix HOST-SAVE -check-prefix NOLINK %s
-// Verify that device-side results are passed to correct tool when
-// -fno-integrated-as is used
+// Verify that device-side results are passed to the correct tool when
+// -fno-integrated-as is used.
// RUN: %clang -### -target x86_64-linux-gnu -fno-integrated-as -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS \
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HNS -check-prefix CUDA-HS-I1 \
-// RUN: -check-prefix CUDA-H-AS \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix HOST-NOSAVE \
+// RUN: -check-prefix HOST-AS -check-prefix NOLINK %s
-// Match device-side preprocessor, and compiler phases with -save-temps
-// CUDA-D1S: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-D1S-SAME: "-fcuda-is-device"
-// CUDA-D1S-SAME: "-x" "cuda"
-// CUDA-D1S: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-D1S-SAME: "-fcuda-is-device"
-// CUDA-D1S-SAME: "-x" "cuda-cpp-output"
+// Match device-side preprocessor and compiler phases with -save-temps.
+// DEVICE-SAVE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-SAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAVE-SAME: "-fcuda-is-device"
+// DEVICE-SAVE-SAME: "-x" "cuda"
-// --cuda-host-only should never trigger unused arg warning.
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CHO %s
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -x c -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CHO %s
+// DEVICE-SAVE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-SAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAVE-SAME: "-fcuda-is-device"
+// DEVICE-SAVE-SAME: "-x" "cuda-cpp-output"
-// --cuda-device-only should not produce warning compiling CUDA files
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CDO %s
+// Match the job that produces PTX assembly.
+// DEVICE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-NOSAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAME: "-fcuda-is-device"
+// DEVICE-SM35-SAME: "-target-cpu" "sm_35"
+// DEVICE-SAME: "-o" "[[PTXFILE:[^"]*]]"
+// DEVICE-NOSAVE-SAME: "-x" "cuda"
+// DEVICE-SAVE-SAME: "-x" "ir"
-// --cuda-device-only should warn during non-CUDA compilation.
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -x c -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-UNUSED-CDO %s
+// Match the call to ptxas (which assembles PTX to SASS).
+// DEVICE:ptxas
+// DEVICE-SM35-DAG: "--gpu-name" "sm_35"
+// DEVICE-DAG: "--output-file" "[[CUBINFILE:[^"]*]]"
+// DEVICE-DAG: "[[PTXFILE]]"
-// Match the job that produces PTX assembly
-// CUDA-D1: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-D1-SAME: "-fcuda-is-device"
-// CUDA-D1-SM35-SAME: "-target-cpu" "sm_35"
-// CUDA-D1-SAME: "-o" "[[GPUBINARY1:[^"]*]]"
-// CUDA-D1NS-SAME: "-x" "cuda"
-// CUDA-D1S-SAME: "-x" "ir"
+// Match another device-side compilation.
+// DEVICE2: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE2-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE2-SAME: "-fcuda-is-device"
+// DEVICE2-SM30-SAME: "-target-cpu" "sm_30"
+// DEVICE2-SAME: "-o" "[[GPUBINARY2:[^"]*]]"
+// DEVICE2-SAME: "-x" "cuda"
-// Match anothe device-side compilation
-// CUDA-D2: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-D2-SAME: "-fcuda-is-device"
-// CUDA-D2-SM30-SAME: "-target-cpu" "sm_30"
-// CUDA-D2-SAME: "-o" "[[GPUBINARY2:[^"]*]]"
-// CUDA-D2-SAME: "-x" "cuda"
+// Match no device-side compilation.
+// NODEVICE-NOT: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// NODEVICE-SAME-NOT: "-fcuda-is-device"
-// Match no device-side compilation
-// CUDA-ND-NOT: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-ND-SAME-NOT: "-fcuda-is-device"
+// INCLUDES-DEVICE:fatbinary
+// INCLUDES-DEVICE-DAG: "--create" "[[FATBINARY:[^"]*]]"
+// INCLUDES-DEVICE-DAG: "--image=profile=sm_{{[0-9]+}},file=[[CUBINFILE]]"
+// INCLUDES-DEVICE-DAG: "--image=profile=compute_{{[0-9]+}},file=[[PTXFILE]]"
-// Match host-side preprocessor job with -save-temps
-// CUDA-HS: "-cc1" "-triple"
-// CUDA-HS-SAME-NOT: "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-HS-SAME-NOT: "-fcuda-is-device"
-// CUDA-HS-SAME: "-x" "cuda"
+// Match host-side preprocessor job with -save-temps.
+// HOST-SAVE: "-cc1" "-triple" "x86_64--linux-gnu"
+// HOST-SAVE-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
+// HOST-SAVE-SAME-NOT: "-fcuda-is-device"
+// HOST-SAVE-SAME: "-x" "cuda"
-// Match host-side compilation
-// CUDA-H: "-cc1" "-triple"
-// CUDA-H-SAME-NOT: "nvptx{{(64)?}}-nvidia-cuda"
-// CUDA-H-SAME-NOT: "-fcuda-is-device"
-// CUDA-H-SAME: "-o" "[[HOSTOUTPUT:[^"]*]]"
-// CUDA-HNS-SAME: "-x" "cuda"
-// CUDA-HS-SAME: "-x" "cuda-cpp-output"
-// CUDA-H-I1-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY1]]"
-// CUDA-H-I2-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY2]]"
+// Match host-side compilation.
+// HOST: "-cc1" "-triple" "x86_64--linux-gnu"
+// HOST-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
+// HOST-SAME-NOT: "-fcuda-is-device"
+// HOST-SAME: "-o" "[[HOSTOUTPUT:[^"]*]]"
+// HOST-NOSAVE-SAME: "-x" "cuda"
+// HOST-SAVE-SAME: "-x" "cuda-cpp-output"
+// INCLUDES-DEVICE-SAME: "-fcuda-include-gpubinary" "[[FATBINARY]]"
-// Match external assembler that uses compilation output
-// CUDA-H-AS: "-o" "{{.*}}.o" "[[HOSTOUTPUT]]"
+// Match external assembler that uses compilation output.
+// HOST-AS: "-o" "{{.*}}.o" "[[HOSTOUTPUT]]"
// Match no GPU code inclusion.
-// CUDA-H-NI-NOT: "-fcuda-include-gpubinary"
+// NOINCLUDES-DEVICE-NOT: "-fcuda-include-gpubinary"
-// Match no CUDA compilation
-// CUDA-NH-NOT: "-cc1" "-triple"
-// CUDA-NH-SAME-NOT: "-x" "cuda"
+// Match no host compilation.
+// NOHOST-NOT: "-cc1" "-triple"
+// NOHOST-SAME-NOT: "-x" "cuda"
-// Match linker
-// CUDA-L: "{{.*}}{{ld|link}}{{(.exe)?}}"
-// CUDA-L-SAME: "[[HOSTOUTPUT]]"
+// Match linker.
+// LINK: "{{.*}}{{ld|link}}{{(.exe)?}}"
+// LINK-SAME: "[[HOSTOUTPUT]]"
-// Match no linker
-// CUDA-NL-NOT: "{{.*}}{{ld|link}}{{(.exe)?}}"
-
-// CUDA-NO-UNUSED-CHO-NOT: warning: argument unused during compilation: '--cuda-host-only'
-// CUDA-UNUSED-CDO: warning: argument unused during compilation: '--cuda-device-only'
-// CUDA-NO-UNUSED-CDO-NOT: warning: argument unused during compilation: '--cuda-device-only'
+// Match no linker.
+// NOLINK-NOT: "{{.*}}{{ld|link}}{{(.exe)?}}"
diff --git a/test/Driver/cuda-output-asm.cu b/test/Driver/cuda-output-asm.cu
new file mode 100644
index 0000000..af62478
--- /dev/null
+++ b/test/Driver/cuda-output-asm.cu
@@ -0,0 +1,29 @@
+// Tests CUDA compilation with -S.
+
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// RUN: %clang -### -S -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 %s 2>&1 \
+// RUN: | FileCheck -check-prefix HOST -check-prefix SM20 %s
+// RUN: %clang -### -S -target x86_64-linux-gnu --cuda-host-only -o foo.s %s 2>&1 \
+// RUN: | FileCheck -check-prefix HOST %s
+// RUN: %clang -### -S -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 \
+// RUN: --cuda-device-only -o foo.s %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM20 %s
+// RUN: %clang -### -S -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 \
+// RUN: --cuda-gpu-arch=sm_30 --cuda-device-only %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM20 -check-prefix SM30 %s
+
+// HOST-DAG: "-cc1" "-triple" "x86_64--linux-gnu"
+// SM20-DAG: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// SM20-same: "-target-cpu" "sm_20"
+// SM30-DAG: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// SM30-same: "-target-cpu" "sm_30"
+
+// RUN: %clang -### -S -target x86_64-linux-gnu -o foo.s %s 2>&1 \
+// RUN: | FileCheck -check-prefix MULTIPLE-OUTPUT-FILES %s
+// RUN: %clang -### -S -target x86_64-linux-gnu --cuda-device-only \
+// RUN: --cuda-gpu-arch=sm_20 --cuda-gpu-arch=sm_30 -o foo.s %s 2>&1 \
+// RUN: | FileCheck -check-prefix MULTIPLE-OUTPUT-FILES %s
+// MULTIPLE-OUTPUT-FILES: error: cannot specify -o when generating multiple output files
diff --git a/test/Driver/cuda-simple.cu b/test/Driver/cuda-simple.cu
index 99d4bfd..3dc0bab 100644
--- a/test/Driver/cuda-simple.cu
+++ b/test/Driver/cuda-simple.cu
@@ -1,6 +1,6 @@
// Verify that we can parse a simple CUDA file with or without -save-temps
// http://llvm.org/PR22936
-// RUN: %clang -Werror -fsyntax-only -c %s
+// RUN: %clang -nocudainc -Werror -fsyntax-only -c %s
//
// Verify that we pass -x cuda-cpp-output to compiler after
// preprocessing a CUDA file
diff --git a/test/Driver/cuda-unused-arg-warning.cu b/test/Driver/cuda-unused-arg-warning.cu
new file mode 100644
index 0000000..e8daad6
--- /dev/null
+++ b/test/Driver/cuda-unused-arg-warning.cu
@@ -0,0 +1,23 @@
+// Tests that we trigger unused-arg warnings on CUDA flags appropriately.
+
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// --cuda-host-only should never trigger unused arg warning.
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -c %s 2>&1 | \
+// RUN: FileCheck %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -x c -c %s 2>&1 | \
+// RUN: FileCheck %s
+
+// --cuda-device-only should warn during non-CUDA compilation.
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -x c -c %s 2>&1 | \
+// RUN: FileCheck -check-prefix UNUSED-WARNING %s
+
+// --cuda-device-only should not produce warning compiling CUDA files
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -c %s 2>&1 | \
+// RUN: FileCheck -check-prefix NO-UNUSED-WARNING %s
+
+// CHECK-NOT: warning: argument unused during compilation: '--cuda-host-only'
+// UNUSED-WARNING: warning: argument unused during compilation: '--cuda-device-only'
+// NO-UNUSED-WARNING-NOT: warning: argument unused during compilation: '--cuda-device-only'
diff --git a/test/Driver/darwin-multiarch-arm.c b/test/Driver/darwin-multiarch-arm.c
new file mode 100644
index 0000000..32d4c1f
--- /dev/null
+++ b/test/Driver/darwin-multiarch-arm.c
@@ -0,0 +1,14 @@
+// Check that we compile correctly with multiple ARM -arch options.
+//
+// RUN: %clang -target arm7-apple-darwin10 -### \
+// RUN: -arch armv7 -arch armv7s %s 2>&1 | FileCheck %s
+
+// CHECK: "-cc1" "-triple" "thumbv7-apple-ios5.0.0"
+// CHECK-SAME: "-o" "[[CC_OUT1:[^"]*]]"
+// CHECK:ld{{(\.exe)?}}" {{.*}} "-o" "[[LD_OUT1:[^"]*]]" {{.*}} "[[CC_OUT1]]"
+// CHECK:"-cc1" "-triple" "thumbv7s-apple-ios5.0.0"
+// CHECK-SAME: "-o" "[[CC_OUT2:[^"]*]]"
+// CHECK:ld{{(\.exe)?}}" {{.*}} "-o" "[[LD_OUT2:[^"]*]]" {{.*}} "[[CC_OUT2]]"
+// CHECK:lipo"
+// CHECK-DAG: "[[LD_OUT1]]"
+// CHECK-DAG: "[[LD_OUT2]]"
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index 8f865f2..0ccacd0 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -2,31 +2,38 @@
// rdar://10383444
// RUN: %clang -### -c -g %s -target x86_64-linux-gnu 2>&1 \
-// RUN: | FileCheck -check-prefix=G %s
+// RUN: | FileCheck -check-prefix=G -check-prefix=G_GDB %s
// RUN: %clang -### -c -g2 %s -target x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck -check-prefix=G %s
// RUN: %clang -### -c -g3 %s -target x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck -check-prefix=G %s
// RUN: %clang -### -c -ggdb %s -target x86_64-linux-gnu 2>&1 \
-// RUN: | FileCheck -check-prefix=G %s
+// RUN: | FileCheck -check-prefix=G -check-prefix=G_GDB %s
// RUN: %clang -### -c -ggdb1 %s -target x86_64-linux-gnu 2>&1 \
-// RUN: | FileCheck -check-prefix=GLTO_ONLY %s
+// RUN: | FileCheck -check-prefix=GLTO_ONLY -check-prefix=G_GDB %s
// RUN: %clang -### -c -ggdb3 %s -target x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -glldb %s -target x86_64-linux-gnu 2>&1 \
+// RUN: | FileCheck -check-prefix=G -check-prefix=G_LLDB %s
+// RUN: %clang -### -c -gsce %s -target x86_64-linux-gnu 2>&1 \
+// RUN: | FileCheck -check-prefix=G -check-prefix=G_SCE %s
// RUN: %clang -### -c -g %s -target x86_64-apple-darwin 2>&1 \
-// RUN: | FileCheck -check-prefix=G_DARWIN %s
+// RUN: | FileCheck -check-prefix=G_DARWIN -check-prefix=G_LLDB %s
// RUN: %clang -### -c -g2 %s -target x86_64-apple-darwin 2>&1 \
// RUN: | FileCheck -check-prefix=G_DARWIN %s
// RUN: %clang -### -c -g3 %s -target x86_64-apple-darwin 2>&1 \
// RUN: | FileCheck -check-prefix=G_DARWIN %s
// RUN: %clang -### -c -ggdb %s -target x86_64-apple-darwin 2>&1 \
-// RUN: | FileCheck -check-prefix=G_DARWIN %s
+// RUN: | FileCheck -check-prefix=G_DARWIN -check-prefix=G_GDB %s
// RUN: %clang -### -c -ggdb1 %s -target x86_64-apple-darwin 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_ONLY_DWARF2 %s
// RUN: %clang -### -c -ggdb3 %s -target x86_64-apple-darwin 2>&1 \
// RUN: | FileCheck -check-prefix=G_DARWIN %s
+// RUN: %clang -### -c -g %s -target x86_64-pc-freebsd10.0 2>&1 \
+// RUN: | FileCheck -check-prefix=G_GDB %s
+
// On the PS4, -g defaults to -gno-column-info, and we always generate the
// arange section.
// RUN: %clang -### -c %s -target x86_64-scei-ps4 2>&1 \
@@ -34,6 +41,8 @@
// RUN: %clang -### -c %s -g -target x86_64-scei-ps4 2>&1 \
// RUN: | FileCheck -check-prefix=G_PS4 %s
// RUN: %clang -### -c %s -g -target x86_64-scei-ps4 2>&1 \
+// RUN: | FileCheck -check-prefix=G_SCE %s
+// RUN: %clang -### -c %s -g -target x86_64-scei-ps4 2>&1 \
// RUN: | FileCheck -check-prefix=NOCI %s
// RUN: %clang -### -c %s -g -gcolumn-info -target x86_64-scei-ps4 2>&1 \
// RUN: | FileCheck -check-prefix=CI %s
@@ -43,6 +52,14 @@
// RUN: %clang -### -c -gfoo %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -g -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -ggdb0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
+// RUN: %clang -### -c -glldb -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
+// RUN: %clang -### -c -glldb -g1 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=GLTO_ONLY -check-prefix=G_LLDB %s
+//
+// PS4 defaults to sce; -ggdb0 changes tuning but turns off debug info,
+// then -g turns it back on without affecting tuning.
+// RUN: %clang -### -c -ggdb0 -g -target x86_64-scei-ps4 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=G -check-prefix=G_GDB %s
//
// RUN: %clang -### -c -g1 %s 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_ONLY %s
@@ -123,6 +140,10 @@
// G_ONLY: "-cc1"
// G_ONLY: "-debug-info-kind=limited"
//
+// G_GDB: "-debugger-tuning=gdb"
+// G_LLDB: "-debugger-tuning=lldb"
+// G_SCE: "-debugger-tuning=sce"
+//
// These tests assert that "-gline-tables-only" "-g" uses the latter,
// but otherwise not caring about the DebugInfoKind.
// G_ONLY_DWARF2: "-cc1"
@@ -148,3 +169,8 @@
// NOCI-NOT: "-dwarf-column-info"
//
// GEXTREFS: "-dwarf-ext-refs" "-fmodule-format=obj" "-debug-info-kind={{standalone|limited}}"
+
+// RUN: not %clang -cc1 -debug-info-kind=watkind 2>&1 | FileCheck -check-prefix=BADSTRING1 %s
+// BADSTRING1: error: invalid value 'watkind' in '-debug-info-kind=watkind'
+// RUN: not %clang -cc1 -debugger-tuning=gmodal 2>&1 | FileCheck -check-prefix=BADSTRING2 %s
+// BADSTRING2: error: invalid value 'gmodal' in '-debugger-tuning=gmodal'
diff --git a/test/Driver/dragonfly.c b/test/Driver/dragonfly.c
index 4be2aad..20921bb 100644
--- a/test/Driver/dragonfly.c
+++ b/test/Driver/dragonfly.c
@@ -2,6 +2,6 @@
// RUN: FileCheck -input-file %t.log %s
// CHECK: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-dragonfly"
-// CHECK: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/usr/libexec/ld-elf.so.{{.*}}" "--hash-style=both" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-L{{.*}}gcc4{{.*}}" "-rpath" "{{.*}}gcc4{{.*}}" "-lc" "-lgcc" "{{.*}}crtend.o" "{{.*}}crtn.o"
+// CHECK: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/usr/libexec/ld-elf.so.{{.*}}" "--hash-style=gnu" "--enable-new-dtags" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-L{{.*}}gcc{{.*}}" "-rpath" "{{.*}}gcc{{.*}}" "-lc" "-lgcc" "{{.*}}crtend.o" "{{.*}}crtn.o"
diff --git a/test/Driver/elfiamcu-header-search.c b/test/Driver/elfiamcu-header-search.c
new file mode 100644
index 0000000..d0f147a
--- /dev/null
+++ b/test/Driver/elfiamcu-header-search.c
@@ -0,0 +1,6 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang -target i386-pc-elfiamcu -c -v -fsyntax-only %s 2>&1 | FileCheck %s
+// CHECK-NOT: /usr/include
+// CHECK-NOT: /usr/local/include
+
diff --git a/test/Driver/emulated-tls.cpp b/test/Driver/emulated-tls.cpp
new file mode 100644
index 0000000..a18c2e2
--- /dev/null
+++ b/test/Driver/emulated-tls.cpp
@@ -0,0 +1,5 @@
+// Cygwin uses emutls. Clang should pass -femulated-tls to cc1 and cc1 should pass EmulatedTLS to LLVM CodeGen.
+// FIXME: Add more targets here to use emutls.
+// RUN: %clang -### -std=c++11 -target i686-pc-cygwin %s 2>&1 | FileCheck %s
+
+// CHECK: "-cc1" {{.*}}"-femulated-tls"
diff --git a/test/Driver/fortran.f95 b/test/Driver/fortran.f95
index 9334cbe..47c6e7b 100644
--- a/test/Driver/fortran.f95
+++ b/test/Driver/fortran.f95
@@ -1,9 +1,21 @@
// Check that the clang driver can invoke gcc to compile Fortran.
// RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -c %s -### 2>&1 \
-// RUN: | FileCheck %s
-// CHECK: gcc
-// CHECK: "-S"
-// CHECK: "-x" "f95"
-// CHECK: clang
-// CHECK: "-cc1as"
+// RUN: | FileCheck --check-prefix=CHECK-OBJECT %s
+// CHECK-OBJECT: gcc
+// CHECK-OBJECT: "-c"
+// CHECK-OBJECT: "-x" "f95"
+// CHECK-OBJECT-NOT: cc1as
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -S %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASM %s
+// CHECK-ASM: gcc
+// CHECK-ASM: "-S"
+// CHECK-ASM: "-x" "f95"
+// CHECK-ASM-NOT: cc1
+
+// RUN: %clang -Wall -target x86_64-unknown-linux-gnu -integrated-as %s -o %t -### 2>&1 | FileCheck --check-prefix=CHECK-WARN %s
+// CHECK-WARN: gcc
+// CHECK-WARN-NOT: "-Wall"
+// CHECK-WARN: ld
+// CHECK-WARN-NOT: "-Wall"
diff --git a/test/Driver/freebsd-mips-as.c b/test/Driver/freebsd-mips-as.c
index da2d120..7555888 100644
--- a/test/Driver/freebsd-mips-as.c
+++ b/test/Driver/freebsd-mips-as.c
@@ -89,3 +89,9 @@
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2 %s
// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EB"
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -G0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-AS-G0 %s
+// MIPS32-EB-AS-G0: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-EB" "-G0"
+// MIPS32-EB-AS-G0-NOT: "-KPIC"
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index d773504..45e9204 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -136,3 +136,8 @@
// RUN: | FileCheck --check-prefix=CHECK-SPARC-CPU %s
// CHECK-SPARC-CPU: cc1{{.*}}" "-target-cpu" "ultrasparc"
// CHECK-SPARC-CPU: as{{.*}}" "-Av9
+
+// Check that -G flags are passed to the linker for mips
+// RUN: %clang -target mips-unknown-freebsd %s -### -G0 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS-G %s
+// CHECK-MIPS-G: ld{{.*}}" "-G0"
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 6e470b2..09eead2 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -160,22 +160,25 @@
// RUN: %clang -target arm-linux-androideabi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-NO-ASAN
// CHECK-ANDROID-NO-ASAN: "-mrelocation-model" "pic"
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -fsanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover -fsanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
+// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
+// CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover
-// CHECK-RECOVER: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
-// CHECK-NO-RECOVER-NOT: sanitize-recover
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
// CHECK-PARTIAL-RECOVER: "-fsanitize-recover={{((object-size|shift-base),?){2}"}}
-// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=address,foobar,object-size,unreachable -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIAG-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=address -fsanitize-recover=all -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-ASAN
+// CHECK-RECOVER-ASAN: "-fsanitize-recover=address"
+
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=foobar,object-size,unreachable -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIAG-RECOVER
// CHECK-DIAG-RECOVER: unsupported argument 'foobar' to option 'fsanitize-recover='
-// CHECK-DIAG-RECOVER: unsupported argument 'address,unreachable' to option 'fsanitize-recover='
+// CHECK-DIAG-RECOVER: unsupported argument 'unreachable' to option 'fsanitize-recover='
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEPRECATED-RECOVER
// CHECK-DEPRECATED-RECOVER: argument '-fsanitize-recover' is deprecated, use '-fsanitize-recover=undefined,integer' instead
@@ -260,6 +263,18 @@
// CHECK-CFI-NOTRAP-WIN: -emit-llvm-bc
// CHECK-CFI-NOTRAP-WIN-NOT: -fsanitize-trap=cfi
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-cfi-cross-dso -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-CROSS-DSO
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NO-CROSS-DSO
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-cfi-cross-dso -fno-sanitize-cfi-cross-dso -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NO-CROSS-DSO
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fno-sanitize-cfi-cross-dso -fsanitize-cfi-cross-dso -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-CROSS-DSO
+// CHECK-CFI-CROSS-DSO: -emit-llvm-bc
+// CHECK-CFI-CROSS-DSO: -fsanitize-cfi-cross-dso
+// CHECK-CFI-NO-CROSS-DSO: -emit-llvm-bc
+// CHECK-CFI-NO-CROSS-DSO-NOT: -fsanitize-cfi-cross-dso
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-stats -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-STATS
+// CHECK-CFI-STATS: -fsanitize-stats
+
// RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
// RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
// RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
@@ -308,3 +323,7 @@
// CHECK-MSAN-PS4: unsupported option '-fsanitize=memory' for target 'x86_64-scei-ps4'
// RUN: %clang -target x86_64-scei-ps4 -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-PS4
// CHECK-TSAN-PS4: unsupported option '-fsanitize=thread' for target 'x86_64-scei-ps4'
+// RUN: %clang -target x86_64-scei-ps4 -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-PS4
+// Make sure there are no *.{o,bc} or -l passed before the ASan library.
+// CHECK-ASAN-PS4-NOT: {{(\.(o|bc)"? |-l).*-lSceDbgAddressSanitizer_stub_weak}}
+// CHECK-ASAN-PS4: -lSceDbgAddressSanitizer_stub_weak
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index 4892bd9..d28e432 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -5,15 +5,16 @@
// RUN: %s \
// RUN: -Wall -Wdocumentation \
// RUN: -Xclang foo-bar \
-// RUN: -march=x86_64 \
+// RUN: -march=x86-64 \
// RUN: -mlinker-version=10 -### 2> %t
// RUN: FileCheck < %t %s
//
-// clang-cc1
+// clang -cc1
+// CHECK: clang
// CHECK: "-Wall" "-Wdocumentation"
// CHECK: "-o" "{{[^"]+}}.o"
//
-// gcc-ld
+// gcc as ld.
// CHECK: gcc{{[^"]*}}"
// CHECK-NOT: "-mlinker-version=10"
// CHECK-NOT: "-Xclang"
@@ -27,3 +28,9 @@
// CHECK-NOT: "-Wall"
// CHECK-NOT: "-Wdocumentation"
// CHECK: "-o" "a.out"
+
+// Check that we're not forwarding -g options to the assembler
+// RUN: %clang -g -target x86_64-unknown-linux-gnu -no-integrated-as -c %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASM %s
+// CHECK-ASM: as
+// CHECK-ASM-NOT: "-g"
diff --git a/test/Driver/gold-lto.c b/test/Driver/gold-lto.c
index db6786f..050b1ef 100644
--- a/test/Driver/gold-lto.c
+++ b/test/Driver/gold-lto.c
@@ -1,23 +1,26 @@
// RUN: touch %t.o
//
// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
-// RUN: -Wl,-plugin-opt=foo \
+// RUN: -Wl,-plugin-opt=foo -O3 \
// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-BASIC
// CHECK-X86-64-BASIC: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-64-BASIC: "-plugin-opt=O3"
// CHECK-X86-64-BASIC: "-plugin-opt=foo"
//
// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
-// RUN: -march=corei7 -Wl,-plugin-opt=foo \
+// RUN: -march=corei7 -Wl,-plugin-opt=foo -Ofast \
// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-COREI7
// CHECK-X86-64-COREI7: "-plugin" "{{.*}}/LLVMgold.so"
// CHECK-X86-64-COREI7: "-plugin-opt=mcpu=corei7"
+// CHECK-X86-64-COREI7: "-plugin-opt=O3"
// CHECK-X86-64-COREI7: "-plugin-opt=foo"
//
// RUN: %clang -target arm-unknown-linux -### %t.o -flto 2>&1 \
-// RUN: -march=armv7a -Wl,-plugin-opt=foo \
+// RUN: -march=armv7a -Wl,-plugin-opt=foo -O0 \
// RUN: | FileCheck %s --check-prefix=CHECK-ARM-V7A
// CHECK-ARM-V7A: "-plugin" "{{.*}}/LLVMgold.so"
// CHECK-ARM-V7A: "-plugin-opt=mcpu=cortex-a8"
+// CHECK-ARM-V7A: "-plugin-opt=O0"
// CHECK-ARM-V7A: "-plugin-opt=foo"
//
// RUN: %clang -target i686-linux-android -### %t.o -flto 2>&1 \
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 3d04932..e3a54dd 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -2,135 +2,92 @@
// Test standard include paths
// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK000 %s
+// CHECK000: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/include"
+
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
// RUN: %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK001 %s
-// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK002 %s
-// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
+// CHECK001: "-cc1" {{.*}} "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/include/c++"
+// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/include"
// -----------------------------------------------------------------------------
// Test -nostdinc, -nostdlibinc, -nostdinc++
// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
// RUN: -nostdinc \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK003 %s
-// CHECK003: "-cc1"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
+// RUN: | FileCheck -check-prefix=CHECK010 %s
+// CHECK010: "-cc1"
+// CHECK010-NOT: "-internal-externc-isystem"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK004 %s
-// CHECK004: "-cc1"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
+// RUN: | FileCheck -check-prefix=CHECK011 %s
+// CHECK011: "-cc1"
+// CHECK011-NOT: "-internal-externc-isystem"
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdlibinc \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK005 %s
-// CHECK005: "-cc1"
-// CHECK005-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
// RUN: -nostdinc++ \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK006 %s
-// CHECK006: "-cc1"
-// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
+// RUN: | FileCheck -check-prefix=CHECK012 %s
+// CHECK012: "-cc1"
+// CHECK012-DAG-NOT: "-internal-isystem"
+// CHECK012-DAG: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/include"
-// -----------------------------------------------------------------------------
-// Test -march=<archname> -mcpu=<archname> -mv<number>
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: %clangxx -### -target hexagon-unknown-elf -fno-integrated-as \
// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
// RUN: --gcc-toolchain="" \
-// RUN: -march=hexagonv3 \
+// RUN: -nostdlibinc \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK007 %s
-// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv3"
+// RUN: | FileCheck -check-prefix=CHECK013 %s
+// CHECK013: "-cc1"
+// CHECK013-DAG-NOT: "-internal-isystem"
+// CHECK013-DAG-NOT: "-internal-externc-isystem"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// -----------------------------------------------------------------------------
+// Test -mcpu=<cpuname> -mv<number>
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv4 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK020 %s
+// CHECK020: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
+// CHECK020: "hexagon-link" {{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v4/crt0
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
// RUN: -mcpu=hexagonv5 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK008 %s
-// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv5"
+// RUN: | FileCheck -check-prefix=CHECK021 %s
+// CHECK021: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
+// CHECK021: "hexagon-link" {{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v5/crt0
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -mv2 \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv55 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK009 %s
-// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv2"
+// RUN: | FileCheck -check-prefix=CHECK022 %s
+// CHECK022: "-cc1" {{.*}} "-target-cpu" "hexagonv55"
+// CHECK022: "hexagon-link" {{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v55/crt0
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK010 %s
-// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv4"
-
-// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: not %clang -mcpu=hexagonv2 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: not %clang -mv2 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
-
-// RUN: not %clang -march=hexagonv3 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: not %clang -mcpu=hexagonv3 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: not %clang -mv3 -target hexagon-unknown-elf \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
+// RUN: | FileCheck -check-prefix=CHECK023 %s
+// CHECK023: "-cc1" {{.*}} "-target-cpu" "hexagonv60"
+// CHECK023: "hexagon-link" {{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0
// -----------------------------------------------------------------------------
// Test Linker related args
@@ -139,450 +96,388 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Defaults for C
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK011 %s
-// CHECK011: "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK011-NOT: "-static"
-// CHECK011-NOT: "-shared"
-// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK011: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK011: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK011: "-L{{.*}}/lib/gcc"
-// CHECK011: "-L{{.*}}/hexagon/lib/v4"
-// CHECK011: "-L{{.*}}/hexagon/lib"
-// CHECK011: "{{[^"]+}}.o"
-// CHECK011: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK011: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK030 %s
+// CHECK030: "-cc1"
+// CHECK030-NEXT: hexagon-link
+// CHECK030-NOT: "-static"
+// CHECK030-NOT: "-shared"
+// CHECK030: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK030: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK030: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK030: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK030: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK030: "{{[^"]+}}.o"
+// CHECK030: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK030: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Defaults for C++
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK012 %s
-// CHECK012: "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK012-NOT: "-static"
-// CHECK012-NOT: "-shared"
-// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK012: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK012: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK012: "-L{{.*}}/lib/gcc"
-// CHECK012: "-L{{.*}}/hexagon/lib/v4"
-// CHECK012: "-L{{.*}}/hexagon/lib"
-// CHECK012: "{{[^"]+}}.o"
-// CHECK012: "-lstdc++" "-lm"
-// CHECK012: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK012: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK031 %s
+// CHECK031: "-cc1"
+// CHECK031-NEXT: hexagon-link
+// CHECK031-NOT: "-static"
+// CHECK031-NOT: "-shared"
+// CHECK031: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK031: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK031: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK031: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK031: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK031: "{{[^"]+}}.o"
+// CHECK031: "-lstdc++" "-lm"
+// CHECK031: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK031: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Additional Libraries (-L)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -Lone -L two -L three \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK013 %s
-// CHECK013: "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK013: "-Lone" "-Ltwo" "-Lthree"
-// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK013: "-L{{.*}}/lib/gcc"
-// CHECK013: "-L{{.*}}/hexagon/lib/v4"
-// CHECK013: "-L{{.*}}/hexagon/lib"
-// CHECK013: "{{[^"]+}}.o"
-// CHECK013: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK013: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK032 %s
+// CHECK032: "-cc1"
+// CHECK032-NEXT: hexagon-link
+// CHECK032-NOT: "-static"
+// CHECK032-NOT: "-shared"
+// CHECK032: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK032: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK032: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK032: "-Lone" "-Ltwo" "-Lthree"
+// CHECK032: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK032: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK032: "{{[^"]+}}.o"
+// CHECK032: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK032: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -static, -shared
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -static \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK014 %s
-// CHECK014: "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK014: "-static"
-// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK014: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK014: "-L{{.*}}/lib/gcc"
-// CHECK014: "-L{{.*}}/hexagon/lib/v4"
-// CHECK014: "-L{{.*}}/hexagon/lib"
-// CHECK014: "{{[^"]+}}.o"
-// CHECK014: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK014: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK033 %s
+// CHECK033: "-cc1"
+// CHECK033-NEXT: hexagon-link
+// CHECK033: "-static"
+// CHECK033: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK033: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK033: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK033: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK033: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK033: "{{[^"]+}}.o"
+// CHECK033: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK033: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -shared \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK015 %s
-// CHECK015: "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK015: "-shared" "-call_shared"
-// CHECK015-NOT: crt0_standalone.o
-// CHECK015-NOT: crt0.o
-// CHECK015: "{{.*}}/hexagon/lib/v4/G0/initS.o"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK015: "-L{{.*}}/lib/gcc"
-// CHECK015: "-L{{.*}}/hexagon/lib/v4/G0"
-// CHECK015: "-L{{.*}}/hexagon/lib/G0"
-// CHECK015: "-L{{.*}}/hexagon/lib/v4"
-// CHECK015: "-L{{.*}}/hexagon/lib"
-// CHECK015: "{{[^"]+}}.o"
-// CHECK015: "--start-group"
-// CHECK015-NOT: "-lstandalone"
-// CHECK015-NOT: "-lc"
-// CHECK015: "-lgcc"
-// CHECK015: "--end-group"
-// CHECK015: "{{.*}}/hexagon/lib/v4/G0/finiS.o"
+// RUN: | FileCheck -check-prefix=CHECK034 %s
+// CHECK034: "-cc1"
+// CHECK034-NEXT: hexagon-link
+// CHECK034: "-shared" "-call_shared"
+// CHECK034-NOT: crt0_standalone.o
+// CHECK034-NOT: crt0.o
+// CHECK034: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0/pic/initS.o"
+// CHECK034: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0"
+// CHECK034: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK034: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK034: "{{[^"]+}}.o"
+// CHECK034: "--start-group"
+// CHECK034-NOT: "-lstandalone"
+// CHECK034-NOT: "-lc"
+// CHECK034: "-lgcc"
+// CHECK034: "--end-group"
+// CHECK034: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0/pic/finiS.o"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -shared \
// RUN: -static \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK016 %s
-// CHECK016: "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK016: "-shared" "-call_shared" "-static"
-// CHECK016-NOT: crt0_standalone.o
-// CHECK016-NOT: crt0.o
-// CHECK016: "{{.*}}/hexagon/lib/v4/G0/init.o"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK016: "-L{{.*}}/lib/gcc"
-// CHECK016: "-L{{.*}}/hexagon/lib/v4/G0"
-// CHECK016: "-L{{.*}}/hexagon/lib/G0"
-// CHECK016: "-L{{.*}}/hexagon/lib/v4"
-// CHECK016: "-L{{.*}}/hexagon/lib"
-// CHECK016: "{{[^"]+}}.o"
-// CHECK016: "--start-group"
-// CHECK016-NOT: "-lstandalone"
-// CHECK016-NOT: "-lc"
-// CHECK016: "-lgcc"
-// CHECK016: "--end-group"
-// CHECK016: "{{.*}}/hexagon/lib/v4/G0/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK035 %s
+// CHECK035: "-cc1"
+// CHECK035-NEXT: hexagon-link
+// CHECK035: "-shared" "-call_shared" "-static"
+// CHECK035-NOT: crt0_standalone.o
+// CHECK035-NOT: crt0.o
+// CHECK035: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0/init.o"
+// CHECK035: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0"
+// CHECK035: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK035: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK035: "{{[^"]+}}.o"
+// CHECK035: "--start-group"
+// CHECK035-NOT: "-lstandalone"
+// CHECK035-NOT: "-lc"
+// CHECK035: "-lgcc"
+// CHECK035: "--end-group"
+// CHECK035: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/G0/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -nostdlib, -nostartfiles, -nodefaultlibs
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -nostdlib \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK017 %s
-// CHECK017: "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK017-NOT: crt0_standalone.o
-// CHECK017-NOT: crt0.o
-// CHECK017-NOT: init.o
-// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK017: "-L{{.*}}/lib/gcc"
-// CHECK017: "-L{{.*}}/hexagon/lib/v4"
-// CHECK017: "-L{{.*}}/hexagon/lib"
-// CHECK017: "{{[^"]+}}.o"
-// CHECK017-NOT: "-lstdc++"
-// CHECK017-NOT: "-lm"
-// CHECK017-NOT: "--start-group"
-// CHECK017-NOT: "-lstandalone"
-// CHECK017-NOT: "-lc"
-// CHECK017-NOT: "-lgcc"
-// CHECK017-NOT: "--end-group"
-// CHECK017-NOT: fini.o
+// RUN: | FileCheck -check-prefix=CHECK036 %s
+// CHECK036: "-cc1"
+// CHECK036-NEXT: hexagon-link
+// CHECK036-NOT: crt0_standalone.o
+// CHECK036-NOT: crt0.o
+// CHECK036-NOT: init.o
+// CHECK036: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK036: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK036: "{{[^"]+}}.o"
+// CHECK036-NOT: "-lstdc++"
+// CHECK036-NOT: "-lm"
+// CHECK036-NOT: "--start-group"
+// CHECK036-NOT: "-lstandalone"
+// CHECK036-NOT: "-lc"
+// CHECK036-NOT: "-lgcc"
+// CHECK036-NOT: "--end-group"
+// CHECK036-NOT: fini.o
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -nostartfiles \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK018 %s
-// CHECK018: "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK018-NOT: crt0_standalone.o
-// CHECK018-NOT: crt0.o
-// CHECK018-NOT: init.o
-// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK018: "-L{{.*}}/lib/gcc"
-// CHECK018: "-L{{.*}}/hexagon/lib/v4"
-// CHECK018: "-L{{.*}}/hexagon/lib"
-// CHECK018: "{{[^"]+}}.o"
-// CHECK018: "-lstdc++"
-// CHECK018: "-lm"
-// CHECK018: "--start-group"
-// CHECK018: "-lstandalone"
-// CHECK018: "-lc"
-// CHECK018: "-lgcc"
-// CHECK018: "--end-group"
-// CHECK018-NOT: fini.o
+// RUN: | FileCheck -check-prefix=CHECK037 %s
+// CHECK037: "-cc1"
+// CHECK037-NEXT: hexagon-link
+// CHECK037-NOT: crt0_standalone.o
+// CHECK037-NOT: crt0.o
+// CHECK037-NOT: init.o
+// CHECK037: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK037: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK037: "{{[^"]+}}.o"
+// CHECK037: "-lstdc++"
+// CHECK037: "-lm"
+// CHECK037: "--start-group"
+// CHECK037: "-lstandalone"
+// CHECK037: "-lc"
+// CHECK037: "-lgcc"
+// CHECK037: "--end-group"
+// CHECK037-NOT: fini.o
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -nodefaultlibs \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK019 %s
-// CHECK019: "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK019: "-L{{.*}}/lib/gcc"
-// CHECK019: "-L{{.*}}/hexagon/lib/v4"
-// CHECK019: "-L{{.*}}/hexagon/lib"
-// CHECK019: "{{[^"]+}}.o"
-// CHECK019-NOT: "-lstdc++"
-// CHECK019-NOT: "-lm"
-// CHECK019-NOT: "--start-group"
-// CHECK019-NOT: "-lstandalone"
-// CHECK019-NOT: "-lc"
-// CHECK019-NOT: "-lgcc"
-// CHECK019-NOT: "--end-group"
-// CHECK019: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK038 %s
+// CHECK038: "-cc1"
+// CHECK038-NEXT: hexagon-link
+// CHECK038: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK038: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK038: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK038: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK038: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK038: "{{[^"]+}}.o"
+// CHECK038-NOT: "-lstdc++"
+// CHECK038-NOT: "-lm"
+// CHECK038-NOT: "--start-group"
+// CHECK038-NOT: "-lstandalone"
+// CHECK038-NOT: "-lc"
+// CHECK038-NOT: "-lgcc"
+// CHECK038-NOT: "--end-group"
+// CHECK038: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -moslib
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -moslib=first -moslib=second \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK020 %s
-// CHECK020: "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK020-NOT: "-static"
-// CHECK020-NOT: "-shared"
-// CHECK020-NOT: crt0_standalone.o
-// CHECK020: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK020: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK020: "-L{{.*}}/lib/gcc"
-// CHECK020: "-L{{.*}}/hexagon/lib/v4"
-// CHECK020: "-L{{.*}}/hexagon/lib"
-// CHECK020: "{{[^"]+}}.o"
-// CHECK020: "--start-group"
-// CHECK020: "-lfirst" "-lsecond"
-// CHECK020-NOT: "-lstandalone"
-// CHECK020: "-lc" "-lgcc" "--end-group"
-// CHECK020: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK039 %s
+// CHECK039: "-cc1"
+// CHECK039-NEXT: hexagon-link
+// CHECK039-NOT: "-static"
+// CHECK039-NOT: "-shared"
+// CHECK039-NOT: crt0_standalone.o
+// CHECK039: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK039: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK039: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK039: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK039: "{{[^"]+}}.o"
+// CHECK039: "--start-group"
+// CHECK039: "-lfirst" "-lsecond"
+// CHECK039-NOT: "-lstandalone"
+// CHECK039: "-lc" "-lgcc" "--end-group"
+// CHECK039: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -moslib=first -moslib=second -moslib=standalone\
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
+// RUN: -moslib=first -moslib=second -moslib=standalone \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK021 %s
-// CHECK021: "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK021-NOT: "-static"
-// CHECK021-NOT: "-shared"
-// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK021: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK021: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK021: "-L{{.*}}/lib/gcc"
-// CHECK021: "-L{{.*}}/hexagon/lib/v4"
-// CHECK021: "-L{{.*}}/hexagon/lib"
-// CHECK021: "{{[^"]+}}.o"
-// CHECK021: "--start-group"
-// CHECK021: "-lfirst" "-lsecond"
-// CHECK021: "-lstandalone"
-// CHECK021: "-lc" "-lgcc" "--end-group"
-// CHECK021: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK03A %s
+// CHECK03A: "-cc1"
+// CHECK03A-NEXT: hexagon-link
+// CHECK03A-NOT: "-static"
+// CHECK03A-NOT: "-shared"
+// CHECK03A: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK03A: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK03A: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK03A: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK03A: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK03A: "{{[^"]+}}.o"
+// CHECK03A: "--start-group"
+// CHECK03A: "-lfirst" "-lsecond"
+// CHECK03A: "-lstandalone"
+// CHECK03A: "-lc" "-lgcc" "--end-group"
+// CHECK03A: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Other args to pass to linker
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clangxx -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -s \
// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
// RUN: -t \
// RUN: -e start_here \
// RUN: -uFoo -undefined Bar \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK022 %s
-// CHECK022: "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK022: "-L{{.*}}/lib/gcc"
-// CHECK022: "-L{{.*}}/hexagon/lib/v4"
-// CHECK022: "-L{{.*}}/hexagon/lib"
-// CHECK022: "-s"
-// CHECK022: "-Tbss" "0xdead" "-Tdata" "0xbeef" "-Ttext" "0xcafe"
-// CHECK022: "-t"
-// CHECK022: "-u" "Foo" "-undefined" "Bar"
-// CHECK022: "{{[^"]+}}.o"
-// CHECK022: "-lstdc++" "-lm"
-// CHECK022: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK022: "{{.*}}/hexagon/lib/v4/fini.o"
+// RUN: | FileCheck -check-prefix=CHECK03B %s
+// CHECK03B: "-cc1"
+// CHECK03B-NEXT: hexagon-link
+// CHECK03B: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0_standalone.o"
+// CHECK03B: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0.o"
+// CHECK03B: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/init.o"
+// CHECK03B: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60"
+// CHECK03B: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib"
+// CHECK03B: "-s"
+// CHECK03B: "-Tbss" "0xdead" "-Tdata" "0xbeef" "-Ttext" "0xcafe"
+// CHECK03B: "-t"
+// CHECK03B: "-u" "Foo" "-undefined" "Bar"
+// CHECK03B: "{{[^"]+}}.o"
+// CHECK03B: "-lstdc++" "-lm"
+// CHECK03B: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK03B: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/fini.o"
// -----------------------------------------------------------------------------
// pic, small data threshold
// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK023 %s
-// CHECK023: "-cc1"
-// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK023-NOT: "-G{{[0-9]+}}"
+// RUN: | FileCheck -check-prefix=CHECK040 %s
+// CHECK040: "-cc1"
+// CHECK040-NEXT: hexagon-link
+// CHECK040-NOT: "-G{{[0-9]+}}"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -fpic \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK024 %s
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck -check-prefix=CHECK041 %s
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -fPIC \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK024 %s
-// CHECK024: "-cc1"
-// CHECK024-NOT: "-mrelocation-model" "static"
-// CHECK024: "-pic-level" "{{[12]}}"
-// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK024: "-G0"
+// RUN: | FileCheck -check-prefix=CHECK041 %s
+// CHECK041: "-cc1"
+// CHECK041-NOT: "-mrelocation-model" "static"
+// CHECK041: "-pic-level" "{{[12]}}"
+// CHECK041: "-mllvm" "-hexagon-small-data-threshold=0"
+// CHECK041-NEXT: hexagon-link
+// CHECK041: "-G0"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf -fno-integrated-as \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -G=8 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck -check-prefix=CHECK042 %s
+// RUN: %clang -### -target hexagon-unknown-elf -fno-integrated-as \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -G 8 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck -check-prefix=CHECK042 %s
+// RUN: %clang -### -target hexagon-unknown-elf -fno-integrated-as \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -msmall-data-threshold=8 \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// CHECK025: "-cc1"
-// CHECK025: "-mrelocation-model" "static"
-// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK025: "-G8"
+// RUN: | FileCheck -check-prefix=CHECK042 %s
+// CHECK042: "-cc1"
+// CHECK042: "-mrelocation-model" "static"
+// CHECK042: "-mllvm" "-hexagon-small-data-threshold=8"
+// CHECK042-NEXT: llvm-mc
+// CHECK042: "-gpsize=8"
+// CHECK042-NEXT: hexagon-link
+// CHECK042: "-G8"
// -----------------------------------------------------------------------------
// pie
// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -pie \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK026 %s
-// CHECK026: "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK026: "-pie"
+// RUN: | FileCheck -check-prefix=CHECK050 %s
+// CHECK050: "-cc1"
+// CHECK050-NEXT: hexagon-link
+// CHECK050: "-pie"
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -pie -shared \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK027 %s
-// CHECK027: "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK027-NOT: "-pie"
-
-// -----------------------------------------------------------------------------
-// Misc Defaults
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK028 %s
-// CHECK028: "-cc1"
-// CHECK028: "-mqdsp6-compat"
-// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
+// RUN: | FileCheck -check-prefix=CHECK051 %s
+// CHECK051: "-cc1"
+// CHECK051-NEXT: hexagon-link
+// CHECK051-NOT: "-pie"
// -----------------------------------------------------------------------------
// Test Assembler related args
// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-elf \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
+// RUN: %clang -### -target hexagon-unknown-elf -fno-integrated-as \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
// RUN: -gdwarf-2 \
// RUN: -Wa,--noexecstack,--trap \
// RUN: -Xassembler --keep-locals \
// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK029 %s
-// CHECK029: "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
+// RUN: | FileCheck -check-prefix=CHECK060 %s
+// CHECK060: "-cc1"
+// CHECK060-NEXT: llvm-mc
+// CHECK060: "--noexecstack" "--trap" "--keep-locals"
+// CHECK060-NEXT: hexagon-link
+
+// -----------------------------------------------------------------------------
+// Misc Defaults
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK070 %s
+// CHECK070: "-cc1"
+// CHECK070: "-Wreturn-type"
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
deleted file mode 100644
index c96fca2..0000000
--- a/test/Driver/hexagon-toolchain.c
+++ /dev/null
@@ -1,588 +0,0 @@
-// -----------------------------------------------------------------------------
-// Test standard include paths
-// -----------------------------------------------------------------------------
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK001 %s
-// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK002 %s
-// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu{{/|\\\\}}hexagon/include/c++/4.4.0"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// -----------------------------------------------------------------------------
-// Test -nostdinc, -nostdlibinc, -nostdinc++
-// -----------------------------------------------------------------------------
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdinc \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK003 %s
-// CHECK003: "-cc1"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdlibinc \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK004 %s
-// CHECK004: "-cc1"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdlibinc \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK005 %s
-// CHECK005: "-cc1"
-// CHECK005-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
-// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
-// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdinc++ \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK006 %s
-// CHECK006: "-cc1"
-// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
-// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"
-
-// -----------------------------------------------------------------------------
-// Test -march=<archname> -mcpu=<archname> -mv<number>
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -march=hexagonv3 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK007 %s
-// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v3"
-// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv3"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -mcpu=hexagonv5 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK008 %s
-// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v5"
-// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv5"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -mv2 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK009 %s
-// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v2"
-// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv2"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK010 %s
-// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-as"{{.*}} "-march=v4"
-// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\\\}}hexagon-ld"{{.*}} "-mv4"
-
-// RUN: not %clang -march=hexagonv2 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: not %clang -mcpu=hexagonv2 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// RUN: not %clang -mv2 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
-// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
-
-// RUN: not %clang -march=hexagonv3 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: not %clang -mcpu=hexagonv3 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// RUN: not %clang -mv3 -target hexagon-unknown-linux \
-// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
-// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
-
-// -----------------------------------------------------------------------------
-// Test Linker related args
-// -----------------------------------------------------------------------------
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Defaults for C
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK011 %s
-// CHECK011: "-cc1"
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK011-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK011-NOT: "-static"
-// CHECK011-NOT: "-shared"
-// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK011: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK011: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK011: "-L{{.*}}/lib/gcc"
-// CHECK011: "-L{{.*}}/hexagon/lib/v4"
-// CHECK011: "-L{{.*}}/hexagon/lib"
-// CHECK011: "{{[^"]+}}.o"
-// CHECK011: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK011: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Defaults for C++
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK012 %s
-// CHECK012: "-cc1"
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK012-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK012-NOT: "-static"
-// CHECK012-NOT: "-shared"
-// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK012: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK012: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK012: "-L{{.*}}/lib/gcc"
-// CHECK012: "-L{{.*}}/hexagon/lib/v4"
-// CHECK012: "-L{{.*}}/hexagon/lib"
-// CHECK012: "{{[^"]+}}.o"
-// CHECK012: "-lstdc++" "-lm"
-// CHECK012: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK012: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Additional Libraries (-L)
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -Lone -L two -L three \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK013 %s
-// CHECK013: "-cc1"
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK013-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK013: "-Lone" "-Ltwo" "-Lthree"
-// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK013: "-L{{.*}}/lib/gcc"
-// CHECK013: "-L{{.*}}/hexagon/lib/v4"
-// CHECK013: "-L{{.*}}/hexagon/lib"
-// CHECK013: "{{[^"]+}}.o"
-// CHECK013: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK013: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// -static, -shared
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -static \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK014 %s
-// CHECK014: "-cc1"
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK014-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK014: "-static"
-// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK014: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK014: "-L{{.*}}/lib/gcc"
-// CHECK014: "-L{{.*}}/hexagon/lib/v4"
-// CHECK014: "-L{{.*}}/hexagon/lib"
-// CHECK014: "{{[^"]+}}.o"
-// CHECK014: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK014: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -shared \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK015 %s
-// CHECK015: "-cc1"
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK015-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK015: "-shared" "-call_shared"
-// CHECK015-NOT: crt0_standalone.o
-// CHECK015-NOT: crt0.o
-// CHECK015: "{{.*}}/hexagon/lib/v4/G0/initS.o"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK015: "-L{{.*}}/lib/gcc"
-// CHECK015: "-L{{.*}}/hexagon/lib/v4/G0"
-// CHECK015: "-L{{.*}}/hexagon/lib/G0"
-// CHECK015: "-L{{.*}}/hexagon/lib/v4"
-// CHECK015: "-L{{.*}}/hexagon/lib"
-// CHECK015: "{{[^"]+}}.o"
-// CHECK015: "--start-group"
-// CHECK015-NOT: "-lstandalone"
-// CHECK015-NOT: "-lc"
-// CHECK015: "-lgcc"
-// CHECK015: "--end-group"
-// CHECK015: "{{.*}}/hexagon/lib/v4/G0/finiS.o"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -shared \
-// RUN: -static \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK016 %s
-// CHECK016: "-cc1"
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK016-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK016: "-shared" "-call_shared" "-static"
-// CHECK016-NOT: crt0_standalone.o
-// CHECK016-NOT: crt0.o
-// CHECK016: "{{.*}}/hexagon/lib/v4/G0/init.o"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK016: "-L{{.*}}/lib/gcc"
-// CHECK016: "-L{{.*}}/hexagon/lib/v4/G0"
-// CHECK016: "-L{{.*}}/hexagon/lib/G0"
-// CHECK016: "-L{{.*}}/hexagon/lib/v4"
-// CHECK016: "-L{{.*}}/hexagon/lib"
-// CHECK016: "{{[^"]+}}.o"
-// CHECK016: "--start-group"
-// CHECK016-NOT: "-lstandalone"
-// CHECK016-NOT: "-lc"
-// CHECK016: "-lgcc"
-// CHECK016: "--end-group"
-// CHECK016: "{{.*}}/hexagon/lib/v4/G0/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// -nostdlib, -nostartfiles, -nodefaultlibs
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostdlib \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK017 %s
-// CHECK017: "-cc1"
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK017-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK017-NOT: crt0_standalone.o
-// CHECK017-NOT: crt0.o
-// CHECK017-NOT: init.o
-// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK017: "-L{{.*}}/lib/gcc"
-// CHECK017: "-L{{.*}}/hexagon/lib/v4"
-// CHECK017: "-L{{.*}}/hexagon/lib"
-// CHECK017: "{{[^"]+}}.o"
-// CHECK017-NOT: "-lstdc++"
-// CHECK017-NOT: "-lm"
-// CHECK017-NOT: "--start-group"
-// CHECK017-NOT: "-lstandalone"
-// CHECK017-NOT: "-lc"
-// CHECK017-NOT: "-lgcc"
-// CHECK017-NOT: "--end-group"
-// CHECK017-NOT: fini.o
-
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nostartfiles \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK018 %s
-// CHECK018: "-cc1"
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK018-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK018-NOT: crt0_standalone.o
-// CHECK018-NOT: crt0.o
-// CHECK018-NOT: init.o
-// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK018: "-L{{.*}}/lib/gcc"
-// CHECK018: "-L{{.*}}/hexagon/lib/v4"
-// CHECK018: "-L{{.*}}/hexagon/lib"
-// CHECK018: "{{[^"]+}}.o"
-// CHECK018: "-lstdc++"
-// CHECK018: "-lm"
-// CHECK018: "--start-group"
-// CHECK018: "-lstandalone"
-// CHECK018: "-lc"
-// CHECK018: "-lgcc"
-// CHECK018: "--end-group"
-// CHECK018-NOT: fini.o
-
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -nodefaultlibs \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK019 %s
-// CHECK019: "-cc1"
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK019-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK019: "-L{{.*}}/lib/gcc"
-// CHECK019: "-L{{.*}}/hexagon/lib/v4"
-// CHECK019: "-L{{.*}}/hexagon/lib"
-// CHECK019: "{{[^"]+}}.o"
-// CHECK019-NOT: "-lstdc++"
-// CHECK019-NOT: "-lm"
-// CHECK019-NOT: "--start-group"
-// CHECK019-NOT: "-lstandalone"
-// CHECK019-NOT: "-lc"
-// CHECK019-NOT: "-lgcc"
-// CHECK019-NOT: "--end-group"
-// CHECK019: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// -moslib
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -moslib=first -moslib=second \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK020 %s
-// CHECK020: "-cc1"
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK020-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK020-NOT: "-static"
-// CHECK020-NOT: "-shared"
-// CHECK020-NOT: crt0_standalone.o
-// CHECK020: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK020: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK020: "-L{{.*}}/lib/gcc"
-// CHECK020: "-L{{.*}}/hexagon/lib/v4"
-// CHECK020: "-L{{.*}}/hexagon/lib"
-// CHECK020: "{{[^"]+}}.o"
-// CHECK020: "--start-group"
-// CHECK020: "-lfirst" "-lsecond"
-// CHECK020-NOT: "-lstandalone"
-// CHECK020: "-lc" "-lgcc" "--end-group"
-// CHECK020: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -moslib=first -moslib=second -moslib=standalone\
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK021 %s
-// CHECK021: "-cc1"
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK021-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK021-NOT: "-static"
-// CHECK021-NOT: "-shared"
-// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK021: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK021: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK021: "-L{{.*}}/lib/gcc"
-// CHECK021: "-L{{.*}}/hexagon/lib/v4"
-// CHECK021: "-L{{.*}}/hexagon/lib"
-// CHECK021: "{{[^"]+}}.o"
-// CHECK021: "--start-group"
-// CHECK021: "-lfirst" "-lsecond"
-// CHECK021: "-lstandalone"
-// CHECK021: "-lc" "-lgcc" "--end-group"
-// CHECK021: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Other args to pass to linker
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clangxx -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -s \
-// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
-// RUN: -t \
-// RUN: -e start_here \
-// RUN: -uFoo -undefined Bar \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK022 %s
-// CHECK022: "-cc1"
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"{{.*}}
-// CHECK022-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
-// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
-// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
-// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
-// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
-// CHECK022: "-L{{.*}}/lib/gcc"
-// CHECK022: "-L{{.*}}/hexagon/lib/v4"
-// CHECK022: "-L{{.*}}/hexagon/lib"
-// CHECK022: "-s"
-// CHECK022: "-Tbss" "0xdead" "-Tdata" "0xbeef" "-Ttext" "0xcafe"
-// CHECK022: "-t"
-// CHECK022: "-u" "Foo" "-undefined" "Bar"
-// CHECK022: "{{[^"]+}}.o"
-// CHECK022: "-lstdc++" "-lm"
-// CHECK022: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
-// CHECK022: "{{.*}}/hexagon/lib/v4/fini.o"
-
-// -----------------------------------------------------------------------------
-// pic, small data threshold
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK023 %s
-// CHECK023: "-cc1"
-// CHECK023: "-mrelocation-model" "static"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK023-NOT: "-G{{[0-9]+}}"
-// CHECK023-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK023-NOT: "-G{{[0-9]+}}"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -fpic \
-// RUN: %s 2>&1 \
-// RUN: | sed -e "s/\.exe//" -e "s/\.EXE//" | FileCheck -check-prefix=CHECK024 %s
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -fPIC \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK024 %s
-// CHECK024: "-cc1"
-// CHECK024-NOT: "-mrelocation-model" "static"
-// CHECK024: "-pic-level" "{{[12]}}"
-// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK024: "-G0"
-// CHECK024-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK024: "-G0"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -G=8 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -G 8 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -msmall-data-threshold=8 \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK025 %s
-// CHECK025: "-cc1"
-// CHECK025: "-mrelocation-model" "static"
-// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK025: "-G8"
-// CHECK025-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK025: "-G8"
-
-// -----------------------------------------------------------------------------
-// pie
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -pie \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK026 %s
-// CHECK026: "-cc1"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK026-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK026: "-pie"
-
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -pie -shared \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK027 %s
-// CHECK027: "-cc1"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK027-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-// CHECK027-NOT: "-pie"
-
-// -----------------------------------------------------------------------------
-// Misc Defaults
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK028 %s
-// CHECK028: "-cc1"
-// CHECK028: "-mqdsp6-compat"
-// CHECK028: "-Wreturn-type"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK028-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
-
-// -----------------------------------------------------------------------------
-// Test Assembler related args
-// -----------------------------------------------------------------------------
-// RUN: %clang -### -target hexagon-unknown-linux \
-// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
-// RUN: --gcc-toolchain="" \
-// RUN: -gdwarf-2 \
-// RUN: -Wa,--noexecstack,--trap \
-// RUN: -Xassembler --keep-locals \
-// RUN: %s 2>&1 \
-// RUN: | FileCheck -check-prefix=CHECK029 %s
-// CHECK029: "-cc1"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-as"
-// CHECK029: "--noexecstack" "--trap" "--keep-locals"
-// CHECK029-NEXT: "{{.*}}/bin{{/|\\\\}}hexagon-ld"
diff --git a/test/Driver/incremental-linker-compatible.c b/test/Driver/incremental-linker-compatible.c
new file mode 100644
index 0000000..e702a01
--- /dev/null
+++ b/test/Driver/incremental-linker-compatible.c
@@ -0,0 +1,17 @@
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -mincremental-linker-compatible 2>&1 | FileCheck %s --check-prefix=TEST1
+// TEST1: "-cc1" {{.*}} "-mincremental-linker-compatible"
+
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -mno-incremental-linker-compatible 2>&1 | FileCheck %s --check-prefix=TEST2
+// TEST2-NOT: "-cc1" {{.*}} "-mincremental-linker-compatible"
+
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -mno-incremental-linker-compatible -mincremental-linker-compatible 2>&1 | FileCheck %s --check-prefix=TEST3
+// TEST3: "-cc1" {{.*}} "-mincremental-linker-compatible"
+
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-linux-gnu -integrated-as -mincremental-linker-compatible -mno-incremental-linker-compatible 2>&1 | FileCheck %s --check-prefix=TEST4
+// TEST4-NOT: "-cc1" {{.*}} "-mincremental-linker-compatible"
+
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-mingw32 -integrated-as 2>&1 | FileCheck %s --check-prefix=TEST5
+// TEST5-NOT: "-cc1" {{.*}} "-mincremental-linker-compatible"
+
+// RUN: %clang '-###' %s -c -o tmp.o -target i686-pc-win32 -integrated-as 2>&1 | FileCheck %s --check-prefix=TEST6
+// TEST6: "-cc1" {{.*}} "-mincremental-linker-compatible"
diff --git a/test/Driver/instrprof-ld.c b/test/Driver/instrprof-ld.c
index b3ba12e..05f65d6 100644
--- a/test/Driver/instrprof-ld.c
+++ b/test/Driver/instrprof-ld.c
@@ -105,3 +105,19 @@
//
// CHECK-WATCHOS-ARMV7: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-WATCHOS-ARMV7: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_watchos.a"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-pc-win32 -fprofile-instr-generate \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefix=CHECK-WINDOWS-I386 %s
+//
+// CHECK-WINDOWS-I386: "{{.*}}link{{(.exe)?}}"
+// CHECK-WINDOWS-I386: "{{.*}}clang_rt.profile-i386.lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-pc-win32 -fprofile-instr-generate \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefix=CHECK-WINDOWS-X86-64 %s
+//
+// CHECK-WINDOWS-X86-64: "{{.*}}link{{(.exe)?}}"
+// CHECK-WINDOWS-X86-64: "{{.*}}clang_rt.profile-x86_64.lib"
diff --git a/test/Driver/mingw-libgcc.c b/test/Driver/mingw-libgcc.c
index c427eba..75a5696 100644
--- a/test/Driver/mingw-libgcc.c
+++ b/test/Driver/mingw-libgcc.c
@@ -1,25 +1,25 @@
-// Test if mingw toolchain driver emits static linking (-lgcc -lgcc_eh) or dynamic linking (-lgcc_s -lgcc).
-// Verified with gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project).
-
-// gcc, static
-// RUN: %clang -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static-libgcc -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static-libgcc -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-
-// gcc, dynamic
-// RUN: %clang -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
-
-// g++, static
-// RUN: %clang -static --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static-libgcc --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-// RUN: %clang -static-libgcc -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
-
-// g++, dynamic
-// RUN: %clang --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
-// RUN: %clang -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
-
-// CHECK_STATIC: "-lgcc" "-lgcc_eh"
-// CHECK_DYNAMIC: "-lgcc_s" "-lgcc"
+// Test if mingw toolchain driver emits static linking (-lgcc -lgcc_eh) or dynamic linking (-lgcc_s -lgcc).
+// Verified with gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project).
+
+// gcc, static
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static-libgcc -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static-libgcc -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+
+// gcc, dynamic
+// RUN: %clang -shared -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
+
+// g++, static
+// RUN: %clang -static --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static-libgcc --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+// RUN: %clang -static-libgcc -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_STATIC %s
+
+// g++, dynamic
+// RUN: %clang --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
+// RUN: %clang -shared --driver-mode=g++ -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DYNAMIC %s
+
+// CHECK_STATIC: "-lgcc" "-lgcc_eh"
+// CHECK_DYNAMIC: "-lgcc_s" "-lgcc"
diff --git a/test/Driver/mingw-useld.c b/test/Driver/mingw-useld.c
new file mode 100644
index 0000000..a0ab5a9
--- /dev/null
+++ b/test/Driver/mingw-useld.c
@@ -0,0 +1,19 @@
+// RUN: %clang -### -target i686-pc-windows-gnu --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_LD_32 %s
+// CHECK_LD_32: ld{{(.exe)?}}"
+// CHECK_LD_32: "i386pe"
+// CHECK_LD_32-NOT: "-flavor" "gnu"
+
+// RUN: %clang -### -target i686-pc-windows-gnu --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s -fuse-ld=lld 2>&1 | FileCheck -check-prefix=CHECK_LLD_32 %s
+// CHECK_LLD_32-NOT: invalid linker name in argument
+// CHECK_LLD_32: lld{{(.exe)?}}" "-flavor" "gnu"
+// CHECK_LLD_32: "i386pe"
+
+// RUN: %clang -### -target x86_64-pc-windows-gnu --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s -fuse-ld=lld 2>&1 | FileCheck -check-prefix=CHECK_LLD_64 %s
+// CHECK_LLD_64-NOT: invalid linker name in argument
+// CHECK_LLD_64: lld{{(.exe)?}}" "-flavor" "gnu"
+// CHECK_LLD_64: "i386pep"
+
+// RUN: %clang -### -target arm-pc-windows-gnu --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s -fuse-ld=lld 2>&1 | FileCheck -check-prefix=CHECK_LLD_ARM %s
+// CHECK_LLD_ARM-NOT: invalid linker name in argument
+// CHECK_LLD_ARM: lld{{(.exe)?}}" "-flavor" "gnu"
+// CHECK_LLD_ARM: "thumb2pe"
diff --git a/test/Driver/mingw.cpp b/test/Driver/mingw.cpp
index b638a64..8dc5b96 100644
--- a/test/Driver/mingw.cpp
+++ b/test/Driver/mingw.cpp
@@ -1,59 +1,59 @@
-// RUN: %clang -target i686-windows-gnu -c -### --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_CLANG_TREE %s
-// CHECK_MINGW_CLANG_TREE: "{{.*}}/Inputs/mingw_clang_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
-// CHECK_MINGW_CLANG_TREE: "{{.*}}/Inputs/mingw_clang_tree/mingw32{{/|\\\\}}include"
-
-
-// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_mingw_org_tree/mingw %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_ORG_TREE %s
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}mingw32"
-// CHECK_MINGW_ORG_TREE: "{{.*}}{{/|\\\\}}Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include-fixed"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}mingw32{{/|\\\\}}include"
-// CHECK_MINGW_ORG_TREE: {{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}include
-
-
-// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_mingw_builds_tree/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_BUILDS_TREE %s
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}i686-w64-mingw32"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include-fixed"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
-
-
-// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_msys2_tree/msys64/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_MSYS_TREE %s
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64{{/|\\\\}}mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}i686-w64-mingw32"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}backward"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include-fixed"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include"
-
-
-// RUN: %clang -target x86_64-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_opensuse_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_OPENSUSE_TREE %s
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}x86_64-w64-mingw32"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}x86_64-w64-mingw32/sys-root/mingw/include"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
-
-
-// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_arch_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_ARCH_TREE %s
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}i686-w64-mingw32"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}backward"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
-
-
-// RUN: %clang -target x86_64-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_ubuntu_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_UBUNTU_TREE %s
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}x86_64-w64-mingw32"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}backward"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include-fixed"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}include"
+// RUN: %clang -target i686-windows-gnu -c -### --sysroot=%S/Inputs/mingw_clang_tree/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_CLANG_TREE %s
+// CHECK_MINGW_CLANG_TREE: "{{.*}}/Inputs/mingw_clang_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
+// CHECK_MINGW_CLANG_TREE: "{{.*}}/Inputs/mingw_clang_tree/mingw32{{/|\\\\}}include"
+
+
+// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_mingw_org_tree/mingw %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_ORG_TREE %s
+// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++"
+// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}mingw32"
+// CHECK_MINGW_ORG_TREE: "{{.*}}{{/|\\\\}}Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
+// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include"
+// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include-fixed"
+// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}mingw32{{/|\\\\}}include"
+// CHECK_MINGW_ORG_TREE: {{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}include
+
+
+// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_mingw_builds_tree/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_BUILDS_TREE %s
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++"
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}i686-w64-mingw32"
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include"
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include-fixed"
+// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
+
+
+// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_msys2_tree/msys64/mingw32 %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_MSYS_TREE %s
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64{{/|\\\\}}mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}i686-w64-mingw32"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}backward"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include-fixed"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
+// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include"
+
+
+// RUN: %clang -target x86_64-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_opensuse_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_OPENSUSE_TREE %s
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++"
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}x86_64-w64-mingw32"
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}x86_64-w64-mingw32/sys-root/mingw/include"
+// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
+
+
+// RUN: %clang -target i686-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_arch_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_ARCH_TREE %s
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0"
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}i686-w64-mingw32"
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}backward"
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
+// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
+
+
+// RUN: %clang -target x86_64-pc-windows-gnu -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_ubuntu_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_UBUNTU_TREE %s
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8"
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}x86_64-w64-mingw32"
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}backward"
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include"
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include-fixed"
+// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}include"
diff --git a/test/Driver/mips-ias-Wa.s b/test/Driver/mips-ias-Wa.s
index 233d062..bc65872 100644
--- a/test/Driver/mips-ias-Wa.s
+++ b/test/Driver/mips-ias-Wa.s
@@ -47,3 +47,94 @@
// RUN: FileCheck -check-prefix=MSOFT-FLOAT-BOTH-MHARD-FLOAT-FIRST %s
// MSOFT-FLOAT-BOTH-MHARD-FLOAT-FIRST: -cc1as
// MSOFT-FLOAT-BOTH-MHARD-FLOAT-FIRST: "-target-feature" "-soft-float" "-target-feature" "+soft-float"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips1 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS1 %s
+// MIPS1: -cc1as
+// MIPS1: "-target-feature" "+mips1"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips2 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS2 %s
+// MIPS2: -cc1as
+// MIPS2: "-target-feature" "+mips2"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips3 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS3 %s
+// MIPS3: -cc1as
+// MIPS3: "-target-feature" "+mips3"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips4 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS4 %s
+// MIPS4: -cc1as
+// MIPS4: "-target-feature" "+mips4"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips5 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS5 %s
+// MIPS5: -cc1as
+// MIPS5: "-target-feature" "+mips5"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips32 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS32 %s
+// MIPS32: -cc1as
+// MIPS32: "-target-feature" "+mips32"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips32r2 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS32R2 %s
+// MIPS32R2: -cc1as
+// MIPS32R2: "-target-feature" "+mips32r2"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips32r3 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS32R3 %s
+// MIPS32R3: -cc1as
+// MIPS32R3: "-target-feature" "+mips32r3"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips32r5 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS32R5 %s
+// MIPS32R5: -cc1as
+// MIPS32R5: "-target-feature" "+mips32r5"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips32r6 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS32R6 %s
+// MIPS32R6: -cc1as
+// MIPS32R6: "-target-feature" "+mips32r6"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64 %s
+// MIPS64: -cc1as
+// MIPS64: "-target-feature" "+mips64"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64r2 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64R2 %s
+// MIPS64R2: -cc1as
+// MIPS64R2: "-target-feature" "+mips64r2"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64r3 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64R3 %s
+// MIPS64R3: -cc1as
+// MIPS64R3: "-target-feature" "+mips64r3"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64r5 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64R5 %s
+// MIPS64R5: -cc1as
+// MIPS64R5: "-target-feature" "+mips64r5"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64r6 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64R6 %s
+// MIPS64R6: -cc1as
+// MIPS64R6: "-target-feature" "+mips64r6"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64r2,-mips4 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64R2-MIPS4 %s
+// MIPS64R2-MIPS4: -cc1as
+// MIPS64R2-MIPS4-NOT: "-target-feature" "+mips64r2"
+// MIPS64R2-MIPS4: "-target-feature" "+mips4"
+// MIPS64R2-MIPS4-NOT: "-target-feature" "+mips64r2"
+
+// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -Wa,-mips64,-mips32,-mips32r2 2>&1 | \
+// RUN: FileCheck -check-prefix=MIPS64-MIPS32-MIPS32R2 %s
+// MIPS64-MIPS32-MIPS32R2: -cc1as
+// MIPS64-MIPS32-MIPS32R2-NOT: "-target-feature" "+mips64"
+// MIPS64-MIPS32-MIPS32R2-NOT: "-target-feature" "+mips32"
+// MIPS64-MIPS32-MIPS32R2: "-target-feature" "+mips32r2"
+// MIPS64-MIPS32-MIPS32R2-NOT: "-target-feature" "+mips64"
+// MIPS64-MIPS32-MIPS32R2-NOT: "-target-feature" "+mips32"
diff --git a/test/Driver/mips-mti-linux.c b/test/Driver/mips-mti-linux.c
new file mode 100644
index 0000000..e3560e2
--- /dev/null
+++ b/test/Driver/mips-mti-linux.c
@@ -0,0 +1,43 @@
+// Check frontend and linker invocations on GPL-free MIPS toolchain.
+//
+// FIXME: Using --sysroot with this toolchain/triple isn't supported. We use
+// it here to test that we are producing the correct paths/flags.
+// Ideally, we'd like to have an --llvm-toolchain option similar to
+// the --gcc-toolchain one.
+// REQUIRES: mips-registered-target
+
+// = Big-endian, mips32r2, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-mti-linux -mips32r2 -mhard-float \
+// RUN: --sysroot=%S/Inputs/mips_mti_linux/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32R2 %s
+//
+// CHECK-BE-HF-32R2: "{{[^"]*}}clang{{[^"]*}}" {{.*}} "-triple" "mips-mti-linux"
+// CHECK-BE-HF-32R2-SAME: "-fuse-init-array" "-target-cpu" "mips32r2"
+// CHECK-BE-HF-32R2-SAME: "-isysroot" "{{.*}}mips_mti_linux/sysroot"
+// CHECK-BE-HF-32R2: "{{[^"]*}}lld{{[^"]*}}" "-flavor" "old-gnu" "-target" "mips-mti-linux"
+// CHECK-BE-HF-32R2-SAME: "--sysroot=[[SYSROOT:[^"]+]]" {{.*}} "-dynamic-linker" "/lib/ld-musl-mips.so.1"
+// CHECK-BE-HF-32R2-SAME: "[[SYSROOT]]/mips-r2-hard-musl/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-BE-HF-32R2-SAME: "[[SYSROOT]]/mips-r2-hard-musl/usr/lib{{/|\\\\}}crti.o"
+// CHECK-BE-HF-32R2-SAME: "-L[[SYSROOT]]/mips-r2-hard-musl/usr/lib"
+// CHECK-BE-HF-32R2-SAME: "{{[^"]+}}/mips-r2-hard-musl{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-mips.a"
+// CHECK-BE-HF-32R2-SAME: "-lc"
+// CHECK-BE-HF-32R2-SAME: "[[SYSROOT]]/mips-r2-hard-musl/usr/lib{{/|\\\\}}crtn.o"
+
+// = Little-endian, mips32r2, hard float
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=mips-mti-linux -mips32r2 -EL -mhard-float \
+// RUN: --sysroot=%S/Inputs/mips_mti_linux/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-LE-HF-32R2 %s
+//
+// CHECK-LE-HF-32R2: "{{[^"]*}}clang{{[^"]*}}" {{.*}} "-triple" "mipsel-mti-linux"
+// CHECK-LE-HF-32R2-SAME: "-fuse-init-array" "-target-cpu" "mips32r2"
+// CHECK-LE-HF-32R2-SAME: "-isysroot" "{{.*}}mips_mti_linux/sysroot"
+// CHECK-LE-HF-32R2: "{{[^"]*}}lld{{[^"]*}}" "-flavor" "old-gnu" "-target" "mipsel-mti-linux"
+// CHECK-LE-HF-32R2-SAME: "--sysroot=[[SYSROOT:[^"]+]]" {{.*}} "-dynamic-linker" "/lib/ld-musl-mipsel.so.1"
+// CHECK-LE-HF-32R2-SAME: "[[SYSROOT]]/mipsel-r2-hard-musl/usr/lib{{/|\\\\}}crt1.o"
+// CHECK-LE-HF-32R2-SAME: "[[SYSROOT]]/mipsel-r2-hard-musl/usr/lib{{/|\\\\}}crti.o"
+// CHECK-LE-HF-32R2-SAME: "-L[[SYSROOT]]/mipsel-r2-hard-musl/usr/lib"
+// CHECK-LE-HF-32R2-SAME: "{{[^"]+}}/mipsel-r2-hard-musl{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-mips.a"
+// CHECK-LE-HF-32R2-SAME: "-lc"
+// CHECK-LE-HF-32R2-SAME: "[[SYSROOT]]/mipsel-r2-hard-musl/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/ms-bitfields.c b/test/Driver/ms-bitfields.c
new file mode 100644
index 0000000..7bf9aaa
--- /dev/null
+++ b/test/Driver/ms-bitfields.c
@@ -0,0 +1,8 @@
+// RUN: %clang -### %s 2>&1 | FileCheck %s -check-prefix=NO-MSBITFIELDS
+// RUN: %clang -### -mno-ms-bitfields -mms-bitfields %s 2>&1 | FileCheck %s -check-prefix=MSBITFIELDS
+// RUN: %clang -### -mms-bitfields -mno-ms-bitfields %s 2>&1 | FileCheck %s -check-prefix=NO-MSBITFIELDS
+
+// MSBITFIELDS: -mms-bitfields
+// NO-MSBITFIELDS-NOT: -mms-bitfields
+
+// REQUIRES: clang-driver
diff --git a/test/Driver/myriad-toolchain.c b/test/Driver/myriad-toolchain.c
index 054fe34..6c94cff 100644
--- a/test/Driver/myriad-toolchain.c
+++ b/test/Driver/myriad-toolchain.c
@@ -1,15 +1,15 @@
// RUN: %clang -no-canonical-prefixes -### -target sparc-myriad-rtems-elf %s \
-// RUN: -B %S/Inputs/basic_myriad_tree 2>&1 | FileCheck %s -check-prefix=LINK_WITH_RTEMS
-// LINK_WITH_RTEMS: Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crti.o
-// LINK_WITH_RTEMS: Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtbegin.o
+// RUN: --gcc-toolchain=%S/Inputs/basic_myriad_tree 2>&1 | FileCheck %s -check-prefix=LINK_WITH_RTEMS
+// LINK_WITH_RTEMS: Inputs{{.*}}crti.o
+// LINK_WITH_RTEMS: Inputs{{.*}}crtbegin.o
// LINK_WITH_RTEMS: "-L{{.*}}Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/../../..{{/|\\\\}}../sparc-myriad-elf/lib"
// LINK_WITH_RTEMS: "-L{{.*}}Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2"
// LINK_WITH_RTEMS: "--start-group" "-lc" "-lrtemscpu" "-lrtemsbsp" "--end-group" "-lgcc"
-// LINK_WITH_RTEMS: Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtend.o
-// LINK_WITH_RTEMS: Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/crtn.o
+// LINK_WITH_RTEMS: Inputs{{.*}}crtend.o
+// LINK_WITH_RTEMS: Inputs{{.*}}crtn.o
// RUN: %clang -c -no-canonical-prefixes -### -target sparc-myriad-rtems-elf -x c++ %s \
-// RUN: -B %S/Inputs/basic_myriad_tree 2>&1 | FileCheck %s -check-prefix=COMPILE_CXX
+// RUN: --gcc-toolchain=%S/Inputs/basic_myriad_tree 2>&1 | FileCheck %s -check-prefix=COMPILE_CXX
// COMPILE_CXX: "-internal-isystem" "{{.*}}/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/../../../../sparc-myriad-elf/include/c++/4.8.2"
// COMPILE_CXX: "-internal-isystem" "{{.*}}/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/../../../../sparc-myriad-elf/include/c++/4.8.2/sparc-myriad-elf"
// COMPILE_CXX: "-internal-isystem" "{{.*}}/Inputs/basic_myriad_tree/lib/gcc/sparc-myriad-elf/4.8.2/../../../../sparc-myriad-elf/include/c++/4.8.2/backward"
@@ -38,8 +38,8 @@
// RUN: %clang -target shave-myriad -c -### %s -isystem somewhere -Icommon -Wa,-yippee 2>&1 \
// RUN: | FileCheck %s -check-prefix=MOVICOMPILE
-// MOVICOMPILE: moviCompile" "-DMYRIAD2" "-mcpu=myriad2" "-S" "-isystem" "somewhere" "-I" "common"
-// MOVICOMPILE: moviAsm" "-no6thSlotCompression" "-cv:myriad2" "-noSPrefixing" "-a"
+// MOVICOMPILE: moviCompile{{(.exe)?}}" "-S" "-fno-exceptions" "-mcpu=myriad2" "-DMYRIAD2" "-isystem" "somewhere" "-I" "common"
+// MOVICOMPILE: moviAsm{{(.exe)?}}" "-no6thSlotCompression" "-cv:myriad2" "-noSPrefixing" "-a"
// MOVICOMPILE: "-yippee" "-i:somewhere" "-i:common" "-elf"
// RUN: %clang -target shave-myriad -c -### %s -DEFINE_ME -UNDEFINE_ME 2>&1 \
@@ -58,12 +58,21 @@
// RUN: %clang -target shave-myriad -c %s -o foo.o -### -MD -MF dep.d 2>&1 \
// RUN: | FileCheck %s -check-prefix=MDMF
-// MDMF: "-S" "-MD" "-MF" "dep.d" "-MT" "foo.o"
+// MDMF: "-S" "-fno-exceptions" "-mcpu=myriad2" "-DMYRIAD2" "-MD" "-MF" "dep.d" "-MT" "foo.o"
+
+// RUN: %clang -target shave-myriad -std=gnu++11 -S %s -o foo.o -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=STDEQ
+// STDEQ: "-S" "-fno-exceptions" "-mcpu=myriad2" "-DMYRIAD2" "-std=gnu++11"
+
+// RUN: %clang -target shave-myriad -E -Ifoo %s -o foo.i -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=PREPROCESS
+// PREPROCESS: "-E" "-mcpu=myriad2" "-DMYRIAD2" "-I" "foo"
// RUN: %clang -target sparc-myriad -### --driver-mode=g++ %s 2>&1 | FileCheck %s --check-prefix=STDLIBCXX
// STDLIBCXX: "-lstdc++" "-lc" "-lgcc"
// RUN: %clang -target sparc-myriad -### -nostdlib %s 2>&1 | FileCheck %s --check-prefix=NOSTDLIB
+// NOSTDLIB-NOT: crtbegin.o
// NOSTDLIB-NOT: "-lc"
// RUN: %clang -### -c -g %s -target sparc-myriad 2>&1 | FileCheck -check-prefix=G_SPARC %s
diff --git a/test/Driver/nodefaultlib.c b/test/Driver/nodefaultlib.c
index f9462fd..08bcea5 100644
--- a/test/Driver/nodefaultlib.c
+++ b/test/Driver/nodefaultlib.c
@@ -1,8 +1,10 @@
-// RUN: %clang -target i686-pc-linux-gnu -### -nodefaultlibs %s 2> %t
-// RUN: FileCheck < %t %s
-//
-// CHECK-NOT: start-group
-// CHECK-NOT: "-lgcc"
-// CHECK-NOT: "-lc"
-// CHECK: crtbegin
-// CHECK: crtend
+// RUN: %clang -target i686-pc-linux-gnu -### -nodefaultlibs %s 2>&1 | FileCheck -check-prefix=TEST1 %s
+// TEST1-NOT: start-group
+// TEST1-NOT: "-lgcc"
+// TEST1-NOT: "-lc"
+// TEST1: crtbegin
+// TEST1: crtend
+
+// RUN: %clang -target i686-pc-linux-gnu -stdlib=libc++ -nodefaultlibs -lstdc++ -### %s 2>&1 | FileCheck -check-prefix=TEST2 %s
+// TEST2-NOT: "-lc++"
+// TEST2: "-lstdc++"
diff --git a/test/Driver/nostdlib.c b/test/Driver/nostdlib.c
index e9ada31..47c6f8b 100644
--- a/test/Driver/nostdlib.c
+++ b/test/Driver/nostdlib.c
@@ -2,3 +2,26 @@
// RUN: FileCheck < %t %s
//
// CHECK-NOT: start-group
+
+// Most of the toolchains would check for -nostartfiles and -nostdlib
+// in a short-circuiting boolean expression, so if both of the preceding
+// options were present, the second would warn about being unused.
+// RUN: %clang -### -nostartfiles -nostdlib -target i386-apple-darwin %s \
+// RUN: 2>&1 | FileCheck %s -check-prefix=ARGSCLAIMED
+// ARGSCLAIMED-NOT: warning:
+
+// In the presence of -nostdlib, the standard libraries should not be
+// passed down to link line
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i686-pc-linux-gnu -nostdlib --rtlib=compiler-rt \
+// RUN: -resource-dir=%S/Inputs/resource_dir -lclang_rt.builtins-i686 \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX-NOSTDLIB %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i686-pc-linux-gnu --rtlib=compiler-rt -nostdlib \
+// RUN: -resource-dir=%S/Inputs/resource_dir -lclang_rt.builtins-i686 \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX-NOSTDLIB %s
+//
+// CHECK-LINUX-NOSTDLIB: warning: argument unused during compilation: '--rtlib=compiler-rt'
+// CHECK-LINUX-NOSTDLIB: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-LINUX-NOSTDLIB-NOT: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-i686.a"
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index ca4b892..aeb2ee3 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -217,7 +217,9 @@
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=5.0.0 -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=6.0.0 -static -### 2>&1 \
-// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target armv7-apple-unknown-macho -static -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
//
// On OpenBSD, PIE is enabled by default, but can be disabled.
// RUN: %clang -c %s -target amd64-pc-openbsd -### 2>&1 \
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index 947183c..34c1ce5 100644
--- a/test/Driver/ppc-features.cpp
+++ b/test/Driver/ppc-features.cpp
@@ -12,6 +12,50 @@
// RUN: not %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
// RUN: not %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// check -msoft-float option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT %s
+// CHECK-SOFTFLOAT: "-target-feature" "+soft-float"
+
+// check -mfloat-abi=soft option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT %s
+// CHECK-FLOATABISOFT: "-target-feature" "+soft-float"
+
+// check -mhard-float option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -mhard-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-HARDFLOAT %s
+// CHECK-HARDFLOAT-NOT: "-target-feature" "+soft-float"
+
+// check -mfloat-abi=hard option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=hard -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABIHARD %s
+// CHECK-FLOATABIHARD-NOT: "-target-feature" "+soft-float"
+
+// check combine -mhard-float -msoft-float option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -mhard-float -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-HARDSOFT %s
+// CHECK-HARDSOFT: "-target-feature" "+soft-float"
+
+// check combine -msoft-float -mhard-float option for ppc32
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -msoft-float -mhard-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTHARD %s
+// CHECK-SOFTHARD-NOT: "-target-feature" "+soft-float"
+
+// check -mfloat-abi=x option
+// RUN: %clang -target powerpc-unknown-linux-gnu %s -mfloat-abi=x -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-ERRMSG %s
+// CHECK-ERRMSG: error: invalid float ABI '-mfloat-abi=x'
+
+// check -msoft-float option for ppc64
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT64 %s
+// CHECK-SOFTFLOAT64: error: invalid float ABI 'soft float is not supported for ppc64'
+
+// check -mfloat-abi=soft option for ppc64
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT64 %s
+// CHECK-FLOATABISOFT64: error: invalid float ABI 'soft float is not supported for ppc64'
+
+// check -msoft-float option for ppc64
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT64le %s
+// CHECK-SOFTFLOAT64le: error: invalid float ABI 'soft float is not supported for ppc64'
+
+// check -mfloat-abi=soft option for ppc64
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT64le %s
+// CHECK-FLOATABISOFT64le: error: invalid float ABI 'soft float is not supported for ppc64'
+
// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64/ppc64le'
// Check that -fno-altivec and -mno-altivec correctly disable the altivec
diff --git a/test/Driver/ps4-analyzer-defaults.cpp b/test/Driver/ps4-analyzer-defaults.cpp
new file mode 100644
index 0000000..f5aacc6
--- /dev/null
+++ b/test/Driver/ps4-analyzer-defaults.cpp
@@ -0,0 +1,33 @@
+// Check that the default analyzer checkers for PS4 are:
+// core
+// cplusplus
+// deadcode
+// nullability
+// unix
+// Excluding:
+// unix.API
+// unix.Vfork
+
+// Check for expected checkers
+// RUN: %clang -target x86_64-scei-ps4 --analyze %s -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PS4-POS-CHECKERS
+//
+// Negative check for unexpected checkers
+// RUN: %clang -target x86_64-scei-ps4 --analyze %s -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PS4-NEG-CHECKERS
+//
+// Check for all unix checkers except API and Vfork
+// RUN: %clang -target x86_64-scei-ps4 --analyze %s -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PS4-UNIX-CHECKERS
+
+// CHECK-PS4-POS-CHECKERS-DAG: analyzer-checker=core
+// CHECK-PS4-POS-CHECKERS-DAG: analyzer-checker=cplusplus
+// CHECK-PS4-POS-CHECKERS-DAG: analyzer-checker=deadcode
+// CHECK-PS4-POS-CHECKERS-DAG: analyzer-checker=nullability
+//
+// CHECK-PS4-NEG-CHECKERS-NOT: analyzer-checker={{osx|security}}
+//
+// CHECK-PS4-UNIX-CHECKERS: analyzer-checker=unix
+// CHECK-PS4-UNIX-CHECKERS-DAG: analyzer-disable-checker=unix.API
+// CHECK-PS4-UNIX-CHECKERS-DAG: analyzer-disable-checker=unix.Vfork
+// CHECK-PS4-UNIX-CHECKERS-NOT: analyzer-checker=unix.{{API|Vfork}}
diff --git a/test/Driver/ps4-runtime-flags.c b/test/Driver/ps4-runtime-flags.c
new file mode 100644
index 0000000..315976d
--- /dev/null
+++ b/test/Driver/ps4-runtime-flags.c
@@ -0,0 +1,19 @@
+// REQUIRES: x86-registered-target
+//
+// Test the profile runtime library to be linked for PS4 compiler.
+// Check PS4 runtime flag --dependent-lib which does not append the default library search path.
+//
+// RUN: %clang -target x86_64-scei-ps4 --coverage %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-arcs %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fno-profile-arcs -fprofile-arcs %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fno-profile-arcs %s -### 2>&1 | FileCheck -check-prefix=CHECK-PS4-NO-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-arcs -fno-profile-arcs %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-NO-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-generate %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fno-profile-generate %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-NO-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-generate=dir %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-instr-generate %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fno-profile-instr-generate %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-NO-PROFILE %s
+// RUN: %clang -target x86_64-scei-ps4 -fprofile-instr-generate=somefile.profraw %s -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-PROFILE %s
+//
+// CHECK-PS4-PROFILE: "--dependent-lib=libclang_rt.profile-x86_64.a"
+// CHECK-PS4-NO-PROFILE-NOT: "--dependent-lib=libclang_rt.profile-x86_64.a"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index a4ea755..4aa0fa4 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -291,6 +291,40 @@
// CHECK-LSAN-ASAN-LINUX: libclang_rt.asan-x86_64
// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
+// CFI by itself does not link runtime libraries.
+// RUN: %clang -fsanitize=cfi %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-LINUX %s
+// CHECK-CFI-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-LINUX-NOT: libclang_rt.
+
+// CFI with diagnostics links the UBSan runtime.
+// RUN: %clang -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-recover=cfi \
+// RUN: %s -### -o %t.o 2>&1\
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-DIAG-LINUX %s
+// CHECK-CFI-DIAG-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-DIAG-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.ubsan_standalone-x86_64.a" "-no-whole-archive"
+
+// Cross-DSO CFI links the CFI runtime.
+// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-LINUX %s
+// CHECK-CFI-CROSS-DSO-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-CROSS-DSO-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.cfi-x86_64.a" "-no-whole-archive"
+
+// Cross-DSO CFI with diagnostics links just the CFI runtime.
+// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
+// RUN: -fno-sanitize-trap=cfi -fsanitize-recover=cfi \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-DIAG-LINUX %s
+// CHECK-CFI-CROSS-DSO-DIAG-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-CROSS-DSO-DIAG-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.cfi_diag-x86_64.a" "-no-whole-archive"
+
// RUN: %clangxx -fsanitize=address %s -### -o %t.o 2>&1 \
// RUN: -mmacosx-version-min=10.6 \
// RUN: -target x86_64-apple-darwin13.4.0 \
@@ -311,6 +345,39 @@
// CHECK-SAFESTACK-LINUX: "-lpthread"
// CHECK-SAFESTACK-LINUX: "-ldl"
+// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-LINUX %s
+// CHECK-CFI-STATS-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-STATS-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.stats_client-x86_64.a" "-no-whole-archive"
+// CHECK-CFI-STATS-LINUX-NOT: "-whole-archive"
+// CHECK-CFI-STATS-LINUX: "{{[^"]*}}libclang_rt.stats-x86_64.a"
+
+// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-apple-darwin \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-DARWIN %s
+// CHECK-CFI-STATS-DARWIN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_client_osx.a"
+// CHECK-CFI-STATS-DARWIN: "{{[^"]*}}libclang_rt.stats_osx_dynamic.dylib"
+
+// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-pc-windows \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN64 %s
+// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats_client-x86_64.lib"
+// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats-x86_64.lib"
+// CHECK-CFI-STATS-WIN64: "--linker-option=/include:__sanitizer_stats_register"
+
+// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
+// RUN: -target i686-pc-windows \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN32 %s
+// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats_client-i386.lib"
+// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats-i386.lib"
+// CHECK-CFI-STATS-WIN32: "--linker-option=/include:___sanitizer_stats_register"
+
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
@@ -339,19 +406,19 @@
// RUN: -target x86_64-scei-ps4 \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-PS4 %s
-// CHECK-UBSAN-PS4: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-UBSAN-PS4: -lSceDbgUBSanitizer_stub_weak
// RUN: %clang -fsanitize=address %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-scei-ps4 \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-PS4 %s
-// CHECK-ASAN-PS4: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-ASAN-PS4: -lSceDbgAddressSanitizer_stub_weak
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-scei-ps4 \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-AUBSAN-PS4 %s
-// CHECK-AUBSAN-PS4: "{{.*}}ld{{(.exe)?}}"
+// CHECK-AUBSAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-AUBSAN-PS4: -lSceDbgAddressSanitizer_stub_weak
diff --git a/test/Driver/sparc-as.c b/test/Driver/sparc-as.c
index d44e845..5b93995 100644
--- a/test/Driver/sparc-as.c
+++ b/test/Driver/sparc-as.c
@@ -1,3 +1,17 @@
+// Make sure Sparc does not use the integrated assembler by default.
+
+// RUN: %clang -target sparc-linux -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-IAS %s
+
+// RUN: %clang -target sparc-linux -fintegrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=IAS %s
+
+// RUN: %clang -target sparc-linux -fno-integrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-IAS %s
+
+// IAS-NOT: "-no-integrated-as"
+// NO-IAS: "-no-integrated-as"
+
// RUN: %clang -no-canonical-prefixes -target sparc--netbsd \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
diff --git a/test/Driver/sparcv9-as.c b/test/Driver/sparcv9-as.c
index 9e6249c..3b641cc 100644
--- a/test/Driver/sparcv9-as.c
+++ b/test/Driver/sparcv9-as.c
@@ -1,3 +1,17 @@
+// Make sure SparcV9 does not use the integrated assembler by default.
+
+// RUN: %clang -target sparcv9-linux -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-IAS %s
+
+// RUN: %clang -target sparcv9-linux -fintegrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=IAS %s
+
+// RUN: %clang -target sparcv9-linux -fno-integrated-as -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-IAS %s
+
+// IAS-NOT: "-no-integrated-as"
+// NO-IAS: "-no-integrated-as"
+
// RUN: %clang -no-canonical-prefixes -target sparcv9--netbsd \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c
index 73206a5..ed66852 100644
--- a/test/Driver/split-debug.c
+++ b/test/Driver/split-debug.c
@@ -45,3 +45,16 @@
//
// CHECK-SPLIT-OVER-GMLT: "-split-dwarf=Enable" "-debug-info-kind=limited"
// CHECK-SPLIT-OVER-GMLT: "-split-dwarf-file"
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -g0 -S -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-G0-OVER-SPLIT < %t %s
+//
+// CHECK-G0-OVER-SPLIT-NOT: "-debug-info-kind
+// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf=Enable"
+// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf-file"
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -g0 -gsplit-dwarf -S -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-SPLIT-OVER-G0 < %t %s
+//
+// CHECK-SPLIT-OVER-G0: "-split-dwarf=Enable" "-debug-info-kind=limited"
+// CHECK-SPLIT-OVER-G0: "-split-dwarf-file"
diff --git a/test/Driver/thinlto_backend.c b/test/Driver/thinlto_backend.c
new file mode 100644
index 0000000..6def582
--- /dev/null
+++ b/test/Driver/thinlto_backend.c
@@ -0,0 +1,10 @@
+// RUN: %clang -O2 %s -flto=thin -c -o %t.o
+// RUN: llvm-lto -thinlto -o %t %t.o
+
+// -fthinlto_index should be passed to cc1
+// RUN: %clang -O2 -o %t1.o -x ir %t.o -c -fthinlto-index=%t.thinlto.bc -### 2>&1 | FileCheck %s -check-prefix=CHECK-THINLTOBE-ACTION
+// CHECK-THINLTOBE-ACTION: -fthinlto-index=
+
+// Ensure clang driver gives the expected error for incorrect input type
+// RUN: not %clang -O2 -o %t1.o %s -c -fthinlto-index=%t.thinlto.bc 2>&1 | FileCheck %s -check-prefix=CHECK-WARNING
+// CHECK-WARNING: error: invalid argument '-fthinlto-index={{.*}}' only allowed with '-x ir'
diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
new file mode 100644
index 0000000..b9685b1
--- /dev/null
+++ b/test/Driver/wasm-toolchain.c
@@ -0,0 +1,44 @@
+// A basic clang -cc1 command-line. WebAssembly is somewhat special in
+// enabling -ffunction-sections, -fdata-sections, and -fvisibility=hidden by
+// default.
+
+// RUN: %clang %s -### -no-canonical-prefixes -target wasm32-unknown-unknown 2>&1 | FileCheck -check-prefix=CC1 %s
+// CC1: clang{{.*}} "-cc1" "-triple" "wasm32-unknown-unknown" {{.*}} "-fvisibility" "hidden" {{.*}} "-ffunction-sections" "-fdata-sections"
+
+// Ditto, but ensure that a user -fno-function-sections disables the
+// default -ffunction-sections.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fno-function-sections 2>&1 | FileCheck -check-prefix=NO_FUNCTION_SECTIONS %s
+// NO_FUNCTION_SECTIONS-NOT: function-sections
+
+// Ditto, but ensure that a user -fno-data-sections disables the
+// default -fdata-sections.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fno-data-sections 2>&1 | FileCheck -check-prefix=NO_DATA_SECTIONS %s
+// NO_DATA_SECTIONS-NOT: data-sections
+
+// Ditto, but ensure that a user -fvisibility=default disables the default
+// -fvisibility=hidden.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fvisibility=default 2>&1 | FileCheck -check-prefix=FVISIBILITY_DEFAULT %s
+// FVISIBILITY_DEFAULT-NOT: hidden
+
+// A basic C link command-line.
+
+// RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown %s 2>&1 | FileCheck -check-prefix=LINK %s
+// LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// LINK: lld{{.*}}" "-flavor" "ld" "[[temp]]" "-o" "a.out"
+
+// A basic C link command-line with optimization. WebAssembly is somewhat
+// special in enabling --gc-sections by default.
+
+// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
+// LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// LINK_OPT: lld{{.*}}" "-flavor" "ld" "--gc-sections" "[[temp]]" "-o" "a.out"
+
+// Ditto, but ensure that a user --no-gc-sections comes after the
+// default --gc-sections.
+
+// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown -Wl,--no-gc-sections %s 2>&1 | FileCheck -check-prefix=NO_GC_SECTIONS %s
+// NO_GC_SECTIONS: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// NO_GC_SECTIONS: lld{{.*}}" "-flavor" "ld" "--gc-sections" "--no-gc-sections" "[[temp]]" "-o" "a.out"
diff --git a/test/Driver/wasm32-unknown-unknown.cpp b/test/Driver/wasm32-unknown-unknown.cpp
index e6fbb62..3f44d93 100644
--- a/test/Driver/wasm32-unknown-unknown.cpp
+++ b/test/Driver/wasm32-unknown-unknown.cpp
@@ -13,34 +13,34 @@
extern "C" {
-// CHECK: @align_c = global i32 1
+// CHECK: @align_c = hidden global i32 1
int align_c = __alignof(char);
-// CHECK: @align_s = global i32 2
+// CHECK: @align_s = hidden global i32 2
int align_s = __alignof(short);
-// CHECK: @align_i = global i32 4
+// CHECK: @align_i = hidden global i32 4
int align_i = __alignof(int);
-// CHECK: @align_l = global i32 4
+// CHECK: @align_l = hidden global i32 4
int align_l = __alignof(long);
-// CHECK: @align_ll = global i32 8
+// CHECK: @align_ll = hidden global i32 8
int align_ll = __alignof(long long);
-// CHECK: @align_p = global i32 4
+// CHECK: @align_p = hidden global i32 4
int align_p = __alignof(void*);
-// CHECK: @align_f = global i32 4
+// CHECK: @align_f = hidden global i32 4
int align_f = __alignof(float);
-// CHECK: @align_d = global i32 8
+// CHECK: @align_d = hidden global i32 8
int align_d = __alignof(double);
-// CHECK: @align_ld = global i32 8
+// CHECK: @align_ld = hidden global i32 16
int align_ld = __alignof(long double);
-// CHECK: @align_vl = global i32 4
+// CHECK: @align_vl = hidden global i32 4
int align_vl = __alignof(va_list);
// CHECK: _GNU_SOURCEdefined
@@ -97,7 +97,7 @@
// CHECK: double @check_double()
double check_double() { return 0; }
-// CHECK: double @check_longdouble()
+// CHECK: fp128 @check_longdouble()
long double check_longdouble() { return 0; }
}
diff --git a/test/Driver/wasm64-unknown-unknown.cpp b/test/Driver/wasm64-unknown-unknown.cpp
index 78b8c76..6162759 100644
--- a/test/Driver/wasm64-unknown-unknown.cpp
+++ b/test/Driver/wasm64-unknown-unknown.cpp
@@ -13,34 +13,34 @@
extern "C" {
-// CHECK: @align_c = global i32 1
+// CHECK: @align_c = hidden global i32 1
int align_c = __alignof(char);
-// CHECK: @align_s = global i32 2
+// CHECK: @align_s = hidden global i32 2
int align_s = __alignof(short);
-// CHECK: @align_i = global i32 4
+// CHECK: @align_i = hidden global i32 4
int align_i = __alignof(int);
-// CHECK: @align_l = global i32 8
+// CHECK: @align_l = hidden global i32 8
int align_l = __alignof(long);
-// CHECK: @align_ll = global i32 8
+// CHECK: @align_ll = hidden global i32 8
int align_ll = __alignof(long long);
-// CHECK: @align_p = global i32 8
+// CHECK: @align_p = hidden global i32 8
int align_p = __alignof(void*);
-// CHECK: @align_f = global i32 4
+// CHECK: @align_f = hidden global i32 4
int align_f = __alignof(float);
-// CHECK: @align_d = global i32 8
+// CHECK: @align_d = hidden global i32 8
int align_d = __alignof(double);
-// CHECK: @align_ld = global i32 8
+// CHECK: @align_ld = hidden global i32 16
int align_ld = __alignof(long double);
-// CHECK: @align_vl = global i32 8
+// CHECK: @align_vl = hidden global i32 8
int align_vl = __alignof(va_list);
// CHECK: _GNU_SOURCEdefined
@@ -97,7 +97,7 @@
// CHECK: double @check_double()
double check_double() { return 0; }
-// CHECK: double @check_longdouble()
+// CHECK: fp128 @check_longdouble()
long double check_longdouble() { return 0; }
}
diff --git a/test/FixIt/fixit-vexing-parse.cpp b/test/FixIt/fixit-vexing-parse.cpp
index 79d8cad..0232f5d 100644
--- a/test/FixIt/fixit-vexing-parse.cpp
+++ b/test/FixIt/fixit-vexing-parse.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -verify -x c++ %s
-// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -verify -x c++ -std=c++98 %s
+// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++98 %s 2>&1 | FileCheck %s
struct S {
int n;
diff --git a/test/Format/cursor.cpp b/test/Format/cursor.cpp
index b0a2fbd..e41c0d5 100644
--- a/test/Format/cursor.cpp
+++ b/test/Format/cursor.cpp
@@ -1,5 +1,5 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s | clang-format -style=LLVM -cursor=6 \
// RUN: | FileCheck -strict-whitespace %s
-// CHECK: {{^\{ "Cursor": 4, }}
+// CHECK: {{^\{ "Cursor": 3, }}
// CHECK: {{^int\ \i;$}}
int i;
diff --git a/test/Format/disable-include-sorting.cpp b/test/Format/disable-include-sorting.cpp
new file mode 100644
index 0000000..875a0af
--- /dev/null
+++ b/test/Format/disable-include-sorting.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-format %s | FileCheck %s
+// RUN: clang-format %s -sort-includes -style="{SortIncludes: false}" | FileCheck %s
+// RUN: clang-format %s -sort-includes=false | FileCheck %s -check-prefix=NOT-SORTED
+
+#include <b>
+#include <a>
+// CHECK: <a>
+// CHECK-NEXT: <b>
+// NOT-SORTED: <b>
+// NOT-SORTED-NEXT: <a>
diff --git a/test/Index/cindex-test-inclusions.c b/test/Index/cindex-test-inclusions.c
index 9c7de2e..b85cd24 100644
--- a/test/Index/cindex-test-inclusions.c
+++ b/test/Index/cindex-test-inclusions.c
@@ -11,3 +11,14 @@
// CHECK: included by:
// CHECK: include_test.h:1:10
// CHECK: cindex-test-inclusions.c:3:10
+
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-inclusion-stack-source %s 2>&1 | FileCheck -check-prefix=REPARSE %s
+// REPARSE: include_test_2.h
+// REPARSE: included by:
+// REPARSE: include_test.h:1:10
+// REPARSE: cindex-test-inclusions.c:3:10
+// REPARSE: include_test.h
+// REPARSE: included by:
+// REPARSE: cindex-test-inclusions.c:3:10
+// REPARSE: cindex-test-inclusions.c
+// REPARSE: included by:
diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp
index d873076..6c10efe 100644
--- a/test/Index/comment-to-html-xml-conversion.cpp
+++ b/test/Index/comment-to-html-xml-conversion.cpp
@@ -800,7 +800,7 @@
template<typename T>
using comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int>;
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@S@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template <typename T>\nusing comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int></Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: TypeAliasTemplateDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@S@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template <typename T>\nusing comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int></Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
};
/// Aaa.
diff --git a/test/Index/complete-preamble.cpp b/test/Index/complete-preamble.cpp
index c57c88a..15720f9 100644
--- a/test/Index/complete-preamble.cpp
+++ b/test/Index/complete-preamble.cpp
@@ -3,6 +3,15 @@
std::
}
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50)
+// RUN: env CINDEXTEST_EDITING=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=SECOND %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=FIRST %s
+// FIRST: Precompiling preamble
+// FIRST: Parsing
+// FIRST: Reparsing
+
+// SECOND: Parsing
+// SECOND: Precompiling preamble
+// SECOND: Reparsing
+
+// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50)
diff --git a/test/Index/evaluate-cursor.cpp b/test/Index/evaluate-cursor.cpp
new file mode 100644
index 0000000..28a9c36
--- /dev/null
+++ b/test/Index/evaluate-cursor.cpp
@@ -0,0 +1,30 @@
+// Test is line- and column-sensitive. Run lines are below.
+
+struct Foo {
+ int x = 10;
+};
+
+void foo() {
+ int p = 11;
+}
+
+#define FUNC_MAC(x) x
+
+void goo() {
+ int p = FUNC_MAC(1);
+ int a = __LINE__;
+}
+
+// RUN: c-index-test -evaluate-cursor-at=%s:4:7 \
+// RUN: -evaluate-cursor-at=%s:8:7 \
+// RUN: -evaluate-cursor-at=%s:8:11 -std=c++11 %s | FileCheck %s
+// CHECK: Value: 10
+// CHECK: Value: 11
+// CHECK: Value: 11
+
+// RUN: c-index-test -get-macro-info-cursor-at=%s:11:9 \
+// RUN: -get-macro-info-cursor-at=%s:14:11 \
+// RUN: -get-macro-info-cursor-at=%s:15:11 -std=c++11 %s | FileCheck -check-prefix=CHECK-MACRO %s
+// CHECK-MACRO: [function macro]
+// CHECK-MACRO: [function macro]
+// CHECK-MACRO: [builtin macro]
diff --git a/test/Index/index-attrs.c b/test/Index/index-attrs.c
new file mode 100644
index 0000000..d526721
--- /dev/null
+++ b/test/Index/index-attrs.c
@@ -0,0 +1,16 @@
+// RUN: c-index-test -index-file -check-prefix CHECK %s -target armv7-windows-gnu -fdeclspec
+
+void __declspec(dllexport) export_function(void) {}
+// CHECK: [indexDeclaraton]: kind: function | name: export_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllexport)
+void __attribute__((dllexport)) export_gnu_attribute(void) {}
+// CHECK: [indexDeclaration] kind: function | name: export_gnu_attribute | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllexport)
+
+void __declspec(dllimport) import_function(void);
+// CHECK: [indexDeclaration] kind: function | name: import_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllimport)
+void __attribute__((dllimport)) import_gnu_attribute(void);
+// CHECK: [indexDeclaration] kind: function | name: import_gnu_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllimport)
+
diff --git a/test/Index/index-attrs.cpp b/test/Index/index-attrs.cpp
new file mode 100644
index 0000000..b6100ac
--- /dev/null
+++ b/test/Index/index-attrs.cpp
@@ -0,0 +1,50 @@
+// RUN: c-index-test -index-file -check-prefix CHECK %s -target armv7-windows-gnu -fdeclspec
+
+struct __declspec(dllexport) export_s {
+ void m();
+};
+// CHECK: [indexDeclaration]: kind: struct | name: export_s | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllexport)
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllexport)
+
+struct __declspec(dllimport) import_s {
+ void m();
+};
+// CHECK: [indexDeclaration]: kind: struct | name: import_s | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllimport)
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllimport)
+
+class __attribute__((dllexport)) export_gnu_s {
+ void m();
+};
+// CHECK: [indexDeclaration]: kind: struct | name: export_gnu_s | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllexport)
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllexport)
+
+class __attribute__((dllimport)) import_gnu_s {
+ void m();
+};
+// CHECK: [indexDeclaration]: kind: struct | name: import_gnu_s | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllimport)
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
+// CHECK: <attribute>: attribute(dllimport)
+
+extern "C" void __declspec(dllexport) export_function(void) {}
+// CHECK: [indexDeclaraton]: kind: function | name: export_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllexport)
+extern "C" void __attribute__((dllexport)) export_gnu_function(void) {}
+// CHECK: [indexDeclaraton]: kind: function | name: export_gnu_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllexport)
+
+extern "C" {
+void __declspec(dllimport) import_function(void);
+// CHECK: [indexDeclaration] kind: function | name: import_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllimport)
+void __attribute__((dllimport)) import_gnu_function(void);
+// CHECK: [indexDeclaration] kind: function | name: import_gnu_function | {{.*}} | lang: C
+// CHECK: <attribute>: attribute(dllimport)
+}
+
diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp
index 570d7cf..79b9c18 100644
--- a/test/Index/index-templates.cpp
+++ b/test/Index/index-templates.cpp
@@ -110,6 +110,9 @@
template <>
void foo<float, 9, FxnTmplEnum_B, FxnTmpl_Var + 7>(float Value);
+template <class T>
+using alias = T;
+
// RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-LOAD %s
// CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22]
// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:10 - 3:20]
@@ -189,6 +192,10 @@
// CHECK-LOAD: index-templates.cpp:101:20: C++ base class specifier=Pair<int, int>:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34]
// CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46]
// CHECK-LOAD: index-templates.cpp:111:6: FunctionDecl=foo:111:6 [Specialization of foo:107:6] [Template arg 0: kind: 1, type: float] [Template arg 1: kind: 4, intval: 9] [Template arg 2: kind: 4, intval: 1] [Template arg 3: kind: 4, intval: 14] Extent=[110:1 - 111:64]
+// CHECK-LOAD: index-templates.cpp:114:1: TypeAliasTemplateDecl=alias:114:1 (Definition) Extent=[113:1 - 114:16]
+// CHECK-LOAD: index-templates.cpp:113:17: TemplateTypeParameter=T:113:17 (Definition) Extent=[113:11 - 113:18] [access=public]
+// CHECK-LOAD: index-templates.cpp:114:7: TypeAliasDecl=alias:114:7 (Definition) Extent=[114:1 - 114:16]
+// CHECK-LOAD: index-templates.cpp:114:15: TypeRef=T:113:17 Extent=[114:15 - 114:16]
// RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-USRS %s
// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_#v# Extent=[3:1 - 4:22]
diff --git a/test/Index/namespaced-base-ctor-init.cpp b/test/Index/namespaced-base-ctor-init.cpp
new file mode 100644
index 0000000..2d60f7c
--- /dev/null
+++ b/test/Index/namespaced-base-ctor-init.cpp
@@ -0,0 +1,10 @@
+namespace ns1 {
+struct Base {};
+struct Derived : Base {
+ Derived() : ns1::Base() {}
+};
+}
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// CHECK: namespaced-base-ctor-init.cpp:4:15: NamespaceRef=ns1:1:11 Extent=[4:15 - 4:18]
+// CHECK: namespaced-base-ctor-init.cpp:4:20: TypeRef=struct ns1::Base:2:8 Extent=[4:20 - 4:24]
diff --git a/test/Index/print-cxx-manglings.cpp b/test/Index/print-cxx-manglings.cpp
new file mode 100644
index 0000000..aae2993
--- /dev/null
+++ b/test/Index/print-cxx-manglings.cpp
@@ -0,0 +1,66 @@
+// REQUIRES: x86-registered-target
+
+// RUN: c-index-test -write-pch %t.itanium.ast -target i686-pc-linux-gnu -fdeclspec %s
+// RUN: c-index-test -test-print-manglings %t.itanium.ast | FileCheck --check-prefix=ITANIUM %s
+
+// RUN: c-index-test -write-pch %t.macho.ast -target i686-apple-darwin -fdeclspec %s
+// RUN: c-index-test -test-print-manglings %t.macho.ast | FileCheck --check-prefix=MACHO %s
+
+// RUN: c-index-test -write-pch %t.msvc.ast -target i686-pc-windows %s
+// RUN: c-index-test -test-print-manglings %t.msvc.ast | FileCheck --check-prefix=MSVC %s
+
+struct s {
+ s(int);
+ ~s();
+ int m(int);
+};
+
+// ITANIUM: CXXConstructor=s{{.*}}[mangled=_ZN1sC2Ei] [mangled=_ZN1sC1Ei]
+// ITANIUM: CXXDestructor=~s{{.*}}[mangled=_ZN1sD2Ev] [mangled=_ZN1sD1Ev]
+
+// MACHO: CXXConstructor=s{{.*}}[mangled=__ZN1sC2Ei] [mangled=__ZN1sC1Ei]
+// MACHO: CXXDestructor=~s{{.*}}[mangled=__ZN1sD2Ev] [mangled=__ZN1sD1Ev]
+
+// MSVC: CXXConstructor=s{{.*}}[mangled=??0s@@QAE@H@Z]
+// MSVC: CXXDestructor=~s{{.*}}[mangled=??1s@@QAE@XZ]
+
+struct t {
+ t(int);
+ virtual ~t();
+ int m(int);
+};
+
+// ITANIUM: CXXConstructor=t{{.*}}[mangled=_ZN1tC2Ei] [mangled=_ZN1tC1Ei]
+// ITANIUM: CXXDestructor=~t{{.*}}[mangled=_ZN1tD2Ev] [mangled=_ZN1tD1Ev] [mangled=_ZN1tD0Ev]
+
+// MACHO: CXXConstructor=t{{.*}}[mangled=__ZN1tC2Ei] [mangled=__ZN1tC1Ei]
+// MACHO: CXXDestructor=~t{{.*}}[mangled=__ZN1tD2Ev] [mangled=__ZN1tD1Ev] [mangled=__ZN1tD0Ev]
+
+// MSVC: CXXConstructor=t{{.*}}[mangled=??0t@@QAE@H@Z]
+// MSVC: CXXDestructor=~t{{.*}}[mangled=??1t@@UAE@XZ]
+
+struct u {
+ u();
+ virtual ~u();
+ virtual int m(int) = 0;
+};
+
+// ITANIUM: CXXConstructor=u{{.*}}[mangled=_ZN1uC2Ev]
+// ITANIUM: CXXDestructor=~u{{.*}}[mangled=_ZN1uD2Ev] [mangled=_ZN1uD1Ev] [mangled=_ZN1uD0Ev]
+
+// MACHO: CXXConstructor=u{{.*}}[mangled=__ZN1uC2Ev]
+// MACHO: CXXDestructor=~u{{.*}}[mangled=__ZN1uD2Ev] [mangled=__ZN1uD1Ev] [mangled=__ZN1uD0Ev]
+
+// MSVC: CXXConstructor=u{{.*}}[mangled=??0u@@QAE@XZ]
+// MSVC: CXXDestructor=~u{{.*}}[mangled=??1u@@UAE@XZ]
+
+struct v {
+ __declspec(dllexport) v(int = 0);
+};
+
+// ITANIUM: CXXConstructor=v{{.*}}[mangled=_ZN1vC2Ei] [mangled=_ZN1vC1Ei]
+
+// MACHO: CXXConstructor=v{{.*}}[mangled=__ZN1vC2Ei] [mangled=__ZN1vC1Ei]
+
+// MSVC: CXXConstructor=v{{.*}}[mangled=??0v@@QAE@H@Z] [mangled=??_Fv@@QAEXXZ]
+
diff --git a/test/Index/print-type-declaration.cpp b/test/Index/print-type-declaration.cpp
new file mode 100644
index 0000000..31c0a73
--- /dev/null
+++ b/test/Index/print-type-declaration.cpp
@@ -0,0 +1,12 @@
+
+class Test{};
+
+int main()
+{
+ auto a = Test();
+ auto b = a;
+}
+
+// RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s
+// CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record]
+// CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record]
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index 04e94ac..61135e3 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -127,20 +127,20 @@
// CHECK: StructDecl=Blob:45:8 (Definition) [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
// CHECK: FieldDecl=i:46:7 (Definition) [type=int] [typekind=Int] [isPOD=1]
// CHECK: VarDecl=member_pointer:49:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
-// CHECK: VarDecl=autoI:53:6 (Definition) [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=autoI:53:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoTbar:54:6 (Definition) [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=autoTbar:54:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: CallExpr=tbar:35:3 [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [args= [int] [Int]] [isPOD=1]
// CHECK: UnexposedExpr=tbar:35:3 [type=int (*)(int)] [typekind=Pointer] [canonicaltype=int (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=int (int)] [pointeekind=FunctionProto]
// CHECK: DeclRefExpr=tbar:35:3 RefName=[54:17 - 54:21] RefName=[54:21 - 54:26] [type=int (int)] [typekind=FunctionProto] [canonicaltype=int (int)] [canonicaltypekind=FunctionProto] [isPOD=0]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoBlob:55:6 (Definition) [type=Blob *] [typekind=Unexposed] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: VarDecl=autoBlob:55:6 (Definition) [type=Blob *] [typekind=Auto] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1]
// CHECK: CXXNewExpr= [type=Blob *] [typekind=Pointer] [isPOD=1] [pointeetype=Blob] [pointeekind=Record]
// CHECK: TypeRef=struct Blob:45:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
// CHECK: CallExpr=Blob:45:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
-// CHECK: FunctionDecl=autoFunction:56:6 (Definition) [type=int ()] [typekind=FunctionProto] [canonicaltype=int ()] [canonicaltypekind=FunctionProto] [resulttype=int] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: FunctionDecl=autoFunction:56:6 (Definition) [type=int ()] [typekind=FunctionProto] [canonicaltype=int ()] [canonicaltypekind=FunctionProto] [resulttype=int] [resulttypekind=Auto] [isPOD=0]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: UnexposedExpr= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoInt:57:16 (Definition) [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=autoInt:57:16 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
diff --git a/test/Index/symbol-visibility.c b/test/Index/symbol-visibility.c
new file mode 100644
index 0000000..014e80f
--- /dev/null
+++ b/test/Index/symbol-visibility.c
@@ -0,0 +1,7 @@
+// RUN: c-index-test -test-print-visibility %s | FileCheck %s
+
+__attribute__ ((visibility ("default"))) void foo1();
+__attribute__ ((visibility ("hidden"))) void foo2();
+
+// CHECK: FunctionDecl=foo1:3:47visibility=Default
+// CHECK: FunctionDecl=foo2:4:46visibility=Hidden
diff --git a/test/Layout/ms-vtordisp-local.cpp b/test/Layout/ms-vtordisp-local.cpp
new file mode 100644
index 0000000..048f4e5
--- /dev/null
+++ b/test/Layout/ms-vtordisp-local.cpp
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -fms-extensions -fexceptions -fcxx-exceptions -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>&1 | FileCheck %s
+
+struct Base {
+ virtual ~Base() {}
+ virtual void BaseFunc() {}
+};
+
+#pragma vtordisp(0)
+
+struct Container {
+ static void f() try {
+ #pragma vtordisp(2)
+ struct HasVtorDisp : virtual Base {
+ virtual ~HasVtorDisp() {}
+ virtual void Func() {}
+ };
+
+ int x[sizeof(HasVtorDisp)];
+
+ // HasVtorDisp: vtordisp because of pragma right before it.
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct HasVtorDisp
+ // CHECK-NEXT: 0 | (HasVtorDisp vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+ } catch (...) {
+ }
+};
+
+struct NoVtorDisp1 : virtual Base {
+ virtual ~NoVtorDisp1() {}
+ virtual void Func() {}
+};
+
+int x1[sizeof(NoVtorDisp1)];
+
+// NoVtroDisp1: no vtordisp because of pragma disabling it.
+//
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct NoVtorDisp1
+// CHECK-NEXT: 0 | (NoVtorDisp1 vftable pointer)
+// CHECK-NEXT: 8 | (NoVtorDisp1 vbtable pointer)
+// CHECK-NEXT: 16 | struct Base (virtual base)
+// CHECK-NEXT: 16 | (Base vftable pointer)
+// CHECK-NEXT: | [sizeof=24, align=8,
+// CHECK-NEXT: | nvsize=16, nvalign=8]
+
+struct Container2 {
+ static void f1() {
+ // Local pragma #1 - must be disabled on exit from f1().
+ #pragma vtordisp(push, 2)
+ struct HasVtorDisp1 : virtual Base {
+ virtual ~HasVtorDisp1() {}
+ virtual void Func() {}
+ };
+
+ int x2[sizeof(HasVtorDisp1)];
+
+ // HasVtorDisp1: vtordisp because of pragma right before it.
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct HasVtorDisp1
+ // CHECK-NEXT: 0 | (HasVtorDisp1 vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp1 vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+
+ struct InnerContainer {
+ static void g1() {
+ struct HasVtorDisp2 : virtual Base {
+ virtual ~HasVtorDisp2() {}
+ virtual void Func() {}
+ };
+
+ int x3[sizeof(HasVtorDisp2)];
+
+ // HasVtorDisp2: vtordisp because of vtordisp(2) in f1().
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct HasVtorDisp2
+ // CHECK-NEXT: 0 | (HasVtorDisp2 vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp2 vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+
+ // Local pragma #2 - must be disabled on exit from g1().
+ #pragma vtordisp(push, 0)
+ struct NoVtorDisp2 : virtual Base {
+ virtual ~NoVtorDisp2() {}
+ virtual void Func() {}
+ };
+
+ int x4[sizeof(NoVtorDisp2)];
+
+ // NoVtroDisp2: no vtordisp because of vtordisp(0) in g1().
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct NoVtorDisp2
+ // CHECK-NEXT: 0 | (NoVtorDisp2 vftable pointer)
+ // CHECK-NEXT: 8 | (NoVtorDisp2 vbtable pointer)
+ // CHECK-NEXT: 16 | struct Base (virtual base)
+ // CHECK-NEXT: 16 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=24, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+ }
+
+ static void g2() {
+ struct HasVtorDisp3 : virtual Base {
+ virtual ~HasVtorDisp3() {}
+ virtual void Func() {}
+ };
+
+ int x5[sizeof(HasVtorDisp3)];
+
+ // HasVtorDisp3: vtordisp because of vtordisp(2) in f1(),
+ // local vtordisp(0) in g1() is disabled.
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct HasVtorDisp3
+ // CHECK-NEXT: 0 | (HasVtorDisp3 vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp3 vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+ }
+ };
+
+ struct HasVtorDisp4 : virtual Base {
+ virtual ~HasVtorDisp4() {}
+ virtual void Func() {}
+ };
+
+ int x6[sizeof(HasVtorDisp4)];
+
+ // HasVtorDisp4: vtordisp because of vtordisp(2) in f1(),
+ // local vtordisp(0) in g1() is disabled,
+ // g2() has no pragmas - stack is not affected.
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct HasVtorDisp4
+ // CHECK-NEXT: 0 | (HasVtorDisp4 vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp4 vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+
+ InnerContainer::g1();
+ InnerContainer::g2();
+ }
+
+ static void f2() {
+ struct NoVtorDisp3 : virtual Base {
+ virtual ~NoVtorDisp3() {}
+ virtual void Func() {}
+ };
+
+ int x7[sizeof(NoVtorDisp3)];
+
+ // NoVtroDisp3: no vtordisp because of global pragma (0),
+ // local vtordisp(2) is disabled on exit from f1().
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct NoVtorDisp3
+ // CHECK-NEXT: 0 | (NoVtorDisp3 vftable pointer)
+ // CHECK-NEXT: 8 | (NoVtorDisp3 vbtable pointer)
+ // CHECK-NEXT: 16 | struct Base (virtual base)
+ // CHECK-NEXT: 16 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=24, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+ }
+};
+
+struct Container3 {
+ #pragma vtordisp(2)
+ struct HasVtorDisp5 : virtual Base {
+ virtual ~HasVtorDisp5() {}
+ virtual void Func() {}
+ };
+
+ int x8[sizeof(HasVtorDisp5)];
+
+ // HasVtorDisp5: vtordisp because of pragma right before it.
+ //
+ // CHECK: *** Dumping AST Record Layout
+ // CHECK-NEXT: 0 | struct Container3::HasVtorDisp5
+ // CHECK-NEXT: 0 | (HasVtorDisp5 vftable pointer)
+ // CHECK-NEXT: 8 | (HasVtorDisp5 vbtable pointer)
+ // CHECK-NEXT: 20 | (vtordisp for vbase Base)
+ // CHECK-NEXT: 24 | struct Base (virtual base)
+ // CHECK-NEXT: 24 | (Base vftable pointer)
+ // CHECK-NEXT: | [sizeof=32, align=8,
+ // CHECK-NEXT: | nvsize=16, nvalign=8]
+};
+
+int main() {
+ Container::f();
+ Container2::f1();
+ Container2::f2();
+ Container3 cont3;
+ return 0;
+};
diff --git a/test/Lexer/msdos-cpm-eof.c b/test/Lexer/msdos-cpm-eof.c
index 3469b59..0b5150d 100644
--- a/test/Lexer/msdos-cpm-eof.c
+++ b/test/Lexer/msdos-cpm-eof.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -Wmicrosoft %s
int x;
+// expected-warning@+1 {{treating Ctrl-Z as end-of-file is a Microsoft extension}}
I am random garbage after ^Z
diff --git a/test/Lexer/objc_macros.m b/test/Lexer/objc_macros.m
new file mode 100644
index 0000000..0223bed
--- /dev/null
+++ b/test/Lexer/objc_macros.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only "-triple" "x86_64-apple-macosx10.10.0" -fobjc-runtime-has-weak -fobjc-weak %s -verify %s
+
+#define __strong
+// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}}
+#define __weak
+// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}}
+#define __unsafe_unretained
+// expected-warning@-1 {{ignoring redefinition of Objective-C qualifier macro}}
+#define __autoreleased
+// No warning because this is the default expansion anyway.
+
+// Check that this still expands to the right text.
+void test() {
+ goto label; // expected-error {{cannot jump from this goto statement to its label}}
+ __weak id x; // expected-note {{jump bypasses initialization of __weak variable}}
+label:
+ return;
+}
+
+#undef __strong
+#define __strong
+// No warning.
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index ed6d1f5..e0575cb 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -150,3 +150,7 @@
// CHECK: DeprecatedAttr
}
}
+
+struct __attribute__((objc_bridge_related(NSParagraphStyle,,))) TestBridgedRef;
+// CHECK: CXXRecordDecl{{.*}} struct TestBridgedRef
+// CHECK-NEXT: ObjCBridgeRelatedAttr{{.*}} NSParagraphStyle
diff --git a/test/Misc/ast-dump-lookups.cpp b/test/Misc/ast-dump-lookups.cpp
index 5c6da48..2d23501 100644
--- a/test/Misc/ast-dump-lookups.cpp
+++ b/test/Misc/ast-dump-lookups.cpp
@@ -1,16 +1,31 @@
// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix DECLS %s
// RUN: %clang_cc1 -std=c++11 -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix LOOKUPS %s
// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix DECLS-LOOKUPS %s
+// RUN: %clang_cc1 -std=c++11 -DPRAGMA -fsyntax-only %s 2>&1 | FileCheck -check-prefix PRAGMA %s
namespace Test {
+ typedef int T;
extern int a;
int a = 0;
}
+#ifdef PRAGMA
+#pragma clang __debug dump Test
+// PRAGMA: lookup results for Test:
+// PRAGMA-NEXT: NamespaceDecl {{.*}} Test
+// PRAGMA-NEXT: |-TypedefDecl {{.*}} T 'int'
+// PRAGMA-NEXT: | `-BuiltinType {{.*}} 'int'
+// PRAGMA-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
+// PRAGMA-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit
+// PRAGMA-NEXT: `-IntegerLiteral {{.*}} 'int' 0
+#endif
+
namespace Test { }
// DECLS: Dumping Test:
// DECLS-NEXT: NamespaceDecl {{.*}} Test
+// DECLS-NEXT: |-TypedefDecl {{.*}} T 'int'
+// DECLS-NEXT: | `-BuiltinType {{.*}} 'int'
// DECLS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
// DECLS-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit
// DECLS-NEXT: `-IntegerLiteral {{.*}} 'int' 0
@@ -20,15 +35,15 @@
// LOOKUPS: Dumping Test:
// LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
-// LOOKUPS-NEXT: `-DeclarationName 'a'
-// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int'
+// LOOKUPS: DeclarationName 'a'
+// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int'
//
// LOOKUPS: Dumping Test:
// LOOKUPS-NEXT: Lookup map is in primary DeclContext
// DECLS-LOOKUPS: Dumping Test:
// DECLS-LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
-// DECLS-LOOKUPS-NEXT: `-DeclarationName 'a'
+// DECLS-LOOKUPS: -DeclarationName 'a'
// DECLS-LOOKUPS-NEXT: `-Var [[A:[^ ]*]] 'a' 'int'
// DECLS-LOOKUPS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
// DECLS-LOOKUPS-NEXT: `-VarDecl [[A]] prev [[EXTERN_A]] {{.*}} a 'int' cinit
diff --git a/test/Misc/ast-print-char-literal.cpp b/test/Misc/ast-print-char-literal.cpp
new file mode 100644
index 0000000..bb5daa2
--- /dev/null
+++ b/test/Misc/ast-print-char-literal.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -ast-print -std=c++1z %s -o - | FileCheck %s
+
+char c = u8'1';
+char d = '1';
+char e = U'1';
+char f = L'1';
+char g = u'1';
+
+template <char c = u8'1'>
+void h();
+
+void i() {
+ h<u8'2'>();
+}
+
+// CHECK: char c = u8'1';
+// CHECK-NEXT: char d = '1';
+// CHECK-NEXT: char e = U'1';
+// CHECK-NEXT: char f = L'1';
+// CHECK-NEXT: char g = u'1';
+
+// CHECK: template <char c = u8'1'>
+
+// CHECK: h<u8'2'>();
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index d499400..15eebb6 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -220,3 +220,29 @@
// CHECK-NEXT: {{.*}}:206:56: note: expanded from macro 'sprintf2'
// CHECK-NEXT: __builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
// CHECK-NEXT: {{^ \^~~~~~~~~~~}}
+
+#define SWAP_AND_APPLY(arg, macro) macro arg
+#define APPLY(macro, arg) macro arg
+#define DECLARE_HELPER() __builtin_printf("%d\n", mylong);
+void use_evil_macros(long mylong) {
+ SWAP_AND_APPLY((), DECLARE_HELPER)
+ APPLY(DECLARE_HELPER, ())
+}
+// CHECK: {{.*}}:228:22: warning: format specifies type 'int' but the argument has type 'long'
+// CHECK-NEXT: SWAP_AND_APPLY((), DECLARE_HELPER)
+// CHECK-NEXT: ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
+// CHECK-NEXT: {{.*}}:224:36: note: expanded from macro 'SWAP_AND_APPLY'
+// CHECK-NEXT: #define SWAP_AND_APPLY(arg, macro) macro arg
+// CHECK-NEXT: ^~~~~~~~~
+// CHECK-NEXT: {{.*}}:226:51: note: expanded from macro 'DECLARE_HELPER'
+// CHECK-NEXT: #define DECLARE_HELPER() __builtin_printf("%d\n", mylong);
+// CHECK-NEXT: ~~ ^~~~~~
+// CHECK-NEXT: {{.*}}:229:9: warning: format specifies type 'int' but the argument has type 'long'
+// CHECK-NEXT: APPLY(DECLARE_HELPER, ())
+// CHECK-NEXT: ~~~~~~^~~~~~~~~~~~~~~~~~~
+// CHECK-NEXT: {{.*}}:225:27: note: expanded from macro 'APPLY'
+// CHECK-NEXT: #define APPLY(macro, arg) macro arg
+// CHECK-NEXT: ^~~~~~~~~
+// CHECK-NEXT: {{.*}}:226:51: note: expanded from macro 'DECLARE_HELPER'
+// CHECK-NEXT: #define DECLARE_HELPER() __builtin_printf("%d\n", mylong);
+// CHECK-NEXT: ~~ ^~~~~~
diff --git a/test/Misc/diag-template-diffing-color.cpp b/test/Misc/diag-template-diffing-color.cpp
index e73fc2c..bf20315 100644
--- a/test/Misc/diag-template-diffing-color.cpp
+++ b/test/Misc/diag-template-diffing-color.cpp
@@ -1,5 +1,5 @@
-// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics %s 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
// REQUIRES: ansi-escape-sequences
template<typename> struct foo {};
void func(foo<int>);
@@ -82,5 +82,23 @@
// CHECK: no viable conversion from 'A<[2 * ...], (default) [[CYAN]]2[[RESET]][[BOLD]]>' to 'A<[2 * ...], [[CYAN]]0[[RESET]][[BOLD]]>'
A<0, 2, 0> N2 = M;
}
+}
+namespace MixedDeclarationIntegerArgument {
+ template<typename T, T n = 5> class A{};
+ int x;
+ int y[5];
+ A<int> a1 = A<int&, x>();
+ // CHECK: no viable conversion from 'A<[[CYAN]]int &[[RESET]][[BOLD]], [[CYAN]]x[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int[[RESET]][[BOLD]], (default) [[CYAN]]5[[RESET]][[BOLD]]>'
+ // TREE: no viable conversion
+ // TREE: A<
+ // TREE: {{\[}}[[CYAN]]int &[[RESET]][[BOLD]] != [[CYAN]]int[[RESET]][[BOLD]]],
+ // TREE: {{\[}}[[CYAN]]x[[RESET]][[BOLD]] != (default) [[CYAN]]5[[RESET]][[BOLD]]]>
+
+ A<int**, nullptr> a2 = A<int, 3 + 1>();
+ // CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<[[CYAN]]int[[RESET]][[BOLD]], [[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int **[[RESET]][[BOLD]], [[CYAN]]nullptr[[RESET]][[BOLD]]>'
+ // TREE: no viable conversion
+ // TREE: A<
+ // TREE: {{\[}}[[CYAN]]int[[RESET]][[BOLD]] != [[CYAN]]int **[[RESET]][[BOLD]]],
+ // TREE: {{\[}}[[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]] != [[CYAN]]nullptr[[RESET]][[BOLD]]]>
}
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 044f07b..70d5e7c 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -925,7 +925,7 @@
// CHECK-ELIDE-NOTREE: no known conversion from 'A<char, [...]>' to 'A<int, [...]>'
a3 = a1;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
- // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (default) 40>' to 'A<[...], 10>'
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (default) Trait<T>::V aka 40>' to 'A<[...], 10>'
a2 = a3;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
// CHECK-ELIDE-NOTREE: no known conversion from 'A<int, 10>' to 'A<char, 40>'
@@ -1118,7 +1118,7 @@
constexpr int * ptr = nullptr;
Wrapper<S<ptr>> W = MakeWrapper<S<&global>>();
// Don't print an extra '&' for 'ptr'
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global>>' to 'Wrapper<S<ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global>>' to 'Wrapper<S<ptr aka nullptr>>'
// Handle parens correctly
Wrapper<S<(&global2)>> W2 = MakeWrapper<S<&global>>();
@@ -1148,7 +1148,7 @@
S<&global, nullptr> s3 = S<&global, &global>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], nullptr>'
S<&global, ptr> s4 = S<&global, &global>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], ptr>
+// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], ptr aka nullptr>
Wrapper<S<&global, nullptr>> W1 = MakeWrapper<S<&global, ptr>>();
Wrapper<S<&global, static_cast<int*>(0)>> W2 = MakeWrapper<S<&global, ptr>>();
@@ -1156,7 +1156,7 @@
Wrapper<S<&global, nullptr>> W3 = MakeWrapper<S<&global, &global>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], nullptr>>'
Wrapper<S<&global, ptr>> W4 = MakeWrapper<S<&global, &global>>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr aka nullptr>>'
Wrapper<S<&global2, ptr>> W5 = MakeWrapper<S<&global, nullptr>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global, [...]>>' to 'Wrapper<S<&global2, [...]>>'
@@ -1180,7 +1180,7 @@
Wrapper<S<&global, &global>> W13 = MakeWrapper<S<&global, ptr>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], nullptr>>' to 'Wrapper<S<[...], &global>>'
Wrapper<S<&global, ptr>> W14 = MakeWrapper<S<&global, &global>>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr aka nullptr>>'
}
namespace TemplateTemplateDefault {
@@ -1271,7 +1271,160 @@
foo<BoolT<true>>(X);
}
// CHECK-ELIDE-NOTREE: no matching function for call to 'foo'
-// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT<true>] not viable: no known conversion from 'BoolT<0>' to 'BoolT<1>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT<true>] not viable: no known conversion from 'BoolT<false>' to 'BoolT<true>' for 1st argument
+}
+
+namespace DifferentIntegralTypes {
+template<typename T, T n>
+class A{};
+void foo() {
+ A<int, 1> a1 = A<long long, 1>();
+ A<unsigned int, 1> a2 = A<int, 5>();
+ A<bool, true> a3 = A<signed char, true>();
+}
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<long long, (long long) 1>' to 'A<int, (int) 1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, (int) 5>' to 'A<unsigned int, (unsigned int) 1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<signed char, (signed char) 1>' to 'A<bool, (bool) true>'
+}
+
+namespace MixedDeclarationIntegerArgument {
+template<typename T, T n> class A{};
+int x;
+int y[5];
+
+A<int, 5> a1 = A<int&, x>();
+A<int, 5 - 1> a2 = A<int*, &x>();
+A<int, 5 + 1> a3 = A<int*, y>();
+A<int, 0> a4 = A<int**, nullptr>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int &, x>' to 'A<int, 5>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, &x>' to 'A<int, 5 - 1 aka 4>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, y>' to 'A<int, 5 + 1 aka 6>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int **, nullptr>' to 'A<int, 0>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [x != 5]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int * != int],
+// CHECK-ELIDE-TREE: [&x != 5 - 1 aka 4]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int * != int],
+// CHECK-ELIDE-TREE: [y != 5 + 1 aka 6]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int ** != int],
+// CHECK-ELIDE-TREE: [nullptr != 0]>
+
+A<int&, x> a5 = A<int, 3>();
+A<int*, &x> a6 = A<int, 3 - 1>();
+A<int*, y> a7 = A<int, 3 + 1>();
+A<int**, nullptr> a8 = A<int, 3>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int &, x>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 - 1 aka 2>' to 'A<int *, &x>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 + 1 aka 4>' to 'A<int *, y>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int **, nullptr>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [3 != x]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int *],
+// CHECK-ELIDE-TREE: [3 - 1 aka 2 != &x]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int *],
+// CHECK-ELIDE-TREE: [3 + 1 aka 4 != y]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int **],
+// CHECK-ELIDE-TREE: [3 != nullptr]>
+
+template<class T, T n = x> class B{} ;
+B<int, 5> b1 = B<int&>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int &, (default) x>' to 'B<int, 5>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: B<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [(default) x != 5]>
+
+B<int &> b2 = B<int, 2>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int, 2>' to 'B<int &, (default) x>'
+// CHECK-ELIDE-TREE: B<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [2 != (default) x]>
+
+template<class T, T n = 11> class C {};
+C<int> c1 = C<int&, x>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int &, x>' to 'C<int, (default) 11>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: C<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [x != (default) 11]>
+
+C<int &, x> c2 = C<int>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int, (default) 11>' to 'C<int &, x>'
+// CHECK-ELIDE-TREE: C<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [(default) 11 != x]>
+}
+
+namespace default_args {
+ template <int x, int y = 1+1, int z = 2>
+ class A {};
+
+ void foo(A<0> &M) {
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[...], (default) 1 + 1 aka 2, (default) 2>' to 'A<[...], 0, 0>'
+ A<0, 0, 0> N = M;
+
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[2 * ...], (default) 2>' to 'A<[2 * ...], 0>'
+ A<0, 2, 0> N2 = M;
+ }
+}
+
+namespace DefaultNonTypeArgWithDependentType {
+// We used to crash diffing integer template arguments when the argument type
+// is dependent and default arguments were used.
+template <typename SizeType = int, SizeType = 0> struct A {};
+template <typename R = A<>> R bar();
+A<> &foo() { return bar(); }
+// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<[2 * ...]>' cannot bind to a temporary of type 'A<[2 * ...]>'
+// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<int, 0>' cannot bind to a temporary of type 'A<int, 0>'
+}
+
+namespace PR24587 {
+template <typename T, T v>
+struct integral_constant {};
+
+auto false_ = integral_constant<bool, false> {};
+
+template <typename T>
+void f(T, decltype(false_));
+
+void run() {
+ f(1, integral_constant<bool, true>{});
+}
+// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
+// CHECK-ELIDE-NOTREE: note: candidate function [with T = int] not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
+}
+
+namespace ZeroArgs {
+template <int N = 0> class A {};
+template <class T = A<>> class B {};
+A<1> a1 = A<>();
+A<> a2 = A<1>();
+B<> b1 = B<int>();
+B<int> b2 = B<>();
+B<> b3 = B<const A<>>();
+B<const A<>> b4 = B<>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<(default) 0>' to 'A<1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<1>' to 'A<(default) 0>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int>' to 'B<(default) ZeroArgs::A<0>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<(default) ZeroArgs::A<0>>' to 'B<int>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<const A<[...]>>' to 'B<A<[...]>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<A<[...]>>' to 'B<const A<[...]>>'
}
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
diff --git a/test/Misc/warning-flags-enabled.c b/test/Misc/warning-flags-enabled.c
index ba29e7a..b809465 100644
--- a/test/Misc/warning-flags-enabled.c
+++ b/test/Misc/warning-flags-enabled.c
@@ -3,7 +3,7 @@
// This shows warnings which are on by default.
// We just check a few to make sure it's doing something sensible.
//
-// CHECK: ext_unterminated_string
+// CHECK: ext_unterminated_char_or_string
// CHECK: warn_condition_is_assignment
// CHECK: warn_null_arg
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 9abfb51..023df5e 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (86):
+CHECK: Warnings without flags (85):
CHECK-NEXT: ext_excess_initializers
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
CHECK-NEXT: ext_expected_semi_decl_list
@@ -85,8 +85,7 @@
CHECK-NEXT: warn_objc_protocol_qualifier_missing_id
CHECK-NEXT: warn_on_superclass_use
CHECK-NEXT: warn_partial_specs_not_deducible
-CHECK-NEXT: warn_pp_convert_lhs_to_positive
-CHECK-NEXT: warn_pp_convert_rhs_to_positive
+CHECK-NEXT: warn_pp_convert_to_positive
CHECK-NEXT: warn_pp_expr_overflow
CHECK-NEXT: warn_pp_line_decimal
CHECK-NEXT: warn_pragma_pack_pop_identifer_and_alignment
diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp
index b255042..3b4547a 100644
--- a/test/Modules/ExtDebugInfo.cpp
+++ b/test/Modules/ExtDebugInfo.cpp
@@ -2,7 +2,8 @@
// Test that only forward declarations are emitted for types dfined in modules.
// Modules:
-// RUN: %clang_cc1 -x objective-c++ -std=c++11 -debug-info-kind=limited -dwarf-ext-refs -fmodules \
+// RUN: %clang_cc1 -x objective-c++ -std=c++11 -debug-info-kind=limited \
+// RUN: -dwarf-ext-refs -fmodules \
// RUN: -fmodule-format=obj -fimplicit-module-maps -DMODULES \
// RUN: -triple %itanium_abi_triple \
// RUN: -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t-mod.ll
@@ -12,10 +13,12 @@
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodule-format=obj -emit-pch -I%S/Inputs \
// RUN: -triple %itanium_abi_triple \
// RUN: -o %t.pch %S/Inputs/DebugCXX.h
-// RUN: %clang_cc1 -std=c++11 -debug-info-kind=limited -dwarf-ext-refs -fmodule-format=obj \
+// RUN: %clang_cc1 -std=c++11 -debug-info-kind=limited \
+// RUN: -dwarf-ext-refs -fmodule-format=obj \
// RUN: -triple %itanium_abi_triple \
// RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s
// RUN: cat %t-pch.ll | FileCheck %s
+// RUN: cat %t-pch.ll | FileCheck %s --check-prefix=CHECK-PCH
#ifdef MODULES
@import DebugCXX;
@@ -35,6 +38,16 @@
auto anon_enum = DebugCXX::e2;
char _anchor = anon_enum + conflicting_uid;
+TypedefUnion tdu;
+TypedefEnum tde;
+TypedefStruct tds;
+
+InAnonymousNamespace anon;
+
+void foo() {
+ anon.i = GlobalStruct.i = GlobalUnion.i = GlobalEnum;
+}
+
// CHECK: ![[NS:.*]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]],
// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugCXX
@@ -62,6 +75,13 @@
// CHECK-SAME: flags: DIFlagFwdDecl,
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")
+// CHECK: !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME: flags: DIFlagFwdDecl, identifier: "_ZTS12TypedefUnion")
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME: flags: DIFlagFwdDecl, identifier: "_ZTS11TypedefEnum")
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: flags: DIFlagFwdDecl, identifier: "_ZTS13TypedefStruct")
+
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "static_member",
// CHECK-SAME: scope: !"_ZTSN8DebugCXX6StructE"
@@ -69,4 +89,25 @@
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, scope: ![[NS]],
// CHECK-SAME: line: 16
-// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !"_ZTSN8DebugCXX6StructE", line: 24)
+// CHECK: !DIGlobalVariable(name: "GlobalUnion",
+// CHECK-SAME: type: ![[GLOBAL_UNION:[0-9]+]]
+// CHECK: ![[GLOBAL_UNION]] = !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME: elements: !{{[0-9]+}})
+// CHECK: !DIGlobalVariable(name: "GlobalStruct",
+// CHECK-SAME: type: ![[GLOBAL_STRUCT:[0-9]+]]
+// CHECK: ![[GLOBAL_STRUCT]] = !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: elements: !{{[0-9]+}})
+
+// CHECK: !DIGlobalVariable(name: "anon",
+// CHECK-SAME: type: ![[GLOBAL_ANON:[0-9]+]]
+// CHECK: ![[GLOBAL_ANON]] = !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: name: "InAnonymousNamespace", {{.*}}DIFlagFwdDecl)
+
+
+// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !"_ZTSN8DebugCXX6StructE", line: 27)
+
+// CHECK: !DICompileUnit(
+// CHECK-SAME: splitDebugFilename:
+// CHECK-SAME: dwoId:
+// CHECK-PCH: !DICompileUnit({{.*}}splitDebugFilename:
+// CHECK-PCH: dwoId: 18446744073709551614
diff --git a/test/Modules/ExtDebugInfo.m b/test/Modules/ExtDebugInfo.m
index 8e063f0..5c3c711 100644
--- a/test/Modules/ExtDebugInfo.m
+++ b/test/Modules/ExtDebugInfo.m
@@ -18,8 +18,13 @@
@import DebugObjC;
#endif
+TypedefUnion tdu;
+TypedefEnum tde;
+TypedefStruct tds;
+
int foo(ObjCClass *c) {
InnerEnum e = e0;
+ GlobalStruct.i = GlobalUnion.i = GlobalEnum;
[c instanceMethodWithInt: 0];
return [c property];
}
@@ -29,7 +34,30 @@
// CHECK-SAME: scope: ![[MOD:[0-9]+]],
// CHECK-SAME: flags: DIFlagFwdDecl)
// CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type,
-// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugObjC
+// CHECK: ![[MOD]] = !DIModule(scope: null, name: "DebugObjC
+
+// CHECK: !DIGlobalVariable(name: "GlobalUnion",
+// CHECK-SAME: type: ![[GLOBAL_UNION:[0-9]+]]
+// CHECK: ![[GLOBAL_UNION]] = !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME: elements: !{{[0-9]+}})
+// CHECK: !DIGlobalVariable(name: "GlobalStruct",
+// CHECK-SAME: type: ![[GLOBAL_STRUCT:[0-9]+]]
+// CHECK: ![[GLOBAL_STRUCT]] = !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: elements: !{{[0-9]+}})
+
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefUnion",
+// CHECK-SAME: baseType: ![[TD_UNION:.*]])
+// CHECK: ![[TD_UNION]] = !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME: flags: DIFlagFwdDecl)
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefEnum",
+// CHECK-SAME: baseType: ![[TD_ENUM:.*]])
+// CHECK: ![[TD_ENUM]] = !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME: flags: DIFlagFwdDecl)
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefStruct",
+// CHECK-SAME: baseType: ![[TD_STRUCT:.*]])
+// CHECK: ![[TD_STRUCT]] = !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: flags: DIFlagFwdDecl)
+
// CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type,
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
// CHECK-SAME: scope: ![[MOD]],
diff --git a/test/Modules/Inputs/DebugCXX.h b/test/Modules/Inputs/DebugCXX.h
index 6ef4445..39dda95 100644
--- a/test/Modules/Inputs/DebugCXX.h
+++ b/test/Modules/Inputs/DebugCXX.h
@@ -17,7 +17,7 @@
e2 = '2'
};
- // Templates (instatiations).
+ // Templates (instantiations).
template<typename T> struct traits {};
template<typename T,
typename Traits = traits<T>
@@ -50,3 +50,25 @@
typedef A<void> B;
void foo(B) {}
}
+
+// Virtual class with a forward declaration.
+class FwdVirtual;
+class FwdVirtual {
+ virtual ~FwdVirtual() {}
+};
+
+struct PureForwardDecl;
+
+typedef union { int i; } TypedefUnion;
+typedef enum { e0 = 0 } TypedefEnum;
+typedef struct { int i; } TypedefStruct;
+
+union { int i; } GlobalUnion;
+struct { int i; } GlobalStruct;
+enum { e5 = 5 } GlobalEnum;
+
+namespace {
+ namespace {
+ struct InAnonymousNamespace { int i; };
+ }
+}
diff --git a/test/Modules/Inputs/DebugObjC.h b/test/Modules/Inputs/DebugObjC.h
index bde463a..eb7a9f9 100644
--- a/test/Modules/Inputs/DebugObjC.h
+++ b/test/Modules/Inputs/DebugObjC.h
@@ -22,3 +22,17 @@
+ (InnerEnum)protocolMethod;
@end
+
+struct FwdDeclared;
+struct FwdDeclared {
+ int i;
+};
+struct PureForwardDecl;
+
+typedef union { int i; } TypedefUnion;
+typedef enum { e1 = 1 } TypedefEnum;
+typedef struct { int i; } TypedefStruct;
+
+union { int i; } GlobalUnion;
+struct { int i; } GlobalStruct;
+enum { e2 = 2 } GlobalEnum;
diff --git a/test/Modules/Inputs/builtin.h b/test/Modules/Inputs/builtin.h
index 7be9017..4717ff2 100644
--- a/test/Modules/Inputs/builtin.h
+++ b/test/Modules/Inputs/builtin.h
@@ -1,3 +1,7 @@
int i;
int *p = &i;
+void use_constant_string_builtins(void) {
+ (void)__builtin___CFStringMakeConstantString("");
+ (void)__builtin___NSStringMakeConstantString("");
+}
diff --git a/test/Modules/Inputs/category_right.h b/test/Modules/Inputs/category_right.h
index 3c83624..d8dedf8 100644
--- a/test/Modules/Inputs/category_right.h
+++ b/test/Modules/Inputs/category_right.h
@@ -1,4 +1,5 @@
@import category_top;
+#import "category_right_sub.h"
@interface Foo(Right1)
-(void)right1;
diff --git a/test/Modules/Inputs/dummy.h b/test/Modules/Inputs/dummy.h
index 6e1ac74..cad8315 100644
--- a/test/Modules/Inputs/dummy.h
+++ b/test/Modules/Inputs/dummy.h
@@ -1,3 +1,5 @@
// This module only exists to make local decl IDs and global decl IDs different.
-
+#ifndef DUMMY_H
+#define DUMMY_H
struct Dummy {} extern *dummy1, *dummy2, *dummy3;
+#endif
diff --git a/test/Modules/Inputs/elaborated-type-structs.h b/test/Modules/Inputs/elaborated-type-structs.h
new file mode 100644
index 0000000..da39409
--- /dev/null
+++ b/test/Modules/Inputs/elaborated-type-structs.h
@@ -0,0 +1,3 @@
+struct S1;
+struct S2 { int x; };
+struct S3 { int x; };
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index d195e2f..632517d 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -379,3 +379,17 @@
module ExtensionTestA {
header "ExtensionTestA.h"
}
+
+module TypedefTag {
+ header "typedef-tag.h"
+ explicit module Hidden {
+ header "typedef-tag-hidden.h"
+ }
+}
+
+module ElaboratedTypeStructs {
+ module Empty {}
+ module Structs {
+ header "elaborated-type-structs.h"
+ }
+}
diff --git a/test/Modules/Inputs/no-linkage/decls.h b/test/Modules/Inputs/no-linkage/decls.h
new file mode 100644
index 0000000..c8d6de5
--- /dev/null
+++ b/test/Modules/Inputs/no-linkage/decls.h
@@ -0,0 +1,11 @@
+namespace RealNS { int UsingDecl; }
+namespace NS = RealNS;
+typedef int Typedef;
+using AliasDecl = int;
+using RealNS::UsingDecl;
+struct Struct {};
+extern int Variable;
+namespace AnotherNS {}
+enum X { Enumerator };
+void Overloads();
+void Overloads(int);
diff --git a/test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep b/test/Modules/Inputs/no-linkage/empty.h
similarity index 100%
copy from test/Driver/Inputs/CUDA/usr/local/cuda/nvvm/libdevice/.keep
copy to test/Modules/Inputs/no-linkage/empty.h
diff --git a/test/Modules/Inputs/no-linkage/module.modulemap b/test/Modules/Inputs/no-linkage/module.modulemap
new file mode 100644
index 0000000..3931b0f
--- /dev/null
+++ b/test/Modules/Inputs/no-linkage/module.modulemap
@@ -0,0 +1 @@
+module M { module E { header "empty.h" } module D { header "decls.h" } }
diff --git a/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h
index e9d7284..f6004f0 100644
--- a/test/Modules/Inputs/submodules-merge-defs/defs.h
+++ b/test/Modules/Inputs/submodules-merge-defs/defs.h
@@ -131,3 +131,10 @@
};
template<typename A, int B> template<typename C> F<A[B]>::F() {}
}
+
+struct MemberClassTemplate {
+ template<typename T> struct A;
+};
+template<typename T> struct MemberClassTemplate::A {};
+template<typename T> struct MemberClassTemplate::A<T*> {};
+template<> struct MemberClassTemplate::A<int> {};
diff --git a/test/Modules/Inputs/typedef-tag-hidden.h b/test/Modules/Inputs/typedef-tag-hidden.h
new file mode 100644
index 0000000..eb59d69
--- /dev/null
+++ b/test/Modules/Inputs/typedef-tag-hidden.h
@@ -0,0 +1 @@
+typedef struct { int x; } TypedefStructHidden_t;
diff --git a/test/Modules/Inputs/typedef-tag.h b/test/Modules/Inputs/typedef-tag.h
new file mode 100644
index 0000000..77dff95
--- /dev/null
+++ b/test/Modules/Inputs/typedef-tag.h
@@ -0,0 +1 @@
+typedef struct { int x; } TypedefStructVisible_t;
diff --git a/test/Modules/Inputs/using-decl-redecl/a.h b/test/Modules/Inputs/using-decl-redecl/a.h
index 4775469..eaa1876 100644
--- a/test/Modules/Inputs/using-decl-redecl/a.h
+++ b/test/Modules/Inputs/using-decl-redecl/a.h
@@ -1,2 +1,3 @@
struct string {};
-namespace N { typedef ::string clstring; }
+const int n = 0;
+namespace N { typedef ::string clstring; using ::n; }
diff --git a/test/Modules/Inputs/using-decl-redecl/d.h b/test/Modules/Inputs/using-decl-redecl/d.h
new file mode 100644
index 0000000..2243de1
--- /dev/null
+++ b/test/Modules/Inputs/using-decl-redecl/d.h
@@ -0,0 +1 @@
+#include "a.h"
diff --git a/test/Modules/Inputs/using-decl-redecl/module.modulemap b/test/Modules/Inputs/using-decl-redecl/module.modulemap
index bd6ea83..a2ebc17 100644
--- a/test/Modules/Inputs/using-decl-redecl/module.modulemap
+++ b/test/Modules/Inputs/using-decl-redecl/module.modulemap
@@ -1,3 +1,4 @@
module a { header "a.h" }
-module b { header "b.h" export * }
-module c { header "c.h" export * }
+module b { header "b.h" export a }
+module c { header "c.h" export a export b }
+module d { header "d.h" }
diff --git a/test/Modules/ModuleDebugInfo.cpp b/test/Modules/ModuleDebugInfo.cpp
index 81192cb..7344397 100644
--- a/test/Modules/ModuleDebugInfo.cpp
+++ b/test/Modules/ModuleDebugInfo.cpp
@@ -8,12 +8,11 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -x objective-c++ -std=c++11 -debug-info-kind=limited -fmodules -fmodule-format=obj -fimplicit-module-maps -DMODULES -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t.ll -mllvm -debug-only=pchcontainer &>%t-mod.ll
// RUN: cat %t-mod.ll | FileCheck %s
// RUN: cat %t-mod.ll | FileCheck --check-prefix=CHECK-NEG %s
-// RUN: cat %t-mod.ll | FileCheck --check-prefix=CHECK-DWO %s
// PCH:
// RUN: %clang_cc1 -triple %itanium_abi_triple -x c++ -std=c++11 -emit-pch -fmodule-format=obj -I %S/Inputs -o %t.pch %S/Inputs/DebugCXX.h -mllvm -debug-only=pchcontainer &>%t-pch.ll
// RUN: cat %t-pch.ll | FileCheck %s
-// RUN: cat %t-mod.ll | FileCheck --check-prefix=CHECK-NEG %s
+// RUN: cat %t-pch.ll | FileCheck --check-prefix=CHECK-NEG %s
#ifdef MODULES
@import DebugCXX;
@@ -22,23 +21,67 @@
// CHECK: distinct !DICompileUnit(language: DW_LANG_{{.*}}C_plus_plus,
// CHECK-SAME: isOptimized: false,
// CHECK-SAME-NOT: splitDebugFilename:
-// CHECK-DWO: dwoId:
+// CHECK: dwoId:
+
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE")
// CHECK: !DINamespace(name: "DebugCXX"
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: identifier: "_ZTS11TypedefEnum")
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME-NOT: name:
+// CHECK: !DIEnumerator(name: "e5", value: 5)
+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX6StructE")
+
// CHECK: !DICompositeType(tag: DW_TAG_class_type,
// CHECK-SAME: name: "Template<int, DebugCXX::traits<int> >"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE")
+
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"
+// CHECK-SAME: identifier: "_ZTSN8DebugCXX1AIJvEEE")
+
// CHECK: !DICompositeType(tag: DW_TAG_class_type,
// CHECK-SAME: name: "Template<float, DebugCXX::traits<float> >"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")
-// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"
-// CHECK-SAME: identifier: "_ZTSN8DebugCXX1AIJvEEE")
+
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "FwdVirtual"
+// CHECK-SAME: elements:
+// CHECK-SAME: identifier: "_ZTS10FwdVirtual")
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$FwdVirtual"
+
+// CHECK: !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: identifier: "_ZTS12TypedefUnion")
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: identifier: "_ZTS13TypedefStruct")
+
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "FloatInstatiation"
// no mangled name here yet.
+
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "B",
// no mangled name here yet.
-// CHECK-NEG-NOT: "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE"
+// CHECK: !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME: name: "InAnonymousNamespace",
+// CHECK-SAME: elements: !{{[0-9]+}})
+
+// CHECK-NEG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "PureForwardDecl"
diff --git a/test/Modules/ModuleDebugInfo.m b/test/Modules/ModuleDebugInfo.m
index 0974f38..6bca676 100644
--- a/test/Modules/ModuleDebugInfo.m
+++ b/test/Modules/ModuleDebugInfo.m
@@ -10,13 +10,14 @@
// RUN: -I %S/Inputs -I %t -emit-llvm -o %t.ll \
// RUN: -mllvm -debug-only=pchcontainer &>%t-mod.ll
// RUN: cat %t-mod.ll | FileCheck %s
-// RUN: cat %t-mod.ll | FileCheck %s --check-prefix=MODULE-CHECK
+// RUN: cat %t-mod.ll | FileCheck %s --check-prefix=CHECK2
// PCH:
// RUN: %clang_cc1 -x objective-c -emit-pch -fmodule-format=obj -I %S/Inputs \
// RUN: -o %t.pch %S/Inputs/DebugObjC.h \
// RUN: -mllvm -debug-only=pchcontainer &>%t-pch.ll
// RUN: cat %t-pch.ll | FileCheck %s
+// RUN: cat %t-pch.ll | FileCheck %s --check-prefix=CHECK2
#ifdef MODULES
@import DebugObjC;
@@ -24,28 +25,65 @@
// CHECK: distinct !DICompileUnit(language: DW_LANG_ObjC
// CHECK-SAME: isOptimized: false,
+
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME: scope: ![[MODULE:[0-9]+]],
+// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugObjC
+
+// CHECK: ![[TD_ENUM:.*]] = !DICompositeType(tag: DW_TAG_enumeration_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: elements:
+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
// CHECK-SAME: name: "FwdDecl",
+// CHECK-SAME: scope: ![[MODULE]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
// CHECK-SAME: name: "ObjCClass",
-// CHECK: !DIObjCProperty(name: "property",
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "ivar"
-// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "InnerEnum"
-// CHECK: !DISubprogram(name: "+[ObjCClass classMethod]"
-// CHECK: !DISubprogram(name: "-[ObjCClass instanceMethodWithInt:]"
-// CHECK: !DISubprogram(name: "-[Category(Category) categoryMethod]"
+// CHECK-SAME: scope: ![[MODULE]],
-// MODULE-CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
-// MODULE-CHECK-SAME: scope: ![[MODULE:[0-9]+]],
-// MODULE-CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugObjC"
-// MODULE-CHECK: !DICompositeType(tag: DW_TAG_structure_type,
-// MODULE-CHECK-SAME: name: "FwdDecl",
-// MODULE-CHECK-SAME: scope: ![[MODULE]],
-// MODULE-CHECK: !DICompositeType(tag: DW_TAG_structure_type,
-// MODULE-CHECK-SAME: name: "ObjCClass",
-// MODULE-CHECK-SAME: scope: ![[MODULE]],
-// MODULE-CHECK: !DISubprogram(name: "+[ObjCClass classMethod]",
-// MODULE-CHECK-SAME: scope: ![[MODULE]],
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "FwdDeclared"
+// CHECK-SAME: elements:
+
+// CHECK: ![[TD_UNION:.*]] = !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: elements:
+
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefUnion",
+// CHECK-SAME: baseType: ![[TD_UNION]])
+
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefEnum",
+// CHECK-SAME: baseType: ![[TD_ENUM:.*]])
+
+// CHECK: ![[TD_STRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME-NOT: name:
+// CHECK-SAME: elements:
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "TypedefStruct",
+// CHECK-SAME: baseType: ![[TD_STRUCT]])
+
+// CHECK: !DICompositeType(tag: DW_TAG_union_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK-SAME-NOT: name:
+
+// CHECK: !DISubprogram(name: "+[ObjCClass classMethod]",
+// CHECK-SAME: scope: ![[MODULE]],
// The forward declaration should not be in the module scope.
-// MODULE-CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "OpaqueData", file
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "OpaqueData", file
+
+// CHECK-NEG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "PureForwardDecl"
+
+// The output order is sublty different for module vs. pch,
+// so these are checked separately:
+//
+// CHECK2: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK2-SAME: name: "FwdDecl",
+// CHECK2: !DICompositeType(tag: DW_TAG_structure_type,
+// CHECK2-SAME: name: "ObjCClass",
+// CHECK2: !DIObjCProperty(name: "property",
+// CHECK2: !DIDerivedType(tag: DW_TAG_member, name: "ivar"
+// CHECK2: !DIDerivedType(tag: DW_TAG_typedef, name: "InnerEnum"
+// CHECK2: !DISubprogram(name: "+[ObjCClass classMethod]"
+// CHECK2: !DISubprogram(name: "-[ObjCClass instanceMethodWithInt:]"
+// CHECK2: !DISubprogram(name: "-[Category(Category) categoryMethod]"
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index 76441fc..9a34c92 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -1,6 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify -DERRORS
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -xobjective-c++ %s -verify
//
// Test both with and without the declarations that refer to unimported
// entities. For error recovery, those cases implicitly trigger an import.
@@ -85,5 +86,16 @@
void includeNotAtTopLevel() { // expected-note {{function 'includeNotAtTopLevel' begins here}}
#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
- expected-error {{import of module 'NoUmbrella.A' appears within function 'includeNotAtTopLevel'}}
+ expected-error {{redundant #include of module 'NoUmbrella.A' appears within function 'includeNotAtTopLevel'}}
}
+
+#ifdef __cplusplus
+namespace NS { // expected-note {{begins here}}
+#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
+ expected-error {{redundant #include of module 'NoUmbrella.A' appears within namespace 'NS'}}
+}
+extern "C" { // expected-note {{begins here}}
+#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
+ expected-error {{import of C++ module 'NoUmbrella.A' appears within extern "C"}}
+}
+#endif
diff --git a/test/Modules/builtins.m b/test/Modules/builtins.m
index 33d2397..2480e63 100644
--- a/test/Modules/builtins.m
+++ b/test/Modules/builtins.m
@@ -1,10 +1,26 @@
-@import builtin;
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs -x c %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs -x objective-c++ %s -verify
+
+// RUN: rm -rf %t.pch.cache
+// RUN: %clang_cc1 -fmodules-cache-path=%t.pch.cache -fmodules -fimplicit-module-maps -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %S/Inputs/use-builtin.h
+// RUN: %clang_cc1 -fmodules-cache-path=%t.pch.cache -fmodules -fimplicit-module-maps -I %S/Inputs %s -include-pch %t.pch %s -verify
+
+// expected-no-diagnostics
+
+void use_constant_string_builtins1(void) {
+ (void)__builtin___CFStringMakeConstantString("");
+ (void)__builtin___NSStringMakeConstantString("");
+}
+
+#include "builtin.h"
int foo() {
return __builtin_object_size(p, 0);
}
-@import builtin.sub;
+#include "builtin_sub.h"
int bar() {
return __builtin_object_size(p, 0);
@@ -14,11 +30,7 @@
return IS_CONST(0);
}
-// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs %s -verify
-
-// RUN: rm -rf %t.pch.cache
-// RUN: %clang_cc1 -fmodules-cache-path=%t.pch.cache -fmodules -fimplicit-module-maps -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %S/Inputs/use-builtin.h
-// RUN: %clang_cc1 -fmodules-cache-path=%t.pch.cache -fmodules -fimplicit-module-maps -I %S/Inputs %s -include-pch %t.pch %s -verify
-
-// expected-no-diagnostics
+void use_constant_string_builtins2(void) {
+ (void)__builtin___CFStringMakeConstantString("");
+ (void)__builtin___NSStringMakeConstantString("");
+}
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index fd6b4f5..ef4e4e4 100644
--- a/test/Modules/cxx-templates.cpp
+++ b/test/Modules/cxx-templates.cpp
@@ -105,8 +105,8 @@
TemplateInstantiationVisibility<char[1]> tiv1;
TemplateInstantiationVisibility<char[2]> tiv2;
- TemplateInstantiationVisibility<char[3]> tiv3; // expected-error {{must be imported from module 'cxx_templates_b_impl'}}
- // expected-note@cxx-templates-b-impl.h:10 {{previous definition is here}}
+ TemplateInstantiationVisibility<char[3]> tiv3; // expected-error 2{{must be imported from module 'cxx_templates_b_impl'}}
+ // expected-note@cxx-templates-b-impl.h:10 2{{previous definition is here}}
TemplateInstantiationVisibility<char[4]> tiv4;
int &p = WithPartialSpecializationUse().f();
diff --git a/test/Modules/decldef.m b/test/Modules/decldef.m
index 420c677..784743f 100644
--- a/test/Modules/decldef.m
+++ b/test/Modules/decldef.m
@@ -11,7 +11,13 @@
#ifdef USE_EARLY
A *a1; // expected-error{{declaration of 'A' must be imported from module 'decldef.Def' before it is required}}
#endif
-B *b1; // expected-error{{must use 'struct' tag to refer to type 'B'}}
+B *b1;
+#ifdef USE_EARLY
+// expected-error@-2{{must use 'struct' tag to refer to type 'B'}}
+#else
+// expected-error@-4{{declaration of 'B' must be imported from module 'decldef.Decl' before it is required}}
+// expected-note@Inputs/decl.h:2 {{previous}}
+#endif
@import decldef.Decl;
A *a2;
diff --git a/test/Modules/elaborated-type-specifier-from-hidden-module.m b/test/Modules/elaborated-type-specifier-from-hidden-module.m
new file mode 100644
index 0000000..0ca1c24
--- /dev/null
+++ b/test/Modules/elaborated-type-specifier-from-hidden-module.m
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify
+
+@import ElaboratedTypeStructs.Empty; // The structs are now hidden.
+struct S1 *x;
+struct S2 *y;
+// FIXME: compatible definition should not be an error.
+struct S2 { int x; }; // expected-error {{redefinition}}
+struct S3 *z;
+// Incompatible definition.
+struct S3 { float y; }; // expected-error {{redefinition}}
+// expected-note@elaborated-type-structs.h:* 2 {{previous definition is here}}
+
+@import ElaboratedTypeStructs.Structs;
+
+void useS1(struct S1 *x);
+void useS2(struct S2 *x);
+void useS2(struct S2 *x);
diff --git a/test/Modules/embed-files.cpp b/test/Modules/embed-files.cpp
new file mode 100644
index 0000000..a1db218
--- /dev/null
+++ b/test/Modules/embed-files.cpp
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'module a { header "a.h" } module b { header "b.h" }' > %t/modulemap
+// RUN: echo 'extern int t;' > %t/t.h
+// RUN: echo '#include "t.h"' > %t/a.h
+// RUN: echo '#include "t.h"' > %t/b.h
+
+// RUN: %clang_cc1 -fmodules -I%t -fmodules-cache-path=%t -fmodule-map-file=%t/modulemap -fmodules-embed-all-files %s -verify
+#include "a.h"
+char t; // expected-error {{different type}}
+// expected-note@t.h:1 {{here}}
+#include "t.h"
+#include "b.h"
+char t; // expected-error {{different type}}
+// expected-note@t.h:1 {{here}}
diff --git a/test/Modules/explicit-build-missing-files.cpp b/test/Modules/explicit-build-missing-files.cpp
index b2730e4f..1ee65d9 100644
--- a/test/Modules/explicit-build-missing-files.cpp
+++ b/test/Modules/explicit-build-missing-files.cpp
@@ -13,6 +13,9 @@
// RUN: %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ %t/modulemap -o %t/a.pcm \
// RUN: -fmodule-map-file=%t/other.modulemap \
// RUN: -fmodules-embed-file=%t/modulemap -fmodules-embed-file=%t/other.modulemap
+// RUN: %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ %t/modulemap -o %t/b.pcm \
+// RUN: -fmodule-map-file=%t/other.modulemap \
+// RUN: -fmodules-embed-all-files
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/modulemap
@@ -27,9 +30,11 @@
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/b.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/b.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s --check-prefix=MISSING-B
// RUN: rm %t/a.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -verify
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/b.pcm %s -verify
// Oftentimes on Windows there are open handles, and deletion will fail.
// REQUIRES: can-remove-opened-file
@@ -46,6 +51,6 @@
// MISSING-B-NOT: please delete the module cache
#endif
-// RUN: not %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ /dev/null -o %t/a.pcm \
+// RUN: not %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ /dev/null -o %t/c.pcm \
// RUN: -fmodules-embed-file=%t/does-not-exist 2>&1 | FileCheck %s --check-prefix=MISSING-EMBED
// MISSING-EMBED: fatal error: file '{{.*}}does-not-exist' specified by '-fmodules-embed-file=' not found
diff --git a/test/Modules/hidden-definition.cpp b/test/Modules/hidden-definition.cpp
new file mode 100644
index 0000000..d06f939
--- /dev/null
+++ b/test/Modules/hidden-definition.cpp
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'struct X {}; struct Y : X { friend int f(Y); };' > %t/a.h
+// RUN: echo 'module a { header "a.h" }' > %t/map
+// RUN: %clang_cc1 -fmodules -x c++ -emit-module -fmodule-name=a %t/map -o %t/a.pcm
+// RUN: %clang_cc1 -fmodules -x c++ -verify -fmodule-file=%t/a.pcm %s -fno-modules-error-recovery
+
+struct X;
+struct Y;
+
+// Ensure that we can't use the definitions of X and Y, since we've not imported module a.
+Y *yp;
+X *xp = yp; // expected-error {{cannot initialize}}
+_Static_assert(!__is_convertible(Y*, X*), "");
+X &xr = *yp; // expected-error {{unrelated type}}
+int g(Y &y) { f(y); } // expected-error {{undeclared identifier 'f'}}
diff --git a/test/Modules/merge-enumerators.cpp b/test/Modules/merge-enumerators.cpp
index 5267ac6..10e1914 100644
--- a/test/Modules/merge-enumerators.cpp
+++ b/test/Modules/merge-enumerators.cpp
@@ -16,11 +16,13 @@
#ifdef MERGE_LATE
namespace N {
- // FIXME: Should we accept this and reject the usage below due to ambiguity instead?
- enum { A } a; // expected-error {{redefinition of enumerator 'A'}}
- // expected-note@a.h:1 {{here}} (from module B.b)
+ enum { A } a; // expected-note {{candidate}}
+ // expected-note@a.h:1 {{candidate}} (from module B.b)
}
#include "a.h"
#endif
N::E e = N::A;
+#ifdef MERGE_LATE
+// expected-error@-2 {{ambiguous}}
+#endif
diff --git a/test/Modules/modular_maps.cpp b/test/Modules/modular_maps.cpp
index 3b6afc7..fc44131 100644
--- a/test/Modules/modular_maps.cpp
+++ b/test/Modules/modular_maps.cpp
@@ -16,4 +16,4 @@
#include "b.h" // expected-error {{private header}}
@import C;
const int v = a + c + x;
-const int val = a + b + c + x; // expected-error {{undeclared identifier}}
+const int val = a + b + c + x;
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
index 6e723c8..42ab185 100644
--- a/test/Modules/module-private.cpp
+++ b/test/Modules/module-private.cpp
@@ -12,11 +12,7 @@
}
int test_broken() {
- HiddenStruct hidden; // \
- // expected-error{{must use 'struct' tag to refer to type 'HiddenStruct' in this scope}} \
- // expected-error{{definition of 'HiddenStruct' must be imported}}
- // expected-note@Inputs/module_private_left.h:3 {{previous definition is here}}
-
+ HiddenStruct hidden; // expected-error{{unknown type name 'HiddenStruct'}}
Integer i; // expected-error{{unknown type name 'Integer'}}
int *ip = 0;
diff --git a/test/Modules/no-linkage.cpp b/test/Modules/no-linkage.cpp
new file mode 100644
index 0000000..1ec8f40
--- /dev/null
+++ b/test/Modules/no-linkage.cpp
@@ -0,0 +1,56 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-local-submodule-visibility -I%S/Inputs/no-linkage -fmodule-map-file=%S/Inputs/no-linkage/module.modulemap %s -verify
+
+#include "empty.h"
+
+namespace NS { int n; } // expected-note {{candidate}}
+struct Typedef { int n; }; // expected-note {{candidate}}
+int AliasDecl; // expected-note {{candidate}}
+int UsingDecl; // expected-note {{candidate}}
+namespace RealNS = NS; // expected-note {{candidate}}
+typedef int Struct; // expected-note {{candidate}}
+enum { Variable }; // expected-note {{candidate}}
+const int AnotherNS = 0; // expected-note {{candidate}}
+const int Enumerator = 0; // expected-note {{candidate}}
+static int Overloads; // expected-note {{candidate}}
+
+// expected-note@decls.h:1 {{candidate}}
+// expected-note@decls.h:2 {{candidate}}
+// expected-note@decls.h:3 {{candidate}}
+// expected-note@decls.h:4 {{candidate}}
+// expected-note@decls.h:5 {{candidate}}
+// expected-note@decls.h:6 {{candidate}}
+// expected-note@decls.h:7 {{candidate}}
+// expected-note@decls.h:8 {{candidate}}
+// expected-note@decls.h:9 {{candidate}}
+// expected-note@decls.h:10 {{candidate}}
+// expected-note@decls.h:11 {{candidate}}
+
+void use(int);
+void use_things() {
+ use(Typedef().n);
+ use(NS::n);
+ use(AliasDecl);
+ use(UsingDecl);
+ use(RealNS::n);
+ use(Struct(0));
+ use(Variable);
+ use(AnotherNS);
+ use(Enumerator);
+ use(Overloads);
+}
+
+#include "decls.h"
+
+void use_things_again() {
+ use(Typedef().n); // expected-error {{ambiguous}}
+ use(NS::n); // expected-error {{ambiguous}}
+ use(AliasDecl); // expected-error {{ambiguous}}
+ use(UsingDecl); // expected-error {{ambiguous}}
+ use(RealNS::n); // expected-error {{ambiguous}}
+ use(Struct(0)); // expected-error {{ambiguous}}
+ use(Variable); // expected-error {{ambiguous}}
+ use(AnotherNS); // expected-error {{ambiguous}}
+ use(Enumerator); // expected-error {{ambiguous}}
+ use(Overloads); // expected-error {{ambiguous}}
+}
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
index e8549fa..42baf35 100644
--- a/test/Modules/objc-categories.m
+++ b/test/Modules/objc-categories.m
@@ -9,7 +9,7 @@
@import category_bottom;
// expected-note@Inputs/category_left.h:14 {{previous definition}}
-// expected-warning@Inputs/category_right.h:11 {{duplicate definition of category}}
+// expected-warning@Inputs/category_right.h:12 {{duplicate definition of category}}
// expected-note@Inputs/category_top.h:1 {{receiver is instance of class declared here}}
@interface Foo(Source)
diff --git a/test/Modules/separate_map_tree.cpp b/test/Modules/separate_map_tree.cpp
index 5a1fff4..a5cb988 100644
--- a/test/Modules/separate_map_tree.cpp
+++ b/test/Modules/separate_map_tree.cpp
@@ -5,4 +5,4 @@
#include "public-in-b.h" // expected-error {{private header}}
#include "public-in-c.h"
#include "private-in-c.h" // expected-error {{private header}}
-const int val = common + b + c + c_; // expected-error {{undeclared identifier}}
+const int val = common + b + c + c_;
diff --git a/test/Modules/submodule-visibility-cycles.cpp b/test/Modules/submodule-visibility-cycles.cpp
index f26f6f2..a01fe56 100644
--- a/test/Modules/submodule-visibility-cycles.cpp
+++ b/test/Modules/submodule-visibility-cycles.cpp
@@ -3,7 +3,7 @@
#include "cycle1.h"
C1 c1;
-C2 c2; // expected-error {{must be imported}} expected-error {{}}
+C2 c2; // expected-error {{must be imported}}
// expected-note@cycle2.h:6 {{here}}
#include "cycle2.h"
diff --git a/test/Modules/submodule-visibility.cpp b/test/Modules/submodule-visibility.cpp
index b2c5fc7..345ae15 100644
--- a/test/Modules/submodule-visibility.cpp
+++ b/test/Modules/submodule-visibility.cpp
@@ -28,3 +28,10 @@
#ifndef B
#error B is not defined
#endif
+
+// Ensure we don't compute the linkage of this struct before we find it has a
+// typedef name for linkage purposes.
+typedef struct {
+ int p;
+ void (*f)(int p);
+} name_for_linkage;
diff --git a/test/Modules/submodules-merge-defs.cpp b/test/Modules/submodules-merge-defs.cpp
index 6a46e6d..23d1f5c 100644
--- a/test/Modules/submodules-merge-defs.cpp
+++ b/test/Modules/submodules-merge-defs.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -fmodules-local-submodule-visibility -DTEXTUAL
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -fmodules-local-submodule-visibility
-// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -fmodules-local-submodule-visibility -DTEXTUAL -DEARLY_INDIRECT_INCLUDE -fno-modules-hide-internal-linkage
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -fmodules-local-submodule-visibility -DTEXTUAL -DEARLY_INDIRECT_INCLUDE
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -fmodules-local-submodule-visibility -fmodule-feature use_defs_twice -DIMPORT_USE_2
// Trigger import of definitions, but don't make them visible.
@@ -12,7 +12,7 @@
#include "indirect.h"
#endif
-A pre_a; // expected-error {{must use 'struct'}}
+A pre_a;
#ifdef IMPORT_USE_2
// expected-error-re@-2 {{must be imported from one of {{.*}}stuff.use{{.*}}stuff.use-2}}
#elif EARLY_INDIRECT_INCLUDE
@@ -21,35 +21,34 @@
// expected-error@-6 {{must be imported from module 'stuff.use'}}
#endif
// expected-note@defs.h:1 +{{here}}
+extern class A pre_a2;
+int pre_use_a = use_a(pre_a2); // expected-error 2{{'A' must be imported}} expected-error {{'use_a' must be imported}}
// expected-note@defs.h:2 +{{here}}
-int pre_use_a = use_a(pre_a); // expected-error {{'A' must be imported}} expected-error {{'use_a' must be imported}}
B::Inner2 pre_bi; // expected-error +{{must be imported}}
// expected-note@defs.h:4 +{{here}}
// expected-note@defs.h:17 +{{here}}
-void pre_bfi(B b) { // expected-error {{must use 'class'}} expected-error +{{must be imported}}
- b.f<int>(); // expected-error +{{must be imported}} expected-error +{{}}
- // expected-note@defs.h:19 +{{here}}
+void pre_bfi(B b) { // expected-error +{{must be imported}}
+ b.f<int>(); // expected-error +{{}}
}
C_Base<1> pre_cb1; // expected-error +{{must be imported}}
// expected-note@defs.h:23 +{{here}}
-C1 pre_c1; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
+C1 pre_c1; // expected-error +{{must be imported}}
// expected-note@defs.h:25 +{{here}}
-C2 pre_c2; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
+C2 pre_c2; // expected-error +{{must be imported}}
// expected-note@defs.h:26 +{{here}}
D::X pre_dx; // expected-error +{{must be imported}}
// expected-note@defs.h:28 +{{here}}
// expected-note@defs.h:29 +{{here}}
-// FIXME: We should warn that use_dx is being used without being imported.
-int pre_use_dx = use_dx(pre_dx);
+int pre_use_dx = use_dx(pre_dx); // ignored; pre_dx is invalid
int pre_e = E(0); // expected-error {{must be imported}}
// expected-note@defs.h:32 +{{here}}
int pre_ff = F<int>().f(); // expected-error +{{must be imported}}
-int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
+int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}} expected-error 2{{expected}}
// expected-note@defs.h:34 +{{here}}
G::A pre_ga // expected-error +{{must be imported}}
@@ -69,8 +68,9 @@
#endif
// expected-note@defs.h:58 +{{here}}
-ScopedEnum pre_scopedenum; // expected-error {{must be imported}} expected-error {{must use 'enum'}}
-// expected-note@defs.h:106 {{here}}
+ScopedEnum pre_scopedenum; // expected-error {{must be imported}}
+// expected-note@defs.h:105 0-1{{here}}
+// expected-note@defs.h:106 0-1{{here}}
enum ScopedEnum : int;
ScopedEnum pre_scopedenum_declared; // ok
@@ -111,4 +111,17 @@
#ifdef TEXTUAL
#include "use-defs.h"
void use_static_inline() { StaticInline::g({}); }
+#ifdef EARLY_INDIRECT_INCLUDE
+// expected-warning@-2 {{ambiguous use of internal linkage declaration 'g' defined in multiple modules}}
+// expected-note@defs.h:71 {{declared here in module 'redef'}}
+// expected-note@defs.h:71 {{declared here in module 'stuff.use'}}
+#endif
+int use_anon_enum = G::g;
+#ifdef EARLY_INDIRECT_INCLUDE
+// expected-warning@-2 3{{ambiguous use of internal linkage declaration 'g' defined in multiple modules}}
+// FIXME: These notes are produced, but -verify can't match them?
+// FIXME-note@defs.h:51 3{{declared here in module 'redef'}}
+// FIXME-note@defs.h:51 3{{declared here in module 'stuff.use'}}
+#endif
+int use_named_enum = G::i;
#endif
diff --git a/test/Modules/tag-injection.c b/test/Modules/tag-injection.c
new file mode 100644
index 0000000..5bb1547
--- /dev/null
+++ b/test/Modules/tag-injection.c
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'struct a;' > %t/a.h
+// RUN: echo 'struct b {}; void foo(struct b*);' > %t/b.h
+// RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } }' > %t/x.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/x.modulemap %s -I%t -verify
+
+#include "a.h"
+
+void f(struct a *p);
+
+// FIXME: We should warn that 'b' will not be visible outside of this function,
+// but we merge this 'b' with X.b's 'b' because we don't yet implement C's
+// "compatible types" rule.
+void g(struct b *p);
+
+struct b b; // expected-error {{definition of 'b' must be imported from module 'X.b' before it is required}}
+// expected-note@b.h:1 {{here}}
diff --git a/test/Modules/tag-injection.cpp b/test/Modules/tag-injection.cpp
new file mode 100644
index 0000000..e55598b
--- /dev/null
+++ b/test/Modules/tag-injection.cpp
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'struct tm;' > %t/a.h
+// RUN: echo 'struct X {}; void foo(struct tm*);' > %t/b.h
+// RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } }' > %t/x.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -std=c++11
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -fmodules-local-submodule-visibility -std=c++11
+
+#include "a.h"
+
+using ::tm;
+
+struct A {
+ // This use of 'struct X' makes the declaration (but not definition) of X visible.
+ virtual void f(struct X *p);
+};
+
+namespace N {
+ struct B : A {
+ void f(struct X *q) override;
+ };
+}
+
+X x; // expected-error {{definition of 'X' must be imported from module 'X.b' before it is required}}
+// expected-note@b.h:1 {{here}}
diff --git a/test/Modules/typedef-tag-not-visible.m b/test/Modules/typedef-tag-not-visible.m
new file mode 100644
index 0000000..e1a6406
--- /dev/null
+++ b/test/Modules/typedef-tag-not-visible.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify
+
+@import TypedefTag;
+
+typedef struct { int x; } TypedefStructHidden_t;
+typedef struct { int x; } TypedefStructVisible_t; // expected-error{{typedef redefinition}}
+// expected-note@typedef-tag.h:1 {{here}}
diff --git a/test/Modules/using-decl-redecl.cpp b/test/Modules/using-decl-redecl.cpp
index 0e78cec..0524052 100644
--- a/test/Modules/using-decl-redecl.cpp
+++ b/test/Modules/using-decl-redecl.cpp
@@ -2,10 +2,20 @@
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t \
// RUN: -fmodule-map-file=%S/Inputs/using-decl-redecl/module.modulemap \
// RUN: -I%S/Inputs/using-decl-redecl \
+// RUN: -Wno-modules-ambiguous-internal-linkage \
// RUN: -verify %s
+
+#include "d.h"
+
+const int n = 0;
+namespace M { using ::n; }
+
#include "c.h"
+
N::clstring y = b;
// Use a typo to trigger import of all declarations in N.
N::clstrinh s; // expected-error {{did you mean 'clstring'}}
-// expected-note@a.h:2 {{here}}
+// expected-note@a.h:3 {{here}}
+
+namespace M { using N::n; }
diff --git a/test/Modules/using-decl.cpp b/test/Modules/using-decl.cpp
index 1677585..b24593b 100644
--- a/test/Modules/using-decl.cpp
+++ b/test/Modules/using-decl.cpp
@@ -1,8 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -DEARLY_IMPORT
// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -UEARLY_IMPORT
-// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -DEARLY_IMPORT -fno-modules-hide-internal-linkage
-// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -UEARLY_IMPORT -fno-modules-hide-internal-linkage
// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -DEARLY_IMPORT -fmodules-local-submodule-visibility
// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -UEARLY_IMPORT -fmodules-local-submodule-visibility
diff --git a/test/OpenMP/atomic_capture_codegen.cpp b/test/OpenMP/atomic_capture_codegen.cpp
index 6dd9f7a..f91da3e 100644
--- a/test/OpenMP/atomic_capture_codegen.cpp
+++ b/test/OpenMP/atomic_capture_codegen.cpp
@@ -72,7 +72,10 @@
typedef float float2 __attribute__((ext_vector_type(2)));
float2 float2x;
-register int rix __asm__("0");
+// Register "0" is currently an invalid register for global register variables.
+// Use "esp" instead of "0".
+// register int rix __asm__("0");
+register int rix __asm__("esp");
int main() {
// CHECK: [[PREV:%.+]] = atomicrmw add i8* @{{.+}}, i8 1 monotonic
diff --git a/test/OpenMP/atomic_codegen.cpp b/test/OpenMP/atomic_codegen.cpp
index cab9df7..536f2cd 100644
--- a/test/OpenMP/atomic_codegen.cpp
+++ b/test/OpenMP/atomic_codegen.cpp
@@ -112,7 +112,7 @@
// TERM_DEBUG: call void @__clang_call_terminate
// TERM_DEBUG: unreachable
}
-// TERM_DEBUG-DAG: [[READ_LOC]] = !DILocation(line: [[@LINE-33]],
-// TERM_DEBUG-DAG: [[WRITE_LOC]] = !DILocation(line: [[@LINE-28]],
-// TERM_DEBUG-DAG: [[UPDATE_LOC]] = !DILocation(line: [[@LINE-22]],
-// TERM_DEBUG-DAG: [[CAPTURE_LOC]] = !DILocation(line: [[@LINE-16]],
+// TERM_DEBUG-DAG: [[READ_LOC]] = !DILocation(line: [[@LINE-28]],
+// TERM_DEBUG-DAG: [[WRITE_LOC]] = !DILocation(line: [[@LINE-22]],
+// TERM_DEBUG-DAG: [[UPDATE_LOC]] = !DILocation(line: [[@LINE-16]],
+// TERM_DEBUG-DAG: [[CAPTURE_LOC]] = !DILocation(line: [[@LINE-9]],
diff --git a/test/OpenMP/atomic_read_codegen.c b/test/OpenMP/atomic_read_codegen.c
index fc47c82..0cd46e3 100644
--- a/test/OpenMP/atomic_read_codegen.c
+++ b/test/OpenMP/atomic_read_codegen.c
@@ -72,7 +72,10 @@
typedef float float2 __attribute__((ext_vector_type(2)));
float2 float2x;
-register int rix __asm__("0");
+// Register "0" is currently an invalid register for global register variables.
+// Use "esp" instead of "0".
+// register int rix __asm__("0");
+register int rix __asm__("esp");
int main() {
// CHECK: load atomic i8, i8*
diff --git a/test/OpenMP/atomic_update_codegen.cpp b/test/OpenMP/atomic_update_codegen.cpp
index df8b538..063b76d 100644
--- a/test/OpenMP/atomic_update_codegen.cpp
+++ b/test/OpenMP/atomic_update_codegen.cpp
@@ -72,7 +72,10 @@
typedef float float2 __attribute__((ext_vector_type(2)));
float2 float2x;
-register int rix __asm__("0");
+// Register "0" is currently an invalid register for global register variables.
+// Use "esp" instead of "0".
+// register int rix __asm__("0");
+register int rix __asm__("esp");
int main() {
// CHECK-NOT: atomicrmw
diff --git a/test/OpenMP/atomic_write_codegen.c b/test/OpenMP/atomic_write_codegen.c
index 1ee26b0..66172af 100644
--- a/test/OpenMP/atomic_write_codegen.c
+++ b/test/OpenMP/atomic_write_codegen.c
@@ -72,7 +72,10 @@
typedef float float2 __attribute__((ext_vector_type(2)));
float2 float2x;
-register int rix __asm__("0");
+// Register "0" is currently an invalid register for global register variables.
+// Use "esp" instead of "0".
+// register int rix __asm__("0");
+register int rix __asm__("esp");
int main() {
// CHECK: load i8, i8*
diff --git a/test/OpenMP/barrier_ast_print.cpp b/test/OpenMP/barrier_ast_print.cpp
index fbb478b..062df80 100644
--- a/test/OpenMP/barrier_ast_print.cpp
+++ b/test/OpenMP/barrier_ast_print.cpp
@@ -12,6 +12,15 @@
T tmain(T argc) {
static T a;
#pragma omp barrier
+ switch (argc) {
+ case 0:
+#pragma omp barrier
+ break;
+ default:
+#pragma omp barrier
+#pragma omp barrier
+ break;
+ }
return a + argc;
}
// CHECK: static int a;
@@ -20,12 +29,39 @@
// CHECK-NEXT: #pragma omp barrier
// CHECK: static T a;
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: switch (argc) {
+// CHECK-NEXT: case 0:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: default:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: }
int main(int argc, char **argv) {
static int a;
// CHECK: static int a;
#pragma omp barrier
// CHECK-NEXT: #pragma omp barrier
+ switch (argc) {
+ case 0:
+#pragma omp barrier
+#pragma omp barrier
+ break;
+ default:
+#pragma omp barrier
+ break;
+ }
+// CHECK-NEXT: switch (argc) {
+// CHECK-NEXT: case 0:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: default:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: }
return tmain(argc) + tmain(argv[0][0]) + a;
}
diff --git a/test/OpenMP/barrier_messages.cpp b/test/OpenMP/barrier_messages.cpp
index 4dc6480..7d79445 100644
--- a/test/OpenMP/barrier_messages.cpp
+++ b/test/OpenMP/barrier_messages.cpp
@@ -27,7 +27,7 @@
#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
switch (argc)
case 1: {
#pragma omp barrier
@@ -35,7 +35,7 @@
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
break;
default: {
#pragma omp barrier
@@ -81,7 +81,7 @@
#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
switch (argc)
case 1: {
#pragma omp barrier
@@ -89,7 +89,7 @@
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
break;
default: {
#pragma omp barrier
diff --git a/test/OpenMP/cancel_codegen.cpp b/test/OpenMP/cancel_codegen.cpp
index c7eaa1a..e2dd367 100644
--- a/test/OpenMP/cancel_codegen.cpp
+++ b/test/OpenMP/cancel_codegen.cpp
@@ -111,7 +111,6 @@
// CHECK: br label %[[RETURN:.+]]
// CHECK: [[ELSE]]
// CHECK: br label
-// CHECK: call void @__kmpc_barrier
// CHECK: [[RETURN]]
// CHECK: ret void
@@ -129,7 +128,6 @@
// CHECK: call i32 @__kmpc_single(
// CHECK-NOT: @__kmpc_cancel
// CHECK: call void @__kmpc_end_single(
-// CHECK: call void @__kmpc_barrier(%ident_t*
// CHECK: ret void
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
@@ -164,7 +162,6 @@
// CHECK: [[CONTINUE]]
// CHECK: br label
// CHECK: call void @__kmpc_for_static_fini(
-// CHECK: call void @__kmpc_barrier(%ident_t*
// CHECK: ret void
#endif
diff --git a/test/OpenMP/cancel_messages.cpp b/test/OpenMP/cancel_messages.cpp
index 0708838..e23b5c3 100644
--- a/test/OpenMP/cancel_messages.cpp
+++ b/test/OpenMP/cancel_messages.cpp
@@ -53,7 +53,7 @@
#pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp cancel sections // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
+#pragma omp cancel sections
switch (argc)
case 1: {
#pragma omp cancel for
@@ -61,7 +61,7 @@
switch (argc) {
#pragma omp cancel taskgroup
case 1:
-#pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
+#pragma omp cancel parallel
break;
default: {
#pragma omp cancel sections
diff --git a/test/OpenMP/cancellation_point_codegen.cpp b/test/OpenMP/cancellation_point_codegen.cpp
index ee557fd..795f69e 100644
--- a/test/OpenMP/cancellation_point_codegen.cpp
+++ b/test/OpenMP/cancellation_point_codegen.cpp
@@ -129,7 +129,6 @@
// CHECK: call i32 @__kmpc_single(
// CHECK-NOT: @__kmpc_cancellationpoint
// CHECK: call void @__kmpc_end_single(
-// CHECK: call void @__kmpc_barrier(%ident_t*
// CHECK: ret void
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
@@ -164,7 +163,6 @@
// CHECK: [[CONTINUE]]
// CHECK: br label
// CHECK: call void @__kmpc_for_static_fini(
-// CHECK: call void @__kmpc_barrier(%ident_t*
// CHECK: ret void
#endif
diff --git a/test/OpenMP/cancellation_point_messages.cpp b/test/OpenMP/cancellation_point_messages.cpp
index d25cb61..2324915 100644
--- a/test/OpenMP/cancellation_point_messages.cpp
+++ b/test/OpenMP/cancellation_point_messages.cpp
@@ -53,7 +53,7 @@
#pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp cancellation point sections // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
+#pragma omp cancellation point sections
switch (argc)
case 1: {
#pragma omp cancellation point for
@@ -61,7 +61,7 @@
switch (argc) {
#pragma omp cancellation point taskgroup
case 1:
-#pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
+#pragma omp cancellation point parallel
break;
default: {
#pragma omp cancellation point sections
diff --git a/test/OpenMP/critical_ast_print.cpp b/test/OpenMP/critical_ast_print.cpp
index 87a1fe0..7189fdd 100644
--- a/test/OpenMP/critical_ast_print.cpp
+++ b/test/OpenMP/critical_ast_print.cpp
@@ -8,6 +8,26 @@
void foo() {}
+// CHECK: template <typename T, int N> int tmain(T argc, char **argv)
+template <typename T, int N>
+int tmain (T argc, char **argv) {
+ T b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp critical
+ a=2;
+// CHECK-NEXT: #pragma omp critical
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: ++a;
+ ++a;
+#pragma omp critical (the_name) hint(N)
+ foo();
+// CHECK-NEXT: #pragma omp critical (the_name) hint(N)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: return N;
+ return N;
+}
+
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
@@ -18,12 +38,12 @@
// CHECK-NEXT: a = 2;
// CHECK-NEXT: ++a;
++a;
-#pragma omp critical (the_name)
+#pragma omp critical (the_name1) hint(23)
foo();
-// CHECK-NEXT: #pragma omp critical (the_name)
+// CHECK-NEXT: #pragma omp critical (the_name1) hint(23)
// CHECK-NEXT: foo();
-// CHECK-NEXT: return 0;
- return 0;
+// CHECK-NEXT: return tmain<int, 4>(a, argv);
+ return tmain<int, 4>(a, argv);
}
#endif
diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp
index 47099d6..e44e220 100644
--- a/test/OpenMP/critical_codegen.cpp
+++ b/test/OpenMP/critical_codegen.cpp
@@ -10,6 +10,7 @@
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
// CHECK: [[UNNAMED_LOCK:@.+]] = common global [8 x i32] zeroinitializer
// CHECK: [[THE_NAME_LOCK:@.+]] = common global [8 x i32] zeroinitializer
+// CHECK: [[THE_NAME_LOCK1:@.+]] = common global [8 x i32] zeroinitializer
// CHECK: define {{.*}}void [[FOO:@.+]]()
@@ -32,6 +33,19 @@
// CHECK: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
#pragma omp critical(the_name)
foo();
+// CHECK: call {{.*}}void @__kmpc_critical_with_hint([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]], i{{64|32}} 23)
+// CHECK-NEXT: invoke {{.*}}void [[FOO]]()
+// CHECK: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]])
+#pragma omp critical(the_name1) hint(23)
+ foo();
+// CHECK: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
+// CHECK-NOT: call {{.*}}void @__kmpc_end_critical(
+ if (a)
+#pragma omp critical(the_name)
+ while (1)
+ ;
+// CHECK: call {{.*}}void [[FOO]]()
+ foo();
// CHECK-NOT: call void @__kmpc_critical
// CHECK-NOT: call void @__kmpc_end_critical
return a;
diff --git a/test/OpenMP/critical_messages.cpp b/test/OpenMP/critical_messages.cpp
index e3f2ad7..bb5ec00 100644
--- a/test/OpenMP/critical_messages.cpp
+++ b/test/OpenMP/critical_messages.cpp
@@ -2,20 +2,21 @@
int foo();
-int main() {
+template<typename T, int N>
+int tmain(int argc, char **argv) { // expected-note {{declared here}}
#pragma omp critical
;
#pragma omp critical untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp critical'}}
#pragma omp critical unknown // expected-warning {{extra tokens at the end of '#pragma omp critical' are ignored}}
#pragma omp critical ( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp critical ( + // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
- #pragma omp critical (name // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp critical (name2 // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp critical (name1)
foo();
{
#pragma omp critical
} // expected-error {{expected statement}}
- #pragma omp critical (name) // expected-note {{previous 'critical' region starts here}}
+ #pragma omp critical (name2) // expected-note {{previous 'critical' region starts here}}
#pragma omp critical
for (int i = 0; i < 10; ++i) {
foo();
@@ -23,11 +24,11 @@
#pragma omp for
for (int j = 0; j < 10; j++) {
foo();
- #pragma omp critical(name) // expected-error {{cannot nest 'critical' regions having the same name 'name'}}
+ #pragma omp critical(name2) // expected-error {{cannot nest 'critical' regions having the same name 'name2'}}
foo();
}
}
- #pragma omp critical (name)
+ #pragma omp critical (name2)
#pragma omp critical
for (int i = 0; i < 10; ++i) {
foo();
@@ -38,7 +39,7 @@
foo();
}
}
- #pragma omp critical (name)
+ #pragma omp critical (name2)
#pragma omp critical
for (int i = 0; i < 10; ++i) {
foo();
@@ -50,9 +51,86 @@
}
}
+ #pragma omp critical (name2) hint // expected-error {{expected '(' after 'hint'}}
+ foo();
+ #pragma omp critical (name2) hint( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp critical (name2) hint(argc) // expected-error {{expression is not an integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ foo();
+ #pragma omp critical (name) hint(N) // expected-error {{argument to 'hint' clause must be a strictly positive integer value}} expected-error {{constructs with the same name must have a 'hint' clause with the same value}} expected-note {{'hint' clause with value '4'}}
+ foo();
+ #pragma omp critical hint(N) // expected-error {{the name of the construct must be specified in presence of 'hint' clause}}
+ foo();
return 0;
}
+int main(int argc, char **argv) { // expected-note {{declared here}}
+ #pragma omp critical
+ ;
+ #pragma omp critical untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp critical'}}
+ #pragma omp critical unknown // expected-warning {{extra tokens at the end of '#pragma omp critical' are ignored}}
+ #pragma omp critical ( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp critical ( + // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp critical (name2 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp critical (name1)
+ foo();
+ {
+ #pragma omp critical
+ } // expected-error {{expected statement}}
+ #pragma omp critical (name2) // expected-note {{previous 'critical' region starts here}}
+ #pragma omp critical
+ for (int i = 0; i < 10; ++i) {
+ foo();
+ #pragma omp parallel
+ #pragma omp for
+ for (int j = 0; j < 10; j++) {
+ foo();
+ #pragma omp critical(name2) // expected-error {{cannot nest 'critical' regions having the same name 'name2'}}
+ foo();
+ }
+ }
+ #pragma omp critical (name2)
+ #pragma omp critical
+ for (int i = 0; i < 10; ++i) {
+ foo();
+ #pragma omp parallel
+ #pragma omp for
+ for (int j = 0; j < 10; j++) {
+ #pragma omp critical
+ foo();
+ }
+ }
+ #pragma omp critical (name2)
+ #pragma omp critical
+ for (int i = 0; i < 10; ++i) {
+ foo();
+ #pragma omp parallel
+ #pragma omp for
+ for (int j = 0; j < 10; j++) {
+ #pragma omp critical (nam)
+ foo();
+ }
+ }
+
+ #pragma omp critical (name2) hint // expected-error {{expected '(' after 'hint'}}
+ foo();
+ #pragma omp critical (name2) hint( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+ #pragma omp critical (name2) hint(argc) // expected-error {{expression is not an integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ foo();
+ #pragma omp critical (name) hint(23) // expected-note {{previous 'hint' clause with value '23'}}
+ foo();
+ #pragma omp critical hint(-5) // expected-error {{argument to 'hint' clause must be a strictly positive integer value}}
+ foo();
+ #pragma omp critical hint(1) // expected-error {{the name of the construct must be specified in presence of 'hint' clause}}
+ foo();
+ return tmain<int, 4>(argc, argv) + tmain<float, -5>(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain<float, -5>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<int, 4>' requested here}}
+}
+
int foo() {
L1:
foo();
@@ -69,4 +147,4 @@
}
return 0;
-}
+ }
diff --git a/test/OpenMP/distribute_ast_print.cpp b/test/OpenMP/distribute_ast_print.cpp
new file mode 100644
index 0000000..c3a175a
--- /dev/null
+++ b/test/OpenMP/distribute_ast_print.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T, int N>
+T tmain(T argc) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+// CHECK: static T a;
+#pragma omp distribute
+// CHECK-NEXT: #pragma omp distribute
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute private(argc, b), firstprivate(c, d), collapse(2)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute private(argc,b) firstprivate(c,d) collapse(2)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+#pragma omp distribute
+// CHECK: #pragma omp distribute
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ return T();
+}
+
+int main (int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp distribute
+// CHECK-NEXT: #pragma omp distribute
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute private(argc,b),firstprivate(argv, c), collapse(2)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute private(argc,b) firstprivate(argv,c) collapse(2)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+#pragma omp distribute
+// CHECK: #pragma omp distribute
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ return (0);
+}
+
+#endif
diff --git a/test/OpenMP/distribute_collapse_messages.cpp b/test/OpenMP/distribute_collapse_messages.cpp
new file mode 100644
index 0000000..8818d65
--- /dev/null
+++ b/test/OpenMP/distribute_collapse_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp distribute collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp distribute collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp distribute collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp distribute', but found only 1}}
+ // expected-error@+3 2 {{directive '#pragma omp distribute' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp distribute collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp distribute collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp distribute collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp distribute'}}
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp distribute collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp distribute collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp distribute collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp distribute collapse (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp distribute', but found only 1}}
+ #pragma omp distribute collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp distribute', but found only 1}}
+ #pragma omp distribute collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp distribute' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp distribute collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp distribute collapse (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp distribute collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp distribute' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp distribute collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ #pragma omp distribute collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp distribute'}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/distribute_dist_schedule_ast_print.cpp b/test/OpenMP/distribute_dist_schedule_ast_print.cpp
new file mode 100644
index 0000000..32389ef
--- /dev/null
+++ b/test/OpenMP/distribute_dist_schedule_ast_print.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T, int N>
+T tmain(T argc) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+// CHECK: static T a;
+#pragma omp distribute dist_schedule(static,10)
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, 10)
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp distribute dist_schedule(static,a)
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, a)
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute dist_schedule(static,2)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, 2)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute dist_schedule(static,a)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, a)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+#pragma omp distribute
+// CHECK: #pragma omp distribute
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ return T();
+}
+
+int main (int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp distribute dist_schedule(static,10)
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, 10)
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp distribute dist_schedule(static,b)
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, b)
+ for (int i=0; i < 2; ++i)a=2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute dist_schedule(static,2)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, 2)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute dist_schedule(static,a)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)foo();
+// CHECK-NEXT: #pragma omp target
+// CHECK-NEXT: #pragma omp teams
+// CHECK-NEXT: #pragma omp distribute dist_schedule(static, a)
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: for (int j = 0; j < 10; ++j)
+// CHECK-NEXT: foo();
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+#pragma omp distribute
+// CHECK: #pragma omp distribute
+ for (int i = 0; i < 10; ++i)foo();
+// CHECK-NEXT: for (int i = 0; i < 10; ++i)
+// CHECK-NEXT: foo();
+ return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
+}
+
+#endif
diff --git a/test/OpenMP/distribute_dist_schedule_messages.cpp b/test/OpenMP/distribute_dist_schedule_messages.cpp
new file mode 100644
index 0000000..98652a2
--- /dev/null
+++ b/test/OpenMP/distribute_dist_schedule_messages.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note {{declared here}}
+
+template <class T, int N>
+T tmain(T argc) {
+ T b = argc, c, d, e, f, g;
+ char ** argv;
+ static T a;
+// CHECK: static T a;
+ #pragma omp distribute dist_schedule // expected-error {{expected '(' after 'dist_schedule'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule ( // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule () // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (argc)) // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, argc > 0 ? argv[1] : argv[2]) // expected-error2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static), dist_schedule (static, 1) // expected-error {{directive '#pragma omp distribute' cannot contain more than one 'dist_schedule' clause}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (int i = 0; i < 10; ++i) foo();
+ return T();
+}
+
+int main(int argc, char **argv) {
+ #pragma omp distribute dist_schedule // expected-error {{expected '(' after 'dist_schedule'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule ( // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule () // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (argc)) // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static), dist_schedule (static, 1) // expected-error {{directive '#pragma omp distribute' cannot contain more than one 'dist_schedule' clause}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i) foo();
+ #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i) foo();
+ return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0])); // expected-note {{in instantiation of function template specialization 'tmain<int, 5>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<char, 1>' requested here}}
+}
diff --git a/test/OpenMP/distribute_firstprivate_messages.cpp b/test/OpenMP/distribute_firstprivate_messages.cpp
new file mode 100644
index 0000000..5d371ab
--- /dev/null
+++ b/test/OpenMP/distribute_firstprivate_messages.cpp
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+ S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+ S5(const S5 &s5):a(s5.a) { }
+public:
+ S5(int v):a(v) { }
+};
+class S6 {
+ int a;
+public:
+ S6() : a(0) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = { 0 };
+ S4 e(4);
+ S5 g(5);
+ S6 p;
+ int i;
+ int &j = i;
+ #pragma omp distribute firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp distribute firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp distribute firstprivate () // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (argc)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate (argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(ba)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(ca) // expected-error {{no matching constructor for initialization of 'S3'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(da)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(S2::S2s)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(S2::S2sc)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams shared(i)
+ #pragma omp distribute firstprivate(i)
+ for (j = 0; j < argc; ++j) foo();
+ #pragma omp target
+ #pragma omp teams shared(i)
+ #pragma omp distribute firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) foo(); // expected-error {{loop iteration variable in the associated loop of 'omp distribute' directive may not be firstprivate, predetermined as private}}
+ #pragma omp target
+ #pragma omp teams private(argc) // expected-note {{defined as private}}
+ #pragma omp distribute firstprivate(argc) // expected-error {{private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams reduction(+:argc) // expected-note {{defined as reduction}}
+ #pragma omp distribute firstprivate(argc) // expected-error {{reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(j)
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute lastprivate(argc), firstprivate(argc) // expected-error {{lastprivate variable cannot be firstprivate in '#pragma omp distribute'}} expected-note{{defined as lastprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ #pragma omp target
+ #pragma omp teams
+#pragma omp distribute firstprivate(argc), lastprivate(argc) // expected-error {{lastprivate variable cannot be firstprivate in '#pragma omp distribute'}} expected-note{{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) foo();
+ return 0;
+}
diff --git a/test/OpenMP/distribute_private_messages.cpp b/test/OpenMP/distribute_private_messages.cpp
new file mode 100644
index 0000000..94ba465
--- /dev/null
+++ b/test/OpenMP/distribute_private_messages.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ static float S2s; // expected-note {{predetermined as shared}}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 c; // expected-note {{predetermined as shared}}
+const S3 ca[5]; // expected-note {{predetermined as shared}}
+extern const int f; // expected-note {{predetermined as shared}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{predetermined as shared}}
+ const int da[5] = { 0 }; // expected-note {{predetermined as shared}}
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+ #pragma omp distribute private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(ba)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(ca) // expected-error {{shared variable cannot be private}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(da) // expected-error {{shared variable cannot be private}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(S2::S2s) // expected-error {{shared variable cannot be private}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp distribute'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp target
+ #pragma omp teams
+ {
+ int i; // expected-note {{predetermined as private}}
+ #pragma omp distribute firstprivate(i), private(i) // expected-error {{private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ }
+ #pragma omp target
+ #pragma omp teams private(i)
+ #pragma omp distribute private(j)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel private(i)
+ #pragma omp target
+ #pragma omp teams firstprivate(i)
+ #pragma omp parallel private(i)
+ #pragma omp target
+ #pragma omp teams reduction(+:i)
+ #pragma omp distribute private(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp distribute private(i)
+ for (int k = 0; k < 10; ++k) {
+ #pragma omp target
+ #pragma omp teams private(i)
+ #pragma omp distribute private(i)
+ for (int x = 0; x < 10; ++x) foo();
+ }
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(i)
+ for (int k = 0; k < 10; ++k) {
+ #pragma omp target
+ #pragma omp teams firstprivate(i)
+ #pragma omp distribute private(i)
+ for (int x = 0; x < 10; ++x) foo();
+ }
+ #pragma omp target
+ #pragma omp teams reduction(+:i)
+ #pragma omp distribute
+ for (int k = 0; k < 10; ++k) {
+ #pragma omp target
+ #pragma omp teams reduction(+:i)
+ #pragma omp distribute private(i)
+ for (int x = 0; x < 10; ++x) foo();
+ }
+
+ return 0;
+}
diff --git a/test/OpenMP/flush_messages.cpp b/test/OpenMP/flush_messages.cpp
index 2f87a29..1c086a3 100644
--- a/test/OpenMP/flush_messages.cpp
+++ b/test/OpenMP/flush_messages.cpp
@@ -31,7 +31,7 @@
#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
switch (argc)
case 1: {
#pragma omp flush
@@ -39,7 +39,7 @@
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
break;
default: {
#pragma omp flush
@@ -95,7 +95,7 @@
#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
switch (argc)
case 1: {
#pragma omp flush
@@ -103,7 +103,7 @@
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
break;
default: {
#pragma omp flush
diff --git a/test/OpenMP/for_ast_print.cpp b/test/OpenMP/for_ast_print.cpp
index 1af391d..8fd82e7 100644
--- a/test/OpenMP/for_ast_print.cpp
+++ b/test/OpenMP/for_ast_print.cpp
@@ -20,7 +20,7 @@
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
-#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait linear(a : N)
+#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int j = 0; j < 2; ++j)
@@ -33,7 +33,7 @@
for (int j = 0; j < 2; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel
- // CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait linear(a: N)
+ // CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
diff --git a/test/OpenMP/for_collapse_messages.cpp b/test/OpenMP/for_collapse_messages.cpp
index 0a74433..d40c305 100644
--- a/test/OpenMP/for_collapse_messages.cpp
+++ b/test/OpenMP/for_collapse_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp for collapse (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp for collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}}
- // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for collapse (1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp for collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for collapse (2) // expected-note {{as specified in 'collapse' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for'}}
@@ -63,7 +63,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}}
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for collapse (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/for_firstprivate_messages.cpp b/test/OpenMP/for_firstprivate_messages.cpp
index 5c34fda..1933de2 100644
--- a/test/OpenMP/for_firstprivate_messages.cpp
+++ b/test/OpenMP/for_firstprivate_messages.cpp
@@ -118,7 +118,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
-#pragma omp for firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp for firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (int k = 0; k < argc; ++k) {
i = k;
v += i;
@@ -285,7 +285,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
-#pragma omp for firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp for firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (int k = 0; k < argc; ++k) {
i = k;
v += i;
diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp
index f268df6..36abd8d 100644
--- a/test/OpenMP/for_lastprivate_codegen.cpp
+++ b/test/OpenMP/for_lastprivate_codegen.cpp
@@ -340,7 +340,6 @@
// CHECK: [[LAST_DONE]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
@@ -372,7 +371,6 @@
// CHECK: [[LAST_DONE]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// CHECK: define internal void [[MAIN_MICROTASK3]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
@@ -419,7 +417,6 @@
// CHECK: [[LAST_DONE]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
diff --git a/test/OpenMP/for_linear_messages.cpp b/test/OpenMP/for_linear_messages.cpp
index b06852e..39fb21e 100644
--- a/test/OpenMP/for_linear_messages.cpp
+++ b/test/OpenMP/for_linear_messages.cpp
@@ -145,6 +145,8 @@
for (int k = 0; k < argc; ++k) { ++k; v += j; }
#pragma omp for linear(i)
for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for linear(i) ordered(1) // expected-error {{'linear' clause cannot be specified along with 'ordered' clause with a parameter}}
+ for (int k = 0; k < argc; ++k) ++k;
return 0;
}
@@ -207,6 +209,8 @@
for (int k = 0; k < argc; ++k) ++k;
#pragma omp for linear(i)
for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp for linear(i) ordered(1) // expected-error {{'linear' clause cannot be specified along with 'ordered' clause with a parameter}}
+ for (int k = 0; k < argc; ++k) ++k;
foomain<int,char>(argc,argv);
return 0;
diff --git a/test/OpenMP/for_loop_messages.cpp b/test/OpenMP/for_loop_messages.cpp
index 14b20ae..895baf5 100644
--- a/test/OpenMP/for_loop_messages.cpp
+++ b/test/OpenMP/for_loop_messages.cpp
@@ -10,10 +10,13 @@
};
static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
#pragma omp threadprivate(sii)
static int globalii;
-register int reg0 __asm__("0");
+// Currently, we cannot use "0" for global register variables.
+// register int reg0 __asm__("0");
+int reg0;
int test_iteration_spaces() {
const int N = 100;
@@ -307,6 +310,7 @@
#pragma omp parallel
{
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for' directive may not be threadprivate or thread local, predetermined as private}}
#pragma omp for
for (sii = 0; sii < 10; sii += 1)
c[sii] = a[sii];
diff --git a/test/OpenMP/for_misc_messages.c b/test/OpenMP/for_misc_messages.c
index fa42d07..0a7cdf8 100644
--- a/test/OpenMP/for_misc_messages.c
+++ b/test/OpenMP/for_misc_messages.c
@@ -175,17 +175,17 @@
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for collapse(-5)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for collapse(0)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -194,7 +194,7 @@
for (i = 0; i < 16; ++i)
// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
for (int j = 0; j < 16; ++j)
-// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+2 {{reduction variable must be shared}}
// expected-error@+1 {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
#pragma omp for reduction(+ : i, j)
for (int k = 0; k < 16; ++k)
diff --git a/test/OpenMP/for_ordered_clause.cpp b/test/OpenMP/for_ordered_clause.cpp
index 5b08021..8af509a 100644
--- a/test/OpenMP/for_ordered_clause.cpp
+++ b/test/OpenMP/for_ordered_clause.cpp
@@ -26,7 +26,7 @@
#pragma omp for ordered(argc
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
#pragma omp for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
@@ -37,7 +37,7 @@
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
-// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+2 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = ST; i < N; i++)
@@ -52,11 +52,19 @@
#pragma omp for ordered(1)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-#pragma omp for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp for ordered(N-1) // expected-error 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
+ for (int i = ST; i < N; i++)
+ argv[0][i] = argv[0][i] - argv[0][i - ST];
+#pragma omp for ordered(N) // expected-error {{argument to 'ordered' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for'}}
+#pragma omp for ordered(N) collapse(N + 2) // expected-error {{the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause}} expected-note {{parameter of the 'collapse' clause}} expected-error {{argument to 'ordered' clause must be a strictly positive integer value}}
+ for (int i = ST; i < N; i++)
+ for (int j = ST; j < N; j++)
+ for (int k = ST; k < N; k++)
+ foo();
return argc;
}
@@ -81,7 +89,7 @@
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
-// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
@@ -98,6 +106,14 @@
foo();
#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for'}}
+#pragma omp for ordered(0) // expected-error {{argument to 'ordered' clause must be a strictly positive integer value}}
+ for (int i = 4; i < 12; i++)
+ argv[0][i] = argv[0][i] - argv[0][i - 4];
+#pragma omp for ordered(2) collapse(3) // expected-error {{the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause}} expected-note {{parameter of the 'collapse' clause}}
+ for (int i = 0; i < 10; i++)
+ for (int j = 0; j < 11; j++)
+ for (int k = 0; k < 12; k++)
+ foo();
// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
return tmain<int, char, 1, 0>(argc, argv);
}
diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp
index 59d7854..423ab3c 100644
--- a/test/OpenMP/for_reduction_codegen.cpp
+++ b/test/OpenMP/for_reduction_codegen.cpp
@@ -379,7 +379,6 @@
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
@@ -606,9 +605,6 @@
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[ARRS_PRIV]]
// CHECK: br i1 [[DONE]],
// CHECK: call void @llvm.stackrestore(i8*
-// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
-// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
@@ -825,7 +821,6 @@
// CHECK: [[RED_DONE]]
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
diff --git a/test/OpenMP/for_reduction_messages.cpp b/test/OpenMP/for_reduction_messages.cpp
index 05368f1..317f88c 100644
--- a/test/OpenMP/for_reduction_messages.cpp
+++ b/test/OpenMP/for_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
void foo() {
}
@@ -54,6 +56,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable: no known conversion from 'int' to 'S6' for 1st argument}}
+#endif
int a;
public:
diff --git a/test/OpenMP/for_schedule_messages.cpp b/test/OpenMP/for_schedule_messages.cpp
index 807a979..8946ce3 100644
--- a/test/OpenMP/for_schedule_messages.cpp
+++ b/test/OpenMP/for_schedule_messages.cpp
@@ -13,13 +13,23 @@
T tmain(T argc, S **argv) {
#pragma omp for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for schedule (monotonic // expected-error {{expected ')'}} expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-warning {{missing ':' after schedule modifier - ignoring}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic, // expected-error {{expected ')'}} expected-error {{expected 'simd' in OpenMP clause 'schedule'}} expected-warning {{missing ':' after schedule modifier - ignoring}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (simd: // expected-error {{expected ')'}} expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (monotonic, auto // expected-error {{expected ')'}} expected-warning {{missing ':' after schedule modifier - ignoring}} expected-error {{expected 'simd' in OpenMP clause 'schedule'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic: auto, // expected-error {{expected ')'}} expected-error {{'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -28,7 +38,7 @@
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp for schedule (guided argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
@@ -36,7 +46,7 @@
#pragma omp for schedule (guided, (ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (static, S) // expected-error {{'S' does not refer to a value}}
@@ -46,7 +56,25 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (dynamic, 1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp for schedule (static, N) // expected-error {{argument to 'schedule' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic: static) // expected-error {{'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic: auto) // expected-error {{'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic: runtime) // expected-error {{'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (monotonic, nonmonotonic: auto) // expected-error {{modifier 'nonmonotonic' cannot be used along with modifier 'monotonic'}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic, monotonic: auto) // expected-error {{modifier 'monotonic' cannot be used along with modifier 'nonmonotonic'}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic, nonmonotonic: auto) // expected-error {{modifier 'nonmonotonic' cannot be used along with modifier 'nonmonotonic'}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (monotonic, monotonic: auto) // expected-error {{modifier 'monotonic' cannot be used along with modifier 'monotonic'}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for schedule (nonmonotonic: guided) ordered // expected-error {{'schedule' clause with 'nonmonotonic' modifier cannot be specified if an 'ordered' clause is specified}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp for ordered(1) schedule(nonmonotonic: dynamic) // expected-error {{'schedule' clause with 'nonmonotonic' modifier cannot be specified if an 'ordered' clause is specified}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -54,13 +82,13 @@
int main(int argc, char **argv) {
#pragma omp for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -73,7 +101,7 @@
#pragma omp for schedule (dynamic, foobool(1) > 0 ? 1 : 2)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (guided, S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/for_simd_aligned_messages.cpp b/test/OpenMP/for_simd_aligned_messages.cpp
index d41ecc1..1007b3c 100644
--- a/test/OpenMP/for_simd_aligned_messages.cpp
+++ b/test/OpenMP/for_simd_aligned_messages.cpp
@@ -50,7 +50,7 @@
T sum = (T)0;
T ind2 = - num * L;
// Negative number is passed as L.
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp for simd aligned(arr:L)
for (i = 0; i < num; ++i) {
T cur = arr[(int)ind2];
@@ -65,7 +65,7 @@
template<int LEN> int test_warn() {
int *ind2 = 0;
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp for simd aligned(ind2:LEN)
for (int i = 0; i < 100; i++) {
ind2 += LEN;
diff --git a/test/OpenMP/for_simd_ast_print.cpp b/test/OpenMP/for_simd_ast_print.cpp
index 725c727..d4b13ba 100644
--- a/test/OpenMP/for_simd_ast_print.cpp
+++ b/test/OpenMP/for_simd_ast_print.cpp
@@ -14,8 +14,8 @@
N myind;
T sum = (T)0;
// CHECK: T sum = (T)0;
-#pragma omp for simd private(myind, g_ind), linear(ind), aligned(arr)
-// CHECK-NEXT: #pragma omp for simd private(myind,g_ind) linear(ind) aligned(arr)
+#pragma omp for simd private(myind, g_ind), linear(ind), aligned(arr) ordered
+// CHECK-NEXT: #pragma omp for simd private(myind,g_ind) linear(ind) aligned(arr) ordered
for (i = 0; i < num; ++i) {
myind = ind;
T cur = arr[myind];
@@ -92,8 +92,8 @@
int k1=0,k2=0;
static int *a;
// CHECK: static int *a;
-#pragma omp for simd
-// CHECK-NEXT: #pragma omp for simd
+#pragma omp for simd ordered
+// CHECK-NEXT: #pragma omp for simd ordered
for (int i=0; i < 2; ++i)*a=2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: *a = 2;
diff --git a/test/OpenMP/for_simd_codegen.cpp b/test/OpenMP/for_simd_codegen.cpp
index cc8193d..e1aa892 100644
--- a/test/OpenMP/for_simd_codegen.cpp
+++ b/test/OpenMP/for_simd_codegen.cpp
@@ -28,24 +28,24 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV:%[^,]+]],
-// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[SIMPLE_LOOP1_BODY:.+]], label %[[SIMPLE_LOOP1_END:[^,]+]]
for (int i = 3; i < 32; i += 5) {
// CHECK: [[SIMPLE_LOOP1_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
// CHECK: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 5
// CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 3, [[CALC_I_1]]
-// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
// ... loop body ...
// End of body: store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: store float [[RESULT:%.+]], float*
a[i] = b[i] * c[i] * d[i];
-// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
-// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
// br label %{{.+}}, !llvm.loop !{{.+}}
}
// CHECK: [[SIMPLE_LOOP1_END]]
@@ -132,36 +132,36 @@
// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]],
// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV3:%[^,]+]],
-// CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]]
+// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP3:%.+]] = icmp ule i64 [[IV3]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP3]], label %[[SIMPLE_LOOP3_BODY:.+]], label %[[SIMPLE_LOOP3_END:[^,]+]]
for (unsigned long long it = 2000; it >= 600; it-=400) {
// CHECK: [[SIMPLE_LOOP3_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV3_0:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[IV3_0:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul i64 [[IV3_0]], 400
// CHECK-NEXT: [[LC_IT_2:%.+]] = sub i64 2000, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64*
//
// Linear start and step are used to calculate current value of the linear variable.
-// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]
+// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]
+// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]],
+// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]
+// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[MUL:%.+]] = mul i64 [[IV3_1]], 1
// CHECK: [[GEP:%.+]] = getelementptr{{.*}}[[GLINSTART]]
-// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]]
*g_ptr++ = 0.0;
-// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: store double{{.*}}[[GEP_VAL]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]]
+// CHECK: store double{{.*}}[[GEP_VAL]]
a[it + lin]++;
// CHECK: [[FLT_INC:%.+]] = fadd float
-// CHECK-NEXT: store float [[FLT_INC]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store float [[FLT_INC]],
+// CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[ADD3_2:%.+]] = add i64 [[IV3_2]], 1
-// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]
}
// CHECK: [[SIMPLE_LOOP3_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -190,22 +190,22 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV4:%[^,]+]],
-// CHECK: [[IV4:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4:%.+]] = load i32, i32* [[OMP_IV4]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP4:%.+]] = icmp sle i32 [[IV4]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP4]], label %[[SIMPLE_LOOP4_BODY:.+]], label %[[SIMPLE_LOOP4_END:[^,]+]]
for (short it = 6; it <= 20; it-=-4) {
// CHECK: [[SIMPLE_LOOP4_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV4_0:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4_0:%.+]] = load i32, i32* [[OMP_IV4]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i32 [[IV4_0]], 4
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i32 6, [[LC_IT_1]]
// CHECK-NEXT: [[LC_IT_3:%.+]] = trunc i32 [[LC_IT_2]] to i16
-// CHECK-NEXT: store i16 [[LC_IT_3]], i16* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: store i16 [[LC_IT_3]], i16*
-// CHECK: [[IV4_2:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4_2:%.+]] = load i32, i32* [[OMP_IV4]]
// CHECK-NEXT: [[ADD4_2:%.+]] = add nsw i32 [[IV4_2]], 1
-// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]]
}
// CHECK: [[SIMPLE_LOOP4_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -227,22 +227,22 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV5:%[^,]+]],
-// CHECK: [[IV5:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5:%.+]] = load i32, i32* [[OMP_IV5]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP5:%.+]] = icmp sle i32 [[IV5]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP5]], label %[[SIMPLE_LOOP5_BODY:.+]], label %[[SIMPLE_LOOP5_END:[^,]+]]
for (unsigned char it = 'z'; it >= 'a'; it+=-1) {
// CHECK: [[SIMPLE_LOOP5_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV5_0:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5_0:%.+]] = load i32, i32* [[OMP_IV5]]
// CHECK-NEXT: [[IV5_1:%.+]] = mul nsw i32 [[IV5_0]], 1
// CHECK-NEXT: [[LC_IT_1:%.+]] = sub nsw i32 122, [[IV5_1]]
// CHECK-NEXT: [[LC_IT_2:%.+]] = trunc i32 [[LC_IT_1]] to i8
-// CHECK-NEXT: store i8 [[LC_IT_2]], i8* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: store i8 [[LC_IT_2]], i8*
-// CHECK: [[IV5_2:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5_2:%.+]] = load i32, i32* [[OMP_IV5]]
// CHECK-NEXT: [[ADD5_2:%.+]] = add nsw i32 [[IV5_2]], 1
-// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]]
}
// CHECK: [[SIMPLE_LOOP5_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -276,24 +276,24 @@
// CHECK: br label %[[SIMD_LOOP7_COND:[^,]+]]
// CHECK: [[SIMD_LOOP7_COND]]
-// CHECK-NEXT: [[IV7:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[IV7:%.+]] = load i64, i64* [[OMP_IV7]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP7:%.+]] = icmp sle i64 [[IV7]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP7]], label %[[SIMPLE_LOOP7_BODY:.+]], label %[[SIMPLE_LOOP7_END:[^,]+]]
for (long long i = -10; i < 10; i += 3) {
// CHECK: [[SIMPLE_LOOP7_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV7_0]], 3
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
-// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],
+// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]
// CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[LC_VAL]] to i32
-// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],
A = i;
-// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]
// CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1
-// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]
}
// CHECK: [[SIMPLE_LOOP7_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -329,23 +329,23 @@
// CHECK: br label %[[SIMD_LOOP8_COND:[^,]+]]
// CHECK: [[SIMD_LOOP8_COND]]
-// CHECK-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP8:%.+]] = icmp sle i64 [[IV8]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP8]], label %[[SIMPLE_LOOP8_BODY:.+]], label %[[SIMPLE_LOOP8_END:[^,]+]]
for (long long i = -10; i < 10; i += 3) {
// CHECK: [[SIMPLE_LOOP8_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV8_0]], 3
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
-// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
-// CHECK: store i32 %{{.+}}, i32* [[R_PRIV]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],
+// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]
+// CHECK: store i32 %{{.+}}, i32* [[R_PRIV]],
R *= i;
-// CHECK: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]]
// CHECK-NEXT: [[ADD8_2:%.+]] = add nsw i64 [[IV8_2]], 1
-// CHECK-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]]
}
// CHECK: [[SIMPLE_LOOP8_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -389,27 +389,27 @@
// CHECK: store i64 [[LB_VAL]], i64* [[T1_OMP_IV:%[^,]+]],
// ...
-// CHECK: [[IV:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[T1_OMP_IV]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP1:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP1]], label %[[T1_BODY:.+]], label %[[T1_END:[^,]+]]
// CHECK: [[T1_BODY]]
// Loop counters i and j updates:
-// CHECK: [[IV1:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV1:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[I_1:%.+]] = sdiv i64 [[IV1]], 4
// CHECK-NEXT: [[I_1_MUL1:%.+]] = mul nsw i64 [[I_1]], 1
// CHECK-NEXT: [[I_1_ADD0:%.+]] = add nsw i64 0, [[I_1_MUL1]]
// CHECK-NEXT: [[I_2:%.+]] = trunc i64 [[I_1_ADD0]] to i32
-// CHECK-NEXT: store i32 [[I_2]], i32* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
-// CHECK: [[IV2:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i32 [[I_2]], i32*
+// CHECK: [[IV2:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[J_1:%.+]] = srem i64 [[IV2]], 4
// CHECK-NEXT: [[J_2:%.+]] = mul nsw i64 [[J_1]], 2
// CHECK-NEXT: [[J_2_ADD0:%.+]] = add nsw i64 0, [[J_2]]
-// CHECK-NEXT: store i64 [[J_2_ADD0]], i64* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i64 [[J_2_ADD0]], i64*
// simd.for.inc:
-// CHECK: [[IV3:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV3:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[INC:%.+]] = add nsw i64 [[IV3]], 1
-// CHECK-NEXT: store i64 [[INC]], i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i64 [[INC]], i64* [[T1_OMP_IV]]
// CHECK-NEXT: br label {{%.+}}
// CHECK: [[T1_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -480,14 +480,14 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[IT_OMP_IV:%[^,]+]],
-// CHECK: [[IV:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}} !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[IT_OMP_IV]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[IT_BODY:[^,]+]], label %[[IT_END:[^,]+]]
for (IterDouble i = ia; i < ib; ++i) {
// CHECK: [[IT_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i32, i32* [[IT_OMP_IV]]
// Call of operator+ (i, IV).
// CHECK: {{%.+}} = invoke {{.+}} @{{.*}}IterDouble{{.*}}
// ... loop body ...
@@ -495,12 +495,12 @@
// Float multiply and save result.
// CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01
// CHECK-NEXT: invoke {{.+}} @{{.*}}IterDouble{{.*}}
-// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]], !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]]
++ic;
//
-// CHECK: [[IV2:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i32, i32* [[IT_OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add nsw i32 [[IV2]], 1
-// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]]
// br label %{{.*}}, !llvm.loop ![[ITER_LOOP_ID]]
}
// CHECK: [[IT_END]]
@@ -533,8 +533,8 @@
//
#pragma omp for simd collapse(4)
-// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp ule i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[COLL1_BODY:[^,]+]], label %[[COLL1_END:[^,]+]]
for (i = 1; i < 3; i++) // 2 iterations
@@ -544,25 +544,25 @@
{
// CHECK: [[COLL1_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i32, i32* [[OMP_IV]]
// Calculation of the loop counters values.
// CHECK: [[CALC_I_1:%.+]] = udiv i32 [[IV1]], 60
// CHECK-NEXT: [[CALC_I_1_MUL1:%.+]] = mul i32 [[CALC_I_1]], 1
// CHECK-NEXT: [[CALC_I_2:%.+]] = add i32 1, [[CALC_I_1_MUL1]]
// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
-// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_J_1:%.+]] = udiv i32 [[IV1_2]], 20
// CHECK-NEXT: [[CALC_J_2:%.+]] = urem i32 [[CALC_J_1]], 3
// CHECK-NEXT: [[CALC_J_2_MUL1:%.+]] = mul i32 [[CALC_J_2]], 1
// CHECK-NEXT: [[CALC_J_3:%.+]] = add i32 2, [[CALC_J_2_MUL1]]
// CHECK-NEXT: store i32 [[CALC_J_3]], i32* [[LC_J:.+]]
-// CHECK: [[IV1_3:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_3:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_K_1:%.+]] = udiv i32 [[IV1_3]], 5
// CHECK-NEXT: [[CALC_K_2:%.+]] = urem i32 [[CALC_K_1]], 4
// CHECK-NEXT: [[CALC_K_2_MUL1:%.+]] = mul i32 [[CALC_K_2]], 1
// CHECK-NEXT: [[CALC_K_3:%.+]] = add i32 3, [[CALC_K_2_MUL1]]
// CHECK-NEXT: store i32 [[CALC_K_3]], i32* [[LC_K:.+]]
-// CHECK: [[IV1_4:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_4:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_L_1:%.+]] = urem i32 [[IV1_4]], 5
// CHECK-NEXT: [[CALC_L_1_MUL1:%.+]] = mul i32 [[CALC_L_1]], 1
// CHECK-NEXT: [[CALC_L_2:%.+]] = add i32 4, [[CALC_L_1_MUL1]]
@@ -570,12 +570,12 @@
// CHECK-NEXT: store i16 [[CALC_L_3]], i16* [[LC_L:.+]]
// ... loop body ...
// End of body: store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
float res = b[j] * c[k];
a[i] = res * d[l];
-// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add i32 [[IV2]], 1
-// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]]
// br label %{{[^,]+}}, !llvm.loop ![[COLL1_LOOP_ID]]
// CHECK: [[COLL1_END]]
}
@@ -621,8 +621,8 @@
//
#pragma omp for simd collapse(2) private(globalfloat, localint)
-// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[WIDE1_BODY:[^,]+]], label %[[WIDE1_END:[^,]+]]
for (i = 1; i < 3; i++) // 2 iterations
@@ -630,10 +630,10 @@
{
// CHECK: [[WIDE1_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i64, i64* [[OMP_IV]]
// Calculation of the loop counters values...
// CHECK: store i32 {{[^,]+}}, i32* [[LC_I:.+]]
-// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]
// CHECK: store i16 {{[^,]+}}, i16* [[LC_J:.+]]
// ... loop body ...
//
@@ -642,14 +642,14 @@
globalfloat = (float)j/i;
float res = b[j] * c[j];
// Store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
a[i] = res * d[i];
// Then there's a store into private var localint:
-// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]
localint = (int)j;
-// CHECK: [[IV2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i64, i64* [[OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add nsw i64 [[IV2]], 1
-// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]]
//
// br label %{{[^,]+}}, !llvm.loop ![[WIDE1_LOOP_ID]]
// CHECK: [[WIDE1_END]]
diff --git a/test/OpenMP/for_simd_collapse_messages.cpp b/test/OpenMP/for_simd_collapse_messages.cpp
index 7bb9b04..5c9d058 100644
--- a/test/OpenMP/for_simd_collapse_messages.cpp
+++ b/test/OpenMP/for_simd_collapse_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp for simd collapse (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp for simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for simd', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp for simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd collapse (1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for simd'}}
@@ -63,7 +63,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/for_simd_firstprivate_messages.cpp b/test/OpenMP/for_simd_firstprivate_messages.cpp
index d3232ea..cb74ee0 100644
--- a/test/OpenMP/for_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/for_simd_firstprivate_messages.cpp
@@ -122,7 +122,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
-#pragma omp for simd firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (int k = 0; k < argc; ++k) {
i = k;
v += i;
@@ -286,7 +286,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
-#pragma omp for simd firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp for simd firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (int k = 0; k < argc; ++k) {
i = k;
v += i;
diff --git a/test/OpenMP/for_simd_loop_messages.cpp b/test/OpenMP/for_simd_loop_messages.cpp
index d336888..afd7b0b 100644
--- a/test/OpenMP/for_simd_loop_messages.cpp
+++ b/test/OpenMP/for_simd_loop_messages.cpp
@@ -10,6 +10,7 @@
};
static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
#pragma omp threadprivate(sii)
static int globalii;
@@ -306,6 +307,7 @@
#pragma omp parallel
{
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for simd' directive may not be threadprivate or thread local, predetermined as linear}}
#pragma omp for simd
for (sii = 0; sii < 10; sii += 1)
c[sii] = a[sii];
@@ -717,10 +719,18 @@
void test_ordered() {
#pragma omp parallel
-// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp for simd'}}
#pragma omp for simd ordered ordered // expected-error {{directive '#pragma omp for simd' cannot contain more than one 'ordered' clause}}
for (int i = 0; i < 16; ++i)
;
+#pragma omp parallel
+#pragma omp for simd ordered
+ for (int i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp for simd' directive}}
+#pragma omp for simd ordered(1)
+ for (int i = 0; i < 16; ++i)
+ ;
}
void test_nowait() {
diff --git a/test/OpenMP/for_simd_misc_messages.c b/test/OpenMP/for_simd_misc_messages.c
index 77af54d..ca1e366 100644
--- a/test/OpenMP/for_simd_misc_messages.c
+++ b/test/OpenMP/for_simd_misc_messages.c
@@ -153,15 +153,15 @@
#pragma omp for simd safelen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp for simd safelen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp for simd safelen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp for simd safelen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -238,15 +238,15 @@
#pragma omp for simd simdlen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp for simd simdlen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp for simd simdlen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp for simd simdlen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -356,17 +356,17 @@
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for simd collapse(-5)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for simd collapse(0)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp for simd collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -375,7 +375,7 @@
for (i = 0; i < 16; ++i)
// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}}
for (int j = 0; j < 16; ++j)
-// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+2 {{reduction variable must be shared}}
// expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}}
#pragma omp for simd reduction(+ : i, j)
for (int k = 0; k < 16; ++k)
diff --git a/test/OpenMP/for_simd_reduction_messages.cpp b/test/OpenMP/for_simd_reduction_messages.cpp
index efa97c5..000960f 100644
--- a/test/OpenMP/for_simd_reduction_messages.cpp
+++ b/test/OpenMP/for_simd_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s
void foo() {
}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
diff --git a/test/OpenMP/for_simd_safelen_messages.cpp b/test/OpenMP/for_simd_safelen_messages.cpp
index 27a87b5..d70e901 100644
--- a/test/OpenMP/for_simd_safelen_messages.cpp
+++ b/test/OpenMP/for_simd_safelen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp for simd safelen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp for simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp for simd safelen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp for simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+2 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd safelen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+1 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp for simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/for_simd_schedule_messages.cpp b/test/OpenMP/for_simd_schedule_messages.cpp
index 740b40b..76ba3a4 100644
--- a/test/OpenMP/for_simd_schedule_messages.cpp
+++ b/test/OpenMP/for_simd_schedule_messages.cpp
@@ -13,13 +13,13 @@
T tmain(T argc, S **argv) {
#pragma omp for simd schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -28,7 +28,7 @@
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp for simd schedule (guided argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for simd schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
@@ -36,7 +36,7 @@
#pragma omp for simd schedule (guided, (ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for simd schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd schedule (static, S) // expected-error {{'S' does not refer to a value}}
@@ -46,7 +46,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd schedule (dynamic, 1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -54,13 +54,13 @@
int main(int argc, char **argv) {
#pragma omp for simd schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -73,7 +73,7 @@
#pragma omp for simd schedule (dynamic, foobool(1) > 0 ? 1 : 2)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp for simd schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd schedule (guided, S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/for_simd_simdlen_messages.cpp b/test/OpenMP/for_simd_simdlen_messages.cpp
index f705e22..c72e546 100644
--- a/test/OpenMP/for_simd_simdlen_messages.cpp
+++ b/test/OpenMP/for_simd_simdlen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp for simd simdlen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp for simd simdlen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd simdlen (1)) // expected-warning {{extra tokens at the end of '#pragma omp for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp for simd simdlen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp for simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+2 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for simd simdlen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp for simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a positive integer value}}
+ #pragma omp for simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+1 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp for simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for simd simdlen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/nesting_of_regions.cpp b/test/OpenMP/nesting_of_regions.cpp
index 8a3bacf..b2b87db 100644
--- a/test/OpenMP/nesting_of_regions.cpp
+++ b/test/OpenMP/nesting_of_regions.cpp
@@ -100,6 +100,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SIMD DIRECTIVE
#pragma omp simd
@@ -227,6 +239,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// FOR DIRECTIVE
#pragma omp for
@@ -377,6 +401,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// FOR SIMD DIRECTIVE
#pragma omp for simd
@@ -504,6 +540,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// SECTIONS DIRECTIVE
#pragma omp sections
@@ -661,6 +709,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp sections
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SECTION DIRECTIVE
#pragma omp section // expected-error {{orphaned 'omp section' directives are prohibited, it must be closely nested to a sections region}}
@@ -854,6 +914,20 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SINGLE DIRECTIVE
#pragma omp single
@@ -994,6 +1068,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp single
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// MASTER DIRECTIVE
#pragma omp master
@@ -1134,6 +1220,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp master
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// CRITICAL DIRECTIVE
#pragma omp critical
@@ -1288,6 +1386,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp critical
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// PARALLEL FOR DIRECTIVE
#pragma omp parallel for
@@ -1443,6 +1553,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// PARALLEL FOR SIMD DIRECTIVE
#pragma omp parallel for simd
@@ -1598,6 +1720,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// PARALLEL SECTIONS DIRECTIVE
#pragma omp parallel sections
@@ -1744,6 +1878,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel sections
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TASK DIRECTIVE
#pragma omp task
@@ -1836,6 +1982,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp task
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// ORDERED DIRECTIVE
#pragma omp ordered
@@ -1902,7 +2060,7 @@
}
#pragma omp ordered
{
-#pragma omp parallel for simd ordered //expected-error {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
+#pragma omp parallel for simd ordered
for (int j = 0; j < 10; ++j) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
@@ -1912,6 +2070,16 @@
}
#pragma omp ordered
{
+#pragma omp parallel for simd ordered
+ for (int j = 0; j < 10; ++j) {
+#pragma omp ordered simd
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp ordered
+ {
#pragma omp parallel for
for (int i = 0; i < 10; ++i)
;
@@ -1976,6 +2144,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp ordered
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp ordered
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'ordered' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// ATOMIC DIRECTIVE
#pragma omp atomic
@@ -2145,6 +2325,22 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
++a;
}
+#pragma omp atomic
+ // expected-error@+2 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+2 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TARGET DIRECTIVE
#pragma omp target
@@ -2250,6 +2446,18 @@
#pragma omp teams // expected-note {{nested teams construct here}}
++a;
}
+#pragma omp target
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'target' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TEAMS DIRECTIVE
#pragma omp target
@@ -2370,6 +2578,365 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskloop // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskloop' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp distribute
+ for (int j = 0; j < 10; ++j)
+ ;
+
+// TASKLOOP DIRECTIVE
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a taskloop region}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master // expected-error {{region cannot be closely nested inside 'taskloop' region}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ {
+#pragma omp single // OK
+ {
+ bar();
+ }
+#pragma omp for // OK
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp sections // OK
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{region cannot be closely nested inside 'taskloop' region}}
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+// DISTRIBUTE DIRECTIVE
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a distribute region}}
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ {
+#pragma omp single
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
}
void foo() {
@@ -2469,6 +3036,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SIMD DIRECTIVE
#pragma omp simd
@@ -2589,6 +3168,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// FOR DIRECTIVE
#pragma omp for
@@ -2729,6 +3320,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// FOR SIMD DIRECTIVE
#pragma omp for simd
@@ -2849,6 +3452,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// SECTIONS DIRECTIVE
#pragma omp sections
@@ -2981,6 +3596,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp sections
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp sections
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'sections' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SECTION DIRECTIVE
#pragma omp section // expected-error {{orphaned 'omp section' directives are prohibited, it must be closely nested to a sections region}}
@@ -3180,6 +3807,22 @@
++a;
}
}
+#pragma omp sections
+ {
+#pragma omp section
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+ }
+#pragma omp sections
+ {
+#pragma omp section
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'section' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// SINGLE DIRECTIVE
#pragma omp single
@@ -3310,6 +3953,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp single
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp single
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'single' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// MASTER DIRECTIVE
#pragma omp master
@@ -3450,6 +4105,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp master
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp master
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'master' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// CRITICAL DIRECTIVE
#pragma omp critical
@@ -3609,6 +4276,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp critical
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp critical
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'critical' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// PARALLEL FOR DIRECTIVE
#pragma omp parallel for
@@ -3764,6 +4443,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// PARALLEL FOR SIMD DIRECTIVE
#pragma omp parallel for simd
@@ -3919,6 +4610,18 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside a simd region}}
++a;
}
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ for (int j = 0; j < 10; ++j)
+ ;
+ }
// PARALLEL SECTIONS DIRECTIVE
#pragma omp parallel sections
@@ -4061,6 +4764,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp parallel sections
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp parallel sections
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'parallel sections' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TASK DIRECTIVE
#pragma omp task
@@ -4152,6 +4867,18 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp task
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp task
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'task' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// ATOMIC DIRECTIVE
#pragma omp atomic
@@ -4321,6 +5048,22 @@
#pragma omp teams // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
++a;
}
+#pragma omp atomic
+ // expected-error@+2 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ {
+#pragma omp taskloop // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp atomic
+ // expected-error@+2 {{the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected an expression statement}}
+ {
+#pragma omp distribute // expected-error {{OpenMP constructs may not be nested inside an atomic region}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TARGET DIRECTIVE
#pragma omp target
@@ -4426,6 +5169,18 @@
#pragma omp teams // expected-note {{nested teams construct here}}
++a;
}
+#pragma omp target
+ {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp target
+ {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'target' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
// TEAMS DIRECTIVE
#pragma omp target
@@ -4546,6 +5301,366 @@
#pragma omp teams // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
++a;
}
+#pragma omp target
+#pragma omp teams
+ {
+#pragma omp taskloop // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp taskloop' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp distribute
+ for (int j = 0; j < 10; ++j)
+ ;
+
+// TASKLOOP DIRECTIVE
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp for simd' directive into a parallel region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp sections' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a taskloop region}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}}
+ {
+ bar();
+ }
+ }
+
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master // expected-error {{region cannot be closely nested inside 'taskloop' region}}
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ {
+#pragma omp single // OK
+ {
+ bar();
+ }
+#pragma omp for // OK
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp sections // OK
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task
+ {
+ bar();
+ }
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier // expected-error {{region cannot be closely nested inside 'taskloop' region}}
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+
+// DISTRIBUTE DIRECTIVE
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp distribute // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp distribute' directive into a teams region?}}
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp sections
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp section // expected-error {{'omp section' directive must be closely nested to a sections region, not a distribute region}}
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp single
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp master
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp critical
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel
+ {
+#pragma omp single
+ {
+ bar();
+ }
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel for simd
+ for (int i = 0; i < 10; ++i)
+ ;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp parallel sections
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp task
+ {
+ bar();
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskyield
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp barrier
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp taskwait
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp flush
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp ordered // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp ordered' directive into a for or a parallel for region with 'ordered' clause?}}
+ bar();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp atomic
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp target
+ ++a;
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute
+ for (int i = 0; i < 10; ++i) {
+#pragma omp teams // expected-error {{region cannot be closely nested inside 'distribute' region; perhaps you forget to enclose 'omp teams' directive into a target region?}}
+ ++a;
+ }
return foo<int>();
}
diff --git a/test/OpenMP/ordered_ast_print.cpp b/test/OpenMP/ordered_ast_print.cpp
index 6328ec0..97fe700 100644
--- a/test/OpenMP/ordered_ast_print.cpp
+++ b/test/OpenMP/ordered_ast_print.cpp
@@ -8,7 +8,7 @@
void foo() {}
-template <class T>
+template <class T, int N>
T tmain (T argc) {
T b = argc, c, d, e, f, g;
static T a;
@@ -42,6 +42,12 @@
{
a=2;
}
+ #pragma omp parallel for ordered(1)
+ for (int i =0 ; i < argc; ++i) {
+ #pragma omp ordered depend(source)
+ #pragma omp ordered depend(sink:i+N)
+ a = 2;
+ }
return (0);
}
@@ -76,7 +82,12 @@
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
-
+// CHECK-NEXT: #pragma omp parallel for ordered(1)
+// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
+// CHECK-NEXT: #pragma omp ordered depend(source)
+// CHECK-NEXT: #pragma omp ordered depend(sink : i + 3)
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
// CHECK: static T a;
// CHECK-NEXT: #pragma omp for ordered
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
@@ -108,7 +119,14 @@
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp parallel for ordered(1)
+// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
+// CHECK-NEXT: #pragma omp ordered depend(source)
+// CHECK-NEXT: #pragma omp ordered depend(sink : i + N)
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
+// CHECK-LABEL: int main(
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
@@ -143,6 +161,12 @@
{
a=2;
}
+ #pragma omp parallel for ordered(1)
+ for (int i =0 ; i < argc; ++i) {
+ #pragma omp ordered depend(source)
+ #pragma omp ordered depend(sink: i - 5)
+ a = 2;
+ }
// CHECK-NEXT: #pragma omp for ordered
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered
@@ -173,7 +197,13 @@
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
- return tmain(argc);
+// CHECK-NEXT: #pragma omp parallel for ordered(1)
+// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
+// CHECK-NEXT: #pragma omp ordered depend(source)
+// CHECK-NEXT: #pragma omp ordered depend(sink : i - 5)
+// CHECK-NEXT: a = 2;
+// CHECK-NEXT: }
+ return tmain<int, 3>(argc);
}
#endif
diff --git a/test/OpenMP/ordered_codegen.cpp b/test/OpenMP/ordered_codegen.cpp
index e77c1be..daa6211 100644
--- a/test/OpenMP/ordered_codegen.cpp
+++ b/test/OpenMP/ordered_codegen.cpp
@@ -224,6 +224,14 @@
#pragma omp ordered simd
f[i] = 1.0;
}
+ // CHECK: store float 0.000000e+00, float* %{{.+}}, align {{[0-9]+}}
+ // CHECK-NEXT: call void [[CAP_FUNC:@.+]](i32* %{{.+}}) #{{[0-9]+}}
+#pragma omp for simd ordered
+ for (int i = low; i < up; ++i) {
+ f[i] = 0.0;
+#pragma omp ordered simd
+ f[i] = 1.0;
+ }
}
// CHECK: define internal void [[CAP_FUNC]](i32* dereferenceable({{[0-9]+}}) %{{.+}}) #
diff --git a/test/OpenMP/ordered_messages.cpp b/test/OpenMP/ordered_messages.cpp
index 559a6b0..36f9bb2 100644
--- a/test/OpenMP/ordered_messages.cpp
+++ b/test/OpenMP/ordered_messages.cpp
@@ -4,6 +4,7 @@
template <class T>
T foo() {
+ T k;
#pragma omp for ordered
for (int i = 0; i < 10; ++i) {
L1:
@@ -90,12 +91,49 @@
{
foo();
}
+ #pragma omp ordered depend(source) // expected-error {{OpenMP constructs may not be nested inside a simd region}}
}
-
+#pragma omp parallel for ordered
+ for (int i = 0; i < 10; ++i) {
+ #pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
+ #pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
+ }
+#pragma omp parallel for ordered(2) // expected-note 5 {{'ordered' clause with specified parameter}}
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 10; ++j) {
+#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
+#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp ordered depend(sink // expected-error {{expected expression}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-error {{expected ')'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-note {{to match this '('}}
+#pragma omp ordered depend(sink : // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend(sink : i // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(sink : i) // expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(source)
+ if (i == j)
+#pragma omp ordered depend(source) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
+ ;
+ if (i == j)
+#pragma omp ordered depend(sink : i, j) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
+ ;
+#pragma omp ordered depend(source) threads // expected-error {{'depend' clauses cannot be mixed with 'threads' clause}}
+#pragma omp ordered simd depend(source) // expected-error {{'depend' clauses cannot be mixed with 'simd' clause}}
+#pragma omp ordered depend(source) depend(source) // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'depend' clause with 'source' dependence}}
+#pragma omp ordered depend(in : i) // expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend(sink : i, j)
+#pragma omp ordered depend(sink : j, i) // expected-error {{expected 'i' loop iteration variable}} expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(sink : i, j, k) // expected-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
+#pragma omp ordered depend(sink : i+foo(), j/4) // expected-error {{expression is not an integral constant expression}} expected-error {{expected '+' or '-' operation}}
+#pragma omp ordered depend(sink : i*0, j-4)// expected-error {{expected '+' or '-' operation}}
+#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(sink : i-0, j+sizeof(T))
+#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
+#pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(T)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}}
+ }
+ }
return T();
}
int foo() {
+int k;
#pragma omp for ordered
for (int i = 0; i < 10; ++i) {
L1:
@@ -182,7 +220,44 @@
{
foo();
}
+ #pragma omp ordered depend(source) // expected-error {{OpenMP constructs may not be nested inside a simd region}}
+ }
+#pragma omp parallel for ordered
+ for (int i = 0; i < 10; ++i) {
+ #pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
+ #pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
+ }
+#pragma omp parallel for ordered(2) // expected-note 5 {{'ordered' clause with specified parameter}}
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 10; ++j) {
+#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
+#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp ordered depend(sink // expected-error {{expected expression}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-error {{expected ')'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-note {{to match this '('}}
+#pragma omp ordered depend(sink : // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend(sink : i // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(sink : i) // expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(source)
+ if (i == j)
+#pragma omp ordered depend(source) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
+ ;
+ if (i == j)
+#pragma omp ordered depend(sink : i, j) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
+ ;
+#pragma omp ordered depend(source) threads // expected-error {{'depend' clauses cannot be mixed with 'threads' clause}}
+#pragma omp ordered simd depend(source) // expected-error {{'depend' clauses cannot be mixed with 'simd' clause}}
+#pragma omp ordered depend(source) depend(source) // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'depend' clause with 'source' dependence}}
+#pragma omp ordered depend(in : i) // expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
+#pragma omp ordered depend(sink : i, j)
+#pragma omp ordered depend(sink : j, i) // expected-error {{expected 'i' loop iteration variable}} expected-error {{expected 'j' loop iteration variable}}
+#pragma omp ordered depend(sink : i, j, k) // expected-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
+#pragma omp ordered depend(sink : i+foo(), j/4) // expected-error {{expression is not an integral constant expression}} expected-error {{expected '+' or '-' operation}}
+#pragma omp ordered depend(sink : i*0, j-4)// expected-error {{expected '+' or '-' operation}}
+#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(sink : i-0, j+sizeof(int))
+#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
+#pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(int)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}}
+ }
}
- return foo<int>();
+ return foo<int>(); // expected-note {{in instantiation of function template specialization 'foo<int>' requested here}}
}
diff --git a/test/OpenMP/parallel_ast_print.cpp b/test/OpenMP/parallel_ast_print.cpp
index 0f789db..1e46fba 100644
--- a/test/OpenMP/parallel_ast_print.cpp
+++ b/test/OpenMP/parallel_ast_print.cpp
@@ -102,4 +102,22 @@
return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
}
+template <class T>
+struct Foo {
+ int foo;
+};
+
+void foo(const Foo<int> &arg) {
+// CHECK: #pragma omp parallel
+#pragma omp parallel
+ {
+// CHECK: #pragma omp for schedule(static)
+#pragma omp for schedule(static)
+ for (int idx = 0; idx < 1234; ++idx) {
+ //arg.foo = idx;
+ idx = arg.foo;
+ }
+ }
+}
+
#endif
diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp
index 0a09bad..04c5c2c 100644
--- a/test/OpenMP/parallel_codegen.cpp
+++ b/test/OpenMP/parallel_codegen.cpp
@@ -57,7 +57,6 @@
// CHECK: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_ADDR]]
// CHECK-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]]
// CHECK-NEXT: invoke {{.*}}void [[FOO:@.+foo.+]](i32{{[ ]?[a-z]*}} [[ARGC]])
-// CHECK: call {{.+}} @__kmpc_barrier(
// CHECK: ret void
// CHECK: call {{.*}}void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
@@ -68,7 +67,6 @@
// CHECK-DEBUG: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_ADDR]]
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO:@.+foo.+]](i32 [[ARGC]])
-// CHECK-DEBUG: call {{.+}} @__kmpc_barrier(
// CHECK-DEBUG: ret void
// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
@@ -101,7 +99,6 @@
// CHECK: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_ADDR]]
// CHECK-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]]
// CHECK-NEXT: invoke {{.*}}void [[FOO1:@.+foo.+]](i8** [[ARGC]])
-// CHECK: call {{.+}} @__kmpc_barrier(
// CHECK: ret void
// CHECK: call {{.*}}void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
@@ -111,7 +108,6 @@
// CHECK-DEBUG: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_ADDR]]
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
-// CHECK-DEBUG: call {{.+}} @__kmpc_barrier(
// CHECK-DEBUG: ret void
// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
diff --git a/test/OpenMP/parallel_copyin_codegen.cpp b/test/OpenMP/parallel_copyin_codegen.cpp
index 9a7449d..ff76cfe 100644
--- a/test/OpenMP/parallel_copyin_codegen.cpp
+++ b/test/OpenMP/parallel_copyin_codegen.cpp
@@ -11,7 +11,6 @@
// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=TLS-LAMBDA %s
// RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=TLS-BLOCKS %s
// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=TLS-ARRAY %s
-// REQUIRES: tls
// expected-no-diagnostics
#ifndef ARRAY
#ifndef HEADER
@@ -85,10 +84,10 @@
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
// LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}})
- // TLS-LAMBDA: [[G_CPY_VAL:%.+]] = call i{{[0-9]+}}* [[G_CTOR:@.+]]()
+ // TLS-LAMBDA: [[G_CPY_VAL:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR:@.+]]()
// TLS-LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* [[G_CPY_VAL]])
- // TLS-LAMBDA: define {{.*}}i{{[0-9]+}}* [[G_CTOR]]() {
+ // TLS-LAMBDA: define {{.*}}i{{[0-9]+}}* [[G_CTOR]]()
// TLS-LAMBDA: ret i{{[0-9]+}}* [[G]]
// TLS-LAMBDA: }
@@ -108,7 +107,7 @@
// LAMBDA: [[DONE]]
// TLS-LAMBDA-DAG: [[G_CAPTURE_SRC:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %
- // TLS-LAMBDA-DAG: [[G_CAPTURE_DST:%.+]] = call i{{[0-9]+}}* [[G_CTOR]]()
+ // TLS-LAMBDA-DAG: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
// TLS-LAMBDA-DAG: [[G_CAPTURE_SRCC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_SRC]] to i{{[0-9]+}}
// TLS-LAMBDA-DAG: [[G_CAPTURE_DSTC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_DST]] to i{{[0-9]+}}
// TLS-LAMBDA: icmp ne i{{[0-9]+}} {{%.+}}, {{%.+}}
@@ -129,7 +128,7 @@
g = 2;
// LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
- // TLS-LAMBDA: [[G_CAPTURE_DST:%.+]] = call i{{[0-9]+}}* [[G_CTOR]]()
+ // TLS-LAMBDA: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
// TLS-LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_CAPTURE_DST]], align 128
}();
}
@@ -147,10 +146,10 @@
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
// BLOCKS: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}})
- // TLS-BLOCKS: [[G_CPY_VAL:%.+]] = call i{{[0-9]+}}* [[G_CTOR:@.+]]()
+ // TLS-BLOCKS: [[G_CPY_VAL:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR:@.+]]()
// TLS-BLOCKS: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* [[G_CPY_VAL]])
- // TLS-BLOCKS: define {{.*}}i{{[0-9]+}}* [[G_CTOR]]() {
+ // TLS-BLOCKS: define {{.*}}i{{[0-9]+}}* [[G_CTOR]]()
// TLS-BLOCKS: ret i{{[0-9]+}}* [[G]]
// TLS-BLOCKS: }
#pragma omp parallel copyin(g)
@@ -169,7 +168,7 @@
// BLOCKS: [[DONE]]
// TLS-BLOCKS-DAG: [[G_CAPTURE_SRC:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %
- // TLS-BLOCKS-DAG: [[G_CAPTURE_DST:%.+]] = call i{{[0-9]+}}* [[G_CTOR]]()
+ // TLS-BLOCKS-DAG: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
// TLS-BLOCKS-DAG: [[G_CAPTURE_SRCC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_SRC]] to i{{[0-9]+}}
// TLS-BLOCKS-DAG: [[G_CAPTURE_DSTC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_DST]] to i{{[0-9]+}}
// TLS-BLOCKS: icmp ne i{{[0-9]+}} {{%.+}}, {{%.+}}
@@ -186,7 +185,7 @@
// BLOCKS-NOT: [[G]]{{[[^:word:]]}}
// BLOCKS: call {{.*}}void {{%.+}}(i8
- // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call i{{[0-9]+}}* [[G_CTOR]]()
+ // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
// TLS-BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_CAPTURE_DST]]
// TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
// TLS-BLOCKS: call {{.*}}void {{%.+}}(i8
@@ -201,7 +200,7 @@
// BLOCKS: ret
// TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
- // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call i{{[0-9]+}}* [[G_CTOR]]()
+ // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
// TLS-BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_CAPTURE_DST]]
// TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
// TLS-BLOCKS: ret
diff --git a/test/OpenMP/parallel_firstprivate_codegen.cpp b/test/OpenMP/parallel_firstprivate_codegen.cpp
index e44c64b..d0da8ce 100644
--- a/test/OpenMP/parallel_firstprivate_codegen.cpp
+++ b/test/OpenMP/parallel_firstprivate_codegen.cpp
@@ -204,9 +204,6 @@
// CHECK: store i{{[0-9]+}} [[SIVAR_REF_ADDR]], i{{[0-9]+}}* [[SIVAR7_PRIV]],
// CHECK: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[SIVAR7_PRIV]],
-// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
-// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call {{.*}}void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
// CHECK: ret void
diff --git a/test/OpenMP/parallel_for_ast_print.cpp b/test/OpenMP/parallel_for_ast_print.cpp
index 197cd0f..c4be521 100644
--- a/test/OpenMP/parallel_for_ast_print.cpp
+++ b/test/OpenMP/parallel_for_ast_print.cpp
@@ -21,7 +21,7 @@
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
-#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) if (parallel :argc) num_threads(N) default(shared) shared(e) reduction(+ : h) linear(a:N)
+#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) if (parallel :argc) num_threads(N) default(shared) shared(e) reduction(+ : h)
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int j = 0; j < 2; ++j)
@@ -33,7 +33,7 @@
for (int j = 0; j < 2; ++j)
for (int j = 0; j < 2; ++j)
foo();
- // CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) if(parallel: argc) num_threads(N) default(shared) shared(e) reduction(+: h) linear(a: N)
+ // CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) if(parallel: argc) num_threads(N) default(shared) shared(e) reduction(+: h)
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
diff --git a/test/OpenMP/parallel_for_codegen.cpp b/test/OpenMP/parallel_for_codegen.cpp
index bf6a6bf..036fa37 100644
--- a/test/OpenMP/parallel_for_codegen.cpp
+++ b/test/OpenMP/parallel_for_codegen.cpp
@@ -22,7 +22,6 @@
// CHECK: [[CHUNK_SIZE:%.+]] = sext i8 [[CHUNK_VAL]] to i64
// CHECK: call void @__kmpc_for_static_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC:@[^,]+]], i32 [[GTID:%[^,]+]], i32 33, i32* [[IS_LAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]], i64 1, i64 [[CHUNK_SIZE]])
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: __kmpc_barrier
#pragma omp parallel for schedule(static, char(a))
for (unsigned long long i = 1; i < 2; ++i) {
}
@@ -68,7 +67,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -112,7 +110,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -175,7 +172,6 @@
// CHECK: [[O_LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -220,7 +216,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -265,7 +260,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -315,9 +309,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -362,9 +353,6 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
// CHECK: ret void
}
@@ -382,21 +370,18 @@
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
// TERM_DEBUG-NOT: __kmpc_global_thread_num
// TERM_DEBUG: call void @__kmpc_for_static_fini({{.+}}), !dbg [[DBG_LOC_END:![0-9]+]]
- // TERM_DEBUG: call {{.+}} @__kmpc_barrier({{.+}}), !dbg [[DBG_LOC_CANCEL:![0-9]+]]
// TERM_DEBUG: [[TERM_LPAD]]
// TERM_DEBUG: call void @__clang_call_terminate
// TERM_DEBUG: unreachable
// CLEANUP-NOT: __kmpc_global_thread_num
// CLEANUP: call void @__kmpc_for_static_init_4u({{.+}})
// CLEANUP: call void @__kmpc_for_static_fini({{.+}})
- // CLEANUP: call {{.+}} @__kmpc_barrier({{.+}})
for (unsigned i = 131071; i <= 2147483647; i += 127)
a[i] += foo() + arr[i];
}
// Check source line corresponds to "#pragma omp parallel for schedule(static, 5)" above:
// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !DILocation(line: [[@LINE-4]],
-// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !DILocation(line: [[@LINE-20]],
-// TERM_DEBUG-DAG: [[DBG_LOC_CANCEL]] = !DILocation(line: [[@LINE-21]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !DILocation(line: [[@LINE-18]],
#endif // HEADER
diff --git a/test/OpenMP/parallel_for_collapse_messages.cpp b/test/OpenMP/parallel_for_collapse_messages.cpp
index 042b819..6e5f71f 100644
--- a/test/OpenMP/parallel_for_collapse_messages.cpp
+++ b/test/OpenMP/parallel_for_collapse_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp parallel for collapse (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp parallel for collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp parallel for' cannot contain more than one 'collapse' clause}}
- // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for collapse (1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp parallel for collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for collapse (2) // expected-note {{as specified in 'collapse' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for'}}
@@ -63,7 +63,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'collapse' clause}}
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for collapse (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_for_lastprivate_messages.cpp b/test/OpenMP/parallel_for_lastprivate_messages.cpp
index 6eb60b3..ccfe2ea 100644
--- a/test/OpenMP/parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_lastprivate_messages.cpp
@@ -17,7 +17,7 @@
S2(S2 &s2) : a(s2.a) {}
S2 &operator=(const S2 &);
const S2 &operator=(const S2 &) const;
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
@@ -188,7 +188,7 @@
#pragma omp parallel for lastprivate(xa) // OK
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for lastprivate(S2::S2s)
+#pragma omp parallel for lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
diff --git a/test/OpenMP/parallel_for_linear_codegen.cpp b/test/OpenMP/parallel_for_linear_codegen.cpp
index d980dd3..940d603 100644
--- a/test/OpenMP/parallel_for_linear_codegen.cpp
+++ b/test/OpenMP/parallel_for_linear_codegen.cpp
@@ -24,7 +24,6 @@
// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK: [[S_INT_TY:%.+]] = type { i32 }
-// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-DAG: [[F:@.+]] = global float 0.0
// CHECK-DAG: [[CNT:@.+]] = global i8 0
template <typename T>
@@ -75,7 +74,6 @@
// LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
// LAMBDA: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
g += 5;
- // LAMBDA: call void @__kmpc_barrier(%{{.+}}* @{{.+}}, i{{[0-9]+}} [[GTID]])
[&]() {
// LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
// LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
@@ -124,7 +122,6 @@
// BLOCKS: call void {{%.+}}(i8
// BLOCKS: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
g += 5;
- // BLOCKS: call void @__kmpc_barrier(%{{.+}}* @{{.+}}, i{{[0-9]+}} [[GTID]])
g = 1;
^{
// BLOCKS: define {{.+}} void {{@.+}}(i8*
@@ -198,7 +195,6 @@
// CHECK: [[ADD:%.+]] = add nsw i64 [[LVAR_VAL]], 3
// CHECK: store i64 [[ADD]], i64* [[LVAR_PRIV]],
// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
@@ -248,7 +244,6 @@
// CHECK: [[ADD:%.+]] = add nsw i32 [[LVAR_VAL]], 1
// CHECK: store i32 [[ADD]], i32* [[LVAR_PRIV]],
// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
#endif
diff --git a/test/OpenMP/parallel_for_loop_messages.cpp b/test/OpenMP/parallel_for_loop_messages.cpp
index 2a65d78..2bb32bd 100644
--- a/test/OpenMP/parallel_for_loop_messages.cpp
+++ b/test/OpenMP/parallel_for_loop_messages.cpp
@@ -10,6 +10,7 @@
};
static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
#pragma omp threadprivate(sii)
static int globalii;
@@ -257,6 +258,7 @@
c[ii] = a[ii];
{
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be threadprivate or thread local, predetermined as private}}
#pragma omp parallel for
for (sii = 0; sii < 10; sii += 1)
c[sii] = a[sii];
diff --git a/test/OpenMP/parallel_for_misc_messages.c b/test/OpenMP/parallel_for_misc_messages.c
index 819f571..1a773be 100644
--- a/test/OpenMP/parallel_for_misc_messages.c
+++ b/test/OpenMP/parallel_for_misc_messages.c
@@ -148,15 +148,15 @@
#pragma omp parallel for collapse(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for collapse(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for collapse(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -165,8 +165,7 @@
for (i = 0; i < 16; ++i)
// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
for (int j = 0; j < 16; ++j)
-// expected-error@+3 {{reduction variable must be shared}}
-// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+2 2 {{reduction variable must be shared}}
// expected-error@+1 {{region cannot be closely nested inside 'parallel for' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}}
#pragma omp for reduction(+ : i, j)
for (int k = 0; k < 16; ++k)
diff --git a/test/OpenMP/parallel_for_num_threads_messages.cpp b/test/OpenMP/parallel_for_num_threads_messages.cpp
index 60c7dfb..10a4e1b 100644
--- a/test/OpenMP/parallel_for_num_threads_messages.cpp
+++ b/test/OpenMP/parallel_for_num_threads_messages.cpp
@@ -24,7 +24,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (S) // expected-error {{'S' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
@@ -32,7 +32,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (argc)
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for num_threads (N) // expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
return argc;
@@ -52,7 +52,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/parallel_for_ordered_messages.cpp b/test/OpenMP/parallel_for_ordered_messages.cpp
index 4a8d378..3729eb9 100644
--- a/test/OpenMP/parallel_for_ordered_messages.cpp
+++ b/test/OpenMP/parallel_for_ordered_messages.cpp
@@ -26,7 +26,7 @@
#pragma omp parallel for ordered(argc
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
#pragma omp parallel for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
@@ -37,7 +37,7 @@
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
-// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+2 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = ST; i < N; i++)
@@ -52,7 +52,7 @@
#pragma omp parallel for ordered(1)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-#pragma omp parallel for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
+#pragma omp parallel for ordered(N) // expected-error {{argument to 'ordered' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(2) // expected-note {{as specified in 'ordered' clause}}
@@ -81,7 +81,7 @@
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
-// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
+// expected-error@+1 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
diff --git a/test/OpenMP/parallel_for_reduction_messages.cpp b/test/OpenMP/parallel_for_reduction_messages.cpp
index 74808fc..22251b4 100644
--- a/test/OpenMP/parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s
void foo() {
}
@@ -16,7 +18,7 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
- static float S2s;
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
@@ -136,7 +141,7 @@
#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(&& : S2::S2s)
+#pragma omp parallel for reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
@@ -258,7 +263,7 @@
#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(&& : S2::S2s)
+#pragma omp parallel for reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
diff --git a/test/OpenMP/parallel_for_schedule_messages.cpp b/test/OpenMP/parallel_for_schedule_messages.cpp
index 5ed6dc8..f446609 100644
--- a/test/OpenMP/parallel_for_schedule_messages.cpp
+++ b/test/OpenMP/parallel_for_schedule_messages.cpp
@@ -13,13 +13,13 @@
T tmain(T argc, S **argv) {
#pragma omp parallel for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp parallel for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -28,7 +28,7 @@
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp parallel for schedule (guided argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}}
@@ -36,7 +36,7 @@
#pragma omp parallel for schedule (guided, (ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for schedule (static, S) // expected-error {{'S' does not refer to a value}}
@@ -46,7 +46,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for schedule (dynamic, 1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp parallel for schedule (static, N) // expected-error {{argument to 'schedule' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -54,13 +54,13 @@
int main(int argc, char **argv) {
#pragma omp parallel for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp parallel for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -73,7 +73,7 @@
#pragma omp parallel for schedule (dynamic, foobool(1) > 0 ? 1 : 2)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for schedule (guided, S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_for_simd_aligned_messages.cpp b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
index e1b9602..8bffd21 100644
--- a/test/OpenMP/parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
@@ -50,7 +50,7 @@
T sum = (T)0;
T ind2 = - num * L;
// Negative number is passed as L.
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp parallel for simd aligned(arr:L)
for (i = 0; i < num; ++i) {
T cur = arr[(int)ind2];
@@ -65,7 +65,7 @@
template<int LEN> int test_warn() {
int *ind2 = 0;
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp parallel for simd aligned(ind2:LEN)
for (int i = 0; i < 100; i++) {
ind2 += LEN;
diff --git a/test/OpenMP/parallel_for_simd_ast_print.cpp b/test/OpenMP/parallel_for_simd_ast_print.cpp
index e23c2cb..1b9415d 100644
--- a/test/OpenMP/parallel_for_simd_ast_print.cpp
+++ b/test/OpenMP/parallel_for_simd_ast_print.cpp
@@ -44,8 +44,8 @@
}
const T clen = 3;
// CHECK: T clen = 3;
- #pragma omp parallel for simd safelen(clen-1) simdlen(clen-1)
-// CHECK-NEXT: #pragma omp parallel for simd safelen(clen - 1) simdlen(clen - 1)
+ #pragma omp parallel for simd safelen(clen-1) simdlen(clen-1) ordered
+// CHECK-NEXT: #pragma omp parallel for simd safelen(clen - 1) simdlen(clen - 1) ordered
for(T i = clen+2; i < 20; ++i) {
// CHECK-NEXT: for (T i = clen + 2; i < 20; ++i) {
v[i] = v[v-clen] + 1;
@@ -92,8 +92,8 @@
int k1=0,k2=0;
static int *a;
// CHECK: static int *a;
-#pragma omp parallel for simd if(parallel :b)
-// CHECK-NEXT: #pragma omp parallel for simd if(parallel: b)
+#pragma omp parallel for simd if(parallel :b) ordered
+// CHECK-NEXT: #pragma omp parallel for simd if(parallel: b) ordered
for (int i=0; i < 2; ++i)*a=2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: *a = 2;
diff --git a/test/OpenMP/parallel_for_simd_codegen.cpp b/test/OpenMP/parallel_for_simd_codegen.cpp
index a39aabf..9a6ad2f 100644
--- a/test/OpenMP/parallel_for_simd_codegen.cpp
+++ b/test/OpenMP/parallel_for_simd_codegen.cpp
@@ -41,29 +41,28 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV:%[^,]+]],
-// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[SIMPLE_LOOP1_BODY:.+]], label %[[SIMPLE_LOOP1_END:[^,]+]]
for (int i = 3; i < 32; i += 5) {
// CHECK: [[SIMPLE_LOOP1_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 5
// CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 3, [[CALC_I_1]]
-// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
// ... loop body ...
// End of body: store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: store float [[RESULT:%.+]], float*
a[i] = b[i] * c[i] * d[i];
-// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
-// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP1_ID]]
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
// br label %{{.+}}, !llvm.loop !{{.+}}
}
// CHECK: [[SIMPLE_LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
long long k = get_val();
@@ -112,7 +111,6 @@
// CHECK: [[LIN0_2:%.+]] = load i64, i64* [[LIN0]]
// CHECK-NEXT: [[LIN_ADD2:%.+]] = add nsw i64 [[LIN0_2]], 27
// CHECK-NEXT: store i64 [[LIN_ADD2]], i64* %{{.+}}
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
int lin = 12;
#pragma omp parallel for simd linear(lin : get_val()), linear(g_ptr)
@@ -143,36 +141,36 @@
// CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]],
// CHECK: store i64 [[LB_VAL]], i64* [[OMP_IV3:%[^,]+]],
-// CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]]
+// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP3:%.+]] = icmp ule i64 [[IV3]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP3]], label %[[SIMPLE_LOOP3_BODY:.+]], label %[[SIMPLE_LOOP3_END:[^,]+]]
for (unsigned long long it = 2000; it >= 600; it-=400) {
// CHECK: [[SIMPLE_LOOP3_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV3_0:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[IV3_0:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul i64 [[IV3_0]], 400
// CHECK-NEXT: [[LC_IT_2:%.+]] = sub i64 2000, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}
//
// Linear start and step are used to calculate current value of the linear variable.
-// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]
+// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]
+// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]]
+// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]
+// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[MUL:%.+]] = mul i64 [[IV3_1]], 1
// CHECK: [[GEP:%.+]] = getelementptr{{.*}}[[GLINSTART]]
-// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]]
*g_ptr++ = 0.0;
-// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: store double{{.*}}[[GEP_VAL]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]]
+// CHECK: store double{{.*}}[[GEP_VAL]]
a[it + lin]++;
// CHECK: [[FLT_INC:%.+]] = fadd float
-// CHECK-NEXT: store float [[FLT_INC]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-// CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store float [[FLT_INC]],
+// CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]]
// CHECK-NEXT: [[ADD3_2:%.+]] = add i64 [[IV3_2]], 1
-// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]
}
// CHECK: [[SIMPLE_LOOP3_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -183,7 +181,6 @@
// CHECK: store i32 {{.+}}, i32* [[LIN_VAR]],
// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]
// CHECK: store double* {{.*}}[[GLIN_VAR]]
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
#pragma omp parallel for simd
// CHECK: call void @__kmpc_for_static_init_4(%ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1)
@@ -201,26 +198,25 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV4:%[^,]+]],
-// CHECK: [[IV4:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4:%.+]] = load i32, i32* [[OMP_IV4]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP4:%.+]] = icmp sle i32 [[IV4]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP4]], label %[[SIMPLE_LOOP4_BODY:.+]], label %[[SIMPLE_LOOP4_END:[^,]+]]
for (short it = 6; it <= 20; it-=-4) {
// CHECK: [[SIMPLE_LOOP4_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV4_0:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4_0:%.+]] = load i32, i32* [[OMP_IV4]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i32 [[IV4_0]], 4
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i32 6, [[LC_IT_1]]
// CHECK-NEXT: [[LC_IT_3:%.+]] = trunc i32 [[LC_IT_2]] to i16
-// CHECK-NEXT: store i16 [[LC_IT_3]], i16* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: store i16 [[LC_IT_3]], i16*
-// CHECK: [[IV4_2:%.+]] = load i32, i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK: [[IV4_2:%.+]] = load i32, i32* [[OMP_IV4]]
// CHECK-NEXT: [[ADD4_2:%.+]] = add nsw i32 [[IV4_2]], 1
-// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP4_ID]]
+// CHECK-NEXT: store i32 [[ADD4_2]], i32* [[OMP_IV4]]
}
// CHECK: [[SIMPLE_LOOP4_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
#pragma omp parallel for simd
// CHECK: call void @__kmpc_for_static_init_4(%ident_t* {{[^,]+}}, i32 %{{[^,]+}}, i32 34, i32* %{{[^,]+}}, i32* [[LB:%[^,]+]], i32* [[UB:%[^,]+]], i32* [[STRIDE:%[^,]+]], i32 1, i32 1)
@@ -238,26 +234,25 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[OMP_IV5:%[^,]+]],
-// CHECK: [[IV5:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5:%.+]] = load i32, i32* [[OMP_IV5]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP5:%.+]] = icmp sle i32 [[IV5]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP5]], label %[[SIMPLE_LOOP5_BODY:.+]], label %[[SIMPLE_LOOP5_END:[^,]+]]
for (unsigned char it = 'z'; it >= 'a'; it+=-1) {
// CHECK: [[SIMPLE_LOOP5_BODY]]
// Start of body: calculate it from IV:
-// CHECK: [[IV5_0:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5_0:%.+]] = load i32, i32* [[OMP_IV5]]
// CHECK-NEXT: [[IV5_1:%.+]] = mul nsw i32 [[IV5_0]], 1
// CHECK-NEXT: [[LC_IT_1:%.+]] = sub nsw i32 122, [[IV5_1]]
// CHECK-NEXT: [[LC_IT_2:%.+]] = trunc i32 [[LC_IT_1]] to i8
-// CHECK-NEXT: store i8 [[LC_IT_2]], i8* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: store i8 [[LC_IT_2]], i8* {{.+}},
-// CHECK: [[IV5_2:%.+]] = load i32, i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK: [[IV5_2:%.+]] = load i32, i32* [[OMP_IV5]]
// CHECK-NEXT: [[ADD5_2:%.+]] = add nsw i32 [[IV5_2]], 1
-// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP5_ID]]
+// CHECK-NEXT: store i32 [[ADD5_2]], i32* [[OMP_IV5]]
}
// CHECK: [[SIMPLE_LOOP5_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
// CHECK-NOT: mul i32 %{{.+}}, 10
#pragma omp parallel for simd
@@ -285,24 +280,24 @@
// CHECK: br label %[[SIMD_LOOP7_COND:[^,]+]]
// CHECK: [[SIMD_LOOP7_COND]]
-// CHECK-NEXT: [[IV7:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[IV7:%.+]] = load i64, i64* [[OMP_IV7]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP7:%.+]] = icmp sle i64 [[IV7]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP7]], label %[[SIMPLE_LOOP7_BODY:.+]], label %[[SIMPLE_LOOP7_END:[^,]+]]
for (long long i = -10; i < 10; i += 3) {
// CHECK: [[SIMPLE_LOOP7_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV7_0]], 3
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
-// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],
+// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]
// CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[LC_VAL]] to i32
-// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],
A = i;
-// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]
// CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1
-// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]
}
// CHECK: [[SIMPLE_LOOP7_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -312,7 +307,6 @@
// CHECK: [[A_PRIV_VAL:%.+]] = load i32, i32* [[A_PRIV]],
// CHECK-NEXT: store i32 [[A_PRIV_VAL]], i32* %{{.+}},
// CHECK-NEXT: br label
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
}
int R;
{
@@ -336,23 +330,23 @@
// CHECK: br label %[[SIMD_LOOP8_COND:[^,]+]]
// CHECK: [[SIMD_LOOP8_COND]]
-// CHECK-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: [[IV8:%.+]] = load i64, i64* [[OMP_IV8]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP8:%.+]] = icmp sle i64 [[IV8]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP8]], label %[[SIMPLE_LOOP8_BODY:.+]], label %[[SIMPLE_LOOP8_END:[^,]+]]
for (long long i = -10; i < 10; i += 3) {
// CHECK: [[SIMPLE_LOOP8_BODY]]
// Start of body: calculate i from IV:
-// CHECK: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK: [[IV8_0:%.+]] = load i64, i64* [[OMP_IV8]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV8_0]], 3
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
-// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
-// CHECK: store i32 %{{.+}}, i32* [[R_PRIV]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],
+// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]
+// CHECK: store i32 %{{.+}}, i32* [[R_PRIV]],
R *= i;
-// CHECK: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK: [[IV8_2:%.+]] = load i64, i64* [[OMP_IV8]]
// CHECK-NEXT: [[ADD8_2:%.+]] = add nsw i64 [[IV8_2]], 1
-// CHECK-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP8_ID]]
+// CHECK-NEXT: store i64 [[ADD8_2]], i64* [[OMP_IV8]]
}
// CHECK: [[SIMPLE_LOOP8_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
@@ -361,7 +355,6 @@
// CHECK: [[RED:%.+]] = mul nsw i32 %{{.+}}, [[R_PRIV_VAL]]
// CHECK-NEXT: store i32 [[RED]], i32* %{{.+}},
// CHECK-NEXT: call void @__kmpc_end_reduce_nowait(
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
}
}
@@ -445,14 +438,14 @@
// CHECK: [[LB_VAL:%.+]] = load i32, i32* [[LB]],
// CHECK: store i32 [[LB_VAL]], i32* [[IT_OMP_IV:%[^,]+]],
-// CHECK: [[IV:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}} !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[IT_OMP_IV]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[IT_BODY:[^,]+]], label %[[IT_END:[^,]+]]
for (IterDouble i = ia; i < ib; ++i) {
// CHECK: [[IT_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i32, i32* [[IT_OMP_IV]]
// Call of operator+ (i, IV).
// CHECK: {{%.+}} = invoke {{.+}} @{{.*}}IterDouble{{.*}}
// ... loop body ...
@@ -460,17 +453,16 @@
// Float multiply and save result.
// CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01
// CHECK-NEXT: invoke {{.+}} @{{.*}}IterDouble{{.*}}
-// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]], !llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]]
++ic;
//
-// CHECK: [[IV2:%.+]] = load i32, i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i32, i32* [[IT_OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add nsw i32 [[IV2]], 1
-// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[ITER_LOOP_ID]]
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[IT_OMP_IV]]
// br label %{{.*}}, !llvm.loop ![[ITER_LOOP_ID]]
}
// CHECK: [[IT_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
// CHECK: ret void
}
@@ -498,8 +490,8 @@
//
#pragma omp parallel for simd collapse(4)
-// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i32, i32* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp ule i32 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[COLL1_BODY:[^,]+]], label %[[COLL1_END:[^,]+]]
for (i = 1; i < 3; i++) // 2 iterations
@@ -509,25 +501,25 @@
{
// CHECK: [[COLL1_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i32, i32* [[OMP_IV]]
// Calculation of the loop counters values.
// CHECK: [[CALC_I_1:%.+]] = udiv i32 [[IV1]], 60
// CHECK-NEXT: [[CALC_I_1_MUL1:%.+]] = mul i32 [[CALC_I_1]], 1
// CHECK-NEXT: [[CALC_I_2:%.+]] = add i32 1, [[CALC_I_1_MUL1]]
// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
-// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_J_1:%.+]] = udiv i32 [[IV1_2]], 20
// CHECK-NEXT: [[CALC_J_2:%.+]] = urem i32 [[CALC_J_1]], 3
// CHECK-NEXT: [[CALC_J_2_MUL1:%.+]] = mul i32 [[CALC_J_2]], 1
// CHECK-NEXT: [[CALC_J_3:%.+]] = add i32 2, [[CALC_J_2_MUL1]]
// CHECK-NEXT: store i32 [[CALC_J_3]], i32* [[LC_J:.+]]
-// CHECK: [[IV1_3:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_3:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_K_1:%.+]] = udiv i32 [[IV1_3]], 5
// CHECK-NEXT: [[CALC_K_2:%.+]] = urem i32 [[CALC_K_1]], 4
// CHECK-NEXT: [[CALC_K_2_MUL1:%.+]] = mul i32 [[CALC_K_2]], 1
// CHECK-NEXT: [[CALC_K_3:%.+]] = add i32 3, [[CALC_K_2_MUL1]]
// CHECK-NEXT: store i32 [[CALC_K_3]], i32* [[LC_K:.+]]
-// CHECK: [[IV1_4:%.+]] = load i32, i32* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV1_4:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[CALC_L_1:%.+]] = urem i32 [[IV1_4]], 5
// CHECK-NEXT: [[CALC_L_1_MUL1:%.+]] = mul i32 [[CALC_L_1]], 1
// CHECK-NEXT: [[CALC_L_2:%.+]] = add i32 4, [[CALC_L_1_MUL1]]
@@ -535,12 +527,12 @@
// CHECK-NEXT: store i16 [[CALC_L_3]], i16* [[LC_L:.+]]
// ... loop body ...
// End of body: store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
float res = b[j] * c[k];
a[i] = res * d[l];
-// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add i32 [[IV2]], 1
-// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[COLL1_LOOP_ID]]
+// CHECK-NEXT: store i32 [[ADD2]], i32* [[OMP_IV]]
// br label %{{[^,]+}}, !llvm.loop ![[COLL1_LOOP_ID]]
// CHECK: [[COLL1_END]]
}
@@ -549,7 +541,6 @@
// CHECK: store i32 3, i32* [[I:%[^,]+]]
// CHECK: store i32 5, i32* [[I:%[^,]+]]
// CHECK: store i16 9, i16* [[I:%[^,]+]]
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
// CHECK: ret void
}
@@ -586,8 +577,8 @@
//
#pragma omp parallel for simd collapse(2) private(globalfloat, localint)
-// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID:[0-9]+]]
-// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
+// CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP]], label %[[WIDE1_BODY:[^,]+]], label %[[WIDE1_END:[^,]+]]
for (i = 1; i < 3; i++) // 2 iterations
@@ -595,10 +586,10 @@
{
// CHECK: [[WIDE1_BODY]]
// Start of body: calculate i from index:
-// CHECK: [[IV1:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV1:%.+]] = load i64, i64* [[OMP_IV]]
// Calculation of the loop counters values...
// CHECK: store i32 {{[^,]+}}, i32* [[LC_I:.+]]
-// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]
// CHECK: store i16 {{[^,]+}}, i16* [[LC_J:.+]]
// ... loop body ...
//
@@ -607,14 +598,14 @@
globalfloat = (float)j/i;
float res = b[j] * c[j];
// Store into a[i]:
-// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
a[i] = res * d[i];
// Then there's a store into private var localint:
-// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]{{.+}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]
localint = (int)j;
-// CHECK: [[IV2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK: [[IV2:%.+]] = load i64, i64* [[OMP_IV]]
// CHECK-NEXT: [[ADD2:%.+]] = add nsw i64 [[IV2]], 1
-// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[WIDE1_LOOP_ID]]
+// CHECK-NEXT: store i64 [[ADD2]], i64* [[OMP_IV]]
//
// br label %{{[^,]+}}, !llvm.loop ![[WIDE1_LOOP_ID]]
// CHECK: [[WIDE1_END]]
@@ -645,31 +636,30 @@
// CHECK: store i64 [[LB_VAL]], i64* [[T1_OMP_IV:%[^,]+]],
// ...
-// CHECK: [[IV:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID:[0-9]+]]
-// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[T1_OMP_IV]]
+// CHECK-NEXT: [[UB_VAL:%.+]] = load i64, i64* [[UB]]
// CHECK-NEXT: [[CMP1:%.+]] = icmp sle i64 [[IV]], [[UB_VAL]]
// CHECK-NEXT: br i1 [[CMP1]], label %[[T1_BODY:.+]], label %[[T1_END:[^,]+]]
// CHECK: [[T1_BODY]]
// Loop counters i and j updates:
-// CHECK: [[IV1:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV1:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[I_1:%.+]] = sdiv i64 [[IV1]], 4
// CHECK-NEXT: [[I_1_MUL1:%.+]] = mul nsw i64 [[I_1]], 1
// CHECK-NEXT: [[I_1_ADD0:%.+]] = add nsw i64 0, [[I_1_MUL1]]
// CHECK-NEXT: [[I_2:%.+]] = trunc i64 [[I_1_ADD0]] to i32
-// CHECK-NEXT: store i32 [[I_2]], i32* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
-// CHECK: [[IV2:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i32 [[I_2]], i32*
+// CHECK: [[IV2:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[J_1:%.+]] = srem i64 [[IV2]], 4
// CHECK-NEXT: [[J_2:%.+]] = mul nsw i64 [[J_1]], 2
// CHECK-NEXT: [[J_2_ADD0:%.+]] = add nsw i64 0, [[J_2]]
-// CHECK-NEXT: store i64 [[J_2_ADD0]], i64* {{%.+}}{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i64 [[J_2_ADD0]], i64*
// simd.for.inc:
-// CHECK: [[IV3:%.+]] = load i64, i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK: [[IV3:%.+]] = load i64, i64* [[T1_OMP_IV]]
// CHECK-NEXT: [[INC:%.+]] = add nsw i64 [[IV3]], 1
-// CHECK-NEXT: store i64 [[INC]], i64* [[T1_OMP_IV]]{{.*}}!llvm.mem.parallel_loop_access ![[T1_ID]]
+// CHECK-NEXT: store i64 [[INC]], i64*
// CHECK-NEXT: br label {{%.+}}
// CHECK: [[T1_END]]
// CHECK: call void @__kmpc_for_static_fini(%ident_t* {{.+}}, i32 %{{.+}})
-// CHECK: call void @__kmpc_barrier(%ident_t* {{.+}}, i32 %{{.+}})
// CHECK: ret void
//
// TERM_DEBUG-LABEL: bar
diff --git a/test/OpenMP/parallel_for_simd_collapse_messages.cpp b/test/OpenMP/parallel_for_simd_collapse_messages.cpp
index 22090e6..4f04cca 100644
--- a/test/OpenMP/parallel_for_simd_collapse_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_collapse_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp parallel for simd collapse (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp parallel for simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for simd', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd collapse (1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp parallel for simd collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for simd'}}
@@ -63,7 +63,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
index 22e514f..bd1a6d5 100644
--- a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
@@ -16,7 +16,7 @@
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
@@ -190,7 +190,7 @@
#pragma omp parallel for simd lastprivate(xa) // OK
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd lastprivate(S2::S2s)
+#pragma omp parallel for simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
diff --git a/test/OpenMP/parallel_for_simd_loop_messages.cpp b/test/OpenMP/parallel_for_simd_loop_messages.cpp
index 8fe5843..e5fd8c0 100644
--- a/test/OpenMP/parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_loop_messages.cpp
@@ -10,6 +10,7 @@
};
static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
#pragma omp threadprivate(sii)
static int globalii;
@@ -259,6 +260,7 @@
c[ii] = a[ii];
{
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be threadprivate or thread local, predetermined as linear}}
#pragma omp parallel for simd
for (sii = 0; sii < 10; sii += 1)
c[sii] = a[sii];
@@ -626,10 +628,16 @@
}
void test_ordered() {
-// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
#pragma omp parallel for simd ordered ordered // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'ordered' clause}}
for (int i = 0; i < 16; ++i)
;
+#pragma omp parallel for simd ordered
+ for (int i = 0; i < 16; ++i)
+ ;
+//expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp parallel for simd' directive}}
+#pragma omp parallel for simd ordered(1)
+ for (int i = 0; i < 16; ++i)
+ ;
}
void test_nowait() {
diff --git a/test/OpenMP/parallel_for_simd_messages.cpp b/test/OpenMP/parallel_for_simd_messages.cpp
index fe14883..18f25fa 100644
--- a/test/OpenMP/parallel_for_simd_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_messages.cpp
@@ -79,9 +79,15 @@
}
void test_ordered() {
-// expected-error@+1 2 {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel for simd'}}
#pragma omp parallel for simd ordered ordered // expected-error {{directive '#pragma omp parallel for simd' cannot contain more than one 'ordered' clause}}
for (int i = 0; i < 16; ++i)
;
+#pragma omp parallel for simd ordered
+ for (int i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp parallel for simd' directive}}
+#pragma omp parallel for simd ordered(1)
+ for (int i = 0; i < 16; ++i)
+ ;
}
diff --git a/test/OpenMP/parallel_for_simd_misc_messages.c b/test/OpenMP/parallel_for_simd_misc_messages.c
index 0f0d76b..378c48f 100644
--- a/test/OpenMP/parallel_for_simd_misc_messages.c
+++ b/test/OpenMP/parallel_for_simd_misc_messages.c
@@ -153,15 +153,15 @@
#pragma omp parallel for simd safelen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd safelen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd safelen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd safelen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -238,15 +238,15 @@
#pragma omp parallel for simd simdlen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd simdlen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd simdlen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd simdlen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -356,17 +356,17 @@
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for simd collapse(-5)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for simd collapse(0)
for (i = 0; i < 16; ++i)
;
#pragma omp parallel
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp parallel for simd collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
diff --git a/test/OpenMP/parallel_for_simd_num_threads_messages.cpp b/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
index 5b5d334..940565c 100644
--- a/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
@@ -24,7 +24,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (S) // expected-error {{'S' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
@@ -32,7 +32,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (argc)
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for simd num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for simd num_threads (N) // expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
return argc;
@@ -52,7 +52,7 @@
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel for simd num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/parallel_for_simd_reduction_messages.cpp b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
index 480f103..e2e9e1b 100644
--- a/test/OpenMP/parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - %s
void foo() {
}
@@ -16,7 +18,7 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
- static float S2s;
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
@@ -136,7 +141,7 @@
#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(&& : S2::S2s)
+#pragma omp parallel for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
@@ -258,7 +263,7 @@
#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(&& : S2::S2s)
+#pragma omp parallel for simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
diff --git a/test/OpenMP/parallel_for_simd_safelen_messages.cpp b/test/OpenMP/parallel_for_simd_safelen_messages.cpp
index eb0aa5a..45f2fa2 100644
--- a/test/OpenMP/parallel_for_simd_safelen_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_safelen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp parallel for simd safelen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp parallel for simd safelen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+2 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd safelen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp parallel for simd safelen (N) // expected-error {{argument to 'safelen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+1 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_for_simd_schedule_messages.cpp b/test/OpenMP/parallel_for_simd_schedule_messages.cpp
index 43e99ae..4135427 100644
--- a/test/OpenMP/parallel_for_simd_schedule_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_schedule_messages.cpp
@@ -13,13 +13,13 @@
T tmain(T argc, S **argv) {
#pragma omp parallel for simd schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -28,7 +28,7 @@
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp parallel for simd schedule (guided argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for simd schedule (static, ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd schedule (dynamic, 1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
@@ -36,7 +36,7 @@
#pragma omp parallel for simd schedule (guided, (ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for simd schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd schedule (static, S) // expected-error {{'S' does not refer to a value}}
@@ -46,7 +46,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd schedule (dynamic, 1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
+ #pragma omp parallel for simd schedule (static, N) // expected-error {{argument to 'schedule' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -54,13 +54,13 @@
int main(int argc, char **argv) {
#pragma omp parallel for simd schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for simd schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
+ #pragma omp parallel for simd schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd schedule (auto // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel for simd schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto', 'runtime', 'monotonic', 'nonmonotonic' or 'simd' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd schedule (auto, // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -73,7 +73,7 @@
#pragma omp parallel for simd schedule (dynamic, foobool(1) > 0 ? 1 : 2)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'schedule' clause}}
- // expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'schedule' clause must be a strictly positive integer value}}
#pragma omp parallel for simd schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd schedule (guided, S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_for_simd_simdlen_messages.cpp b/test/OpenMP/parallel_for_simd_simdlen_messages.cpp
index b71c210..dd1cf0f 100644
--- a/test/OpenMP/parallel_for_simd_simdlen_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_simdlen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp parallel for simd simdlen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd simdlen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd simdlen (1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp parallel for simd simdlen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+2 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp parallel for simd simdlen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp parallel for simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a positive integer value}}
+ #pragma omp parallel for simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+1 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp parallel for simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp parallel for simd simdlen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/parallel_num_threads_messages.cpp b/test/OpenMP/parallel_num_threads_messages.cpp
index 180d9cd..adcf6ca 100644
--- a/test/OpenMP/parallel_num_threads_messages.cpp
+++ b/test/OpenMP/parallel_num_threads_messages.cpp
@@ -19,11 +19,11 @@
#pragma omp parallel num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
#pragma omp parallel num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
- #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads (S) // expected-error {{'S' does not refer to a value}}
#pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp parallel num_threads (argc)
- #pragma omp parallel num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel num_threads (N) // expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel redef_num_threads (argc, argc)
foo();
@@ -37,7 +37,7 @@
#pragma omp parallel num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel num_threads (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
#pragma omp parallel num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }}
- #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads (S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp parallel num_threads (num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char, -1>' requested here}}
diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp
index c497526..ab535b4 100644
--- a/test/OpenMP/parallel_private_messages.cpp
+++ b/test/OpenMP/parallel_private_messages.cpp
@@ -13,7 +13,7 @@
mutable int a;
public:
S2():a(0) { }
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
};
const S2 b;
const S2 ba[5];
@@ -69,7 +69,7 @@
#pragma omp parallel private(ba)
#pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(da) // expected-error {{shared variable cannot be private}}
- #pragma omp parallel private(S2::S2s)
+ #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp parallel private(threadvar, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
#pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
diff --git a/test/OpenMP/parallel_reduction_codegen.cpp b/test/OpenMP/parallel_reduction_codegen.cpp
index 0fea14f..b9744b6 100644
--- a/test/OpenMP/parallel_reduction_codegen.cpp
+++ b/test/OpenMP/parallel_reduction_codegen.cpp
@@ -22,7 +22,6 @@
// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
-// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
@@ -164,6 +163,12 @@
vec[0] = t_var;
s_arr[0] = var;
}
+ if (var1)
+#pragma omp parallel reduction(+ : t_var) reduction(& : var) reduction(&& : var1) reduction(min : t_var1)
+ while (1) {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
return tmain<int>();
#endif
}
@@ -172,6 +177,7 @@
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x i32]*, float*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x i32]*, float*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*)* [[MAIN_MICROTASK1:@.+]] to void
// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
// CHECK: ret
@@ -341,7 +347,6 @@
// break;
// CHECK: br label %[[RED_DONE]]
// CHECK: [[RED_DONE]]
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
@@ -427,6 +432,35 @@
// CHECK: store float [[UP]], float* [[T_VAR1_LHS]],
// CHECK: ret void
+// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca float,
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[T_VAR1_PRIV:%.+]] = alloca float,
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[T_VAR_REF:%.+]] = load float*, float** %
+// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
+// CHECK: [[VAR1_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
+// CHECK: [[T_VAR1_REF:%.+]] = load float*, float** %
+
+// For + reduction operation initial value of private variable is 0.
+// CHECK: store float 0.0{{.+}}, float* [[T_VAR_PRIV]],
+
+// For & reduction operation initial value of private variable is ones in all bits.
+// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// For && reduction operation initial value of private variable is 1.0.
+// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR1_PRIV]])
+
+// For min reduction operation initial value of private variable is largest repesentable value.
+// CHECK: store float 0x47EFFFFFE0000000, float* [[T_VAR1_PRIV]],
+
+// CHECK-NOT: call i32 @__kmpc_reduce
+
+// CHECK: ret void
+
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
@@ -572,7 +606,6 @@
// break;
// CHECK: br label %[[RED_DONE]]
// CHECK: [[RED_DONE]]
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
diff --git a/test/OpenMP/parallel_reduction_messages.cpp b/test/OpenMP/parallel_reduction_messages.cpp
index 9439fed..b29f7c9 100644
--- a/test/OpenMP/parallel_reduction_messages.cpp
+++ b/test/OpenMP/parallel_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s
void foo() {
}
@@ -16,7 +18,7 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
- static float S2s;
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
@@ -116,7 +121,7 @@
foo();
#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
-#pragma omp parallel reduction(&& : S2::S2s)
+#pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
foo();
#pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
foo();
@@ -211,7 +216,7 @@
foo();
#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
-#pragma omp parallel reduction(&& : S2::S2s)
+#pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
foo();
#pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
foo();
diff --git a/test/OpenMP/parallel_sections_codegen.cpp b/test/OpenMP/parallel_sections_codegen.cpp
index a517062..b8c1e39 100644
--- a/test/OpenMP/parallel_sections_codegen.cpp
+++ b/test/OpenMP/parallel_sections_codegen.cpp
@@ -5,7 +5,6 @@
// REQUIRES: x86-registered-target
#ifndef HEADER
#define HEADER
-// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-LABEL: foo
void foo() {};
// CHECK-LABEL: bar
@@ -73,7 +72,6 @@
// CHECK: [[INNER_LOOP_END]]
}
// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]],
return tmain<int>();
}
@@ -89,7 +87,6 @@
// CHECK: call void @__kmpc_end_single(
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
-// CHECK-NEXT: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]],
// CHECK-NEXT: ret
// CHECK: [[TERM_LPAD]]
// CHECK: call void @__clang_call_terminate(i8*
diff --git a/test/OpenMP/parallel_sections_lastprivate_messages.cpp b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
index d213cdd..af3c5e2 100644
--- a/test/OpenMP/parallel_sections_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
@@ -16,7 +16,7 @@
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
@@ -220,7 +220,7 @@
{
foo();
}
-#pragma omp parallel sections lastprivate(S2::S2s)
+#pragma omp parallel sections lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_num_threads_messages.cpp b/test/OpenMP/parallel_sections_num_threads_messages.cpp
index a500256..cda3841 100644
--- a/test/OpenMP/parallel_sections_num_threads_messages.cpp
+++ b/test/OpenMP/parallel_sections_num_threads_messages.cpp
@@ -23,7 +23,7 @@
{foo();}
#pragma omp parallel sections num_threads ((argc > 0) ? argv[1] : argv[2]) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
{foo();}
- #pragma omp parallel sections num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel sections' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel sections num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel sections' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
{foo();}
#pragma omp parallel sections num_threads (S) // expected-error {{'S' does not refer to a value}}
{foo();}
@@ -31,7 +31,7 @@
{foo();}
#pragma omp parallel sections num_threads (argc)
{foo();}
- #pragma omp parallel sections num_threads (N) // expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel sections num_threads (N) // expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
{foo();}
return argc;
@@ -50,7 +50,7 @@
{foo();}
#pragma omp parallel sections num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{integral }}
{foo();}
- #pragma omp parallel sections num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel sections' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a positive integer value}}
+ #pragma omp parallel sections num_threads (foobool(argc)), num_threads (true), num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel sections' cannot contain more than one 'num_threads' clause}} expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}}
{foo();}
#pragma omp parallel sections num_threads (S1) // expected-error {{'S1' does not refer to a value}}
{foo();}
diff --git a/test/OpenMP/parallel_sections_reduction_messages.cpp b/test/OpenMP/parallel_sections_reduction_messages.cpp
index ccf6741..eff1849 100644
--- a/test/OpenMP/parallel_sections_reduction_messages.cpp
+++ b/test/OpenMP/parallel_sections_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s
void foo() {
}
@@ -16,7 +18,7 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
- static float S2s;
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
@@ -156,7 +161,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(&& : S2::S2s)
+#pragma omp parallel sections reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
{
foo();
}
@@ -309,7 +314,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(&& : S2::S2s)
+#pragma omp parallel sections reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
{
foo();
}
diff --git a/test/OpenMP/schedule_codegen.cpp b/test/OpenMP/schedule_codegen.cpp
new file mode 100644
index 0000000..bd5ec86
--- /dev/null
+++ b/test/OpenMP/schedule_codegen.cpp
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+
+int main() {
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for simd
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for schedule(static)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for simd schedule(static)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for schedule(static, 2)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for simd schedule(static, 2)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(auto)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(auto)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(runtime)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(runtime)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for schedule(monotonic: static)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for simd schedule(monotonic: static)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for schedule(monotonic: static, 2)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_for_static_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_for_static_fini
+#pragma omp for simd schedule(monotonic: static, 2)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(monotonic: auto)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(monotonic: auto)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(monotonic: runtime)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(monotonic: runtime)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(monotonic: guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(monotonic: guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(monotonic: dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(monotonic: dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(nonmonotonic: guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(nonmonotonic: guided)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for schedule(nonmonotonic: dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(nonmonotonic: dynamic)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(static) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for simd schedule(static) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(static, 2) ordered(1)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for simd schedule(static, 2) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(auto) ordered(1)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+#pragma omp for simd schedule(auto) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(runtime) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for simd schedule(runtime) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(guided) ordered(1)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for simd schedule(guided) ordered
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for schedule(dynamic) ordered(1)
+ for(int i = 0; i < 10; ++i);
+// CHECK: @__kmpc_dispatch_init
+// CHECK-NOT: !llvm.mem.parallel_loop_access
+// CHECK: @__kmpc_dispatch_next
+#pragma omp for simd schedule(dynamic)
+ for(int i = 0; i < 10; ++i);
+ return 0;
+}
diff --git a/test/OpenMP/sections_codegen.cpp b/test/OpenMP/sections_codegen.cpp
index 9c7ce21..44fdefe 100644
--- a/test/OpenMP/sections_codegen.cpp
+++ b/test/OpenMP/sections_codegen.cpp
@@ -96,7 +96,6 @@
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
// CHECK-NEXT: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SINGLE_LOC]],
-// CHECK: call void @__kmpc_barrier(
// CHECK: ret
// CHECK: [[TERM_LPAD]]
// CHECK: call void @__clang_call_terminate(i8*
diff --git a/test/OpenMP/sections_firstprivate_messages.cpp b/test/OpenMP/sections_firstprivate_messages.cpp
index e6ce503..cd2b4b8 100644
--- a/test/OpenMP/sections_firstprivate_messages.cpp
+++ b/test/OpenMP/sections_firstprivate_messages.cpp
@@ -135,7 +135,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp sections' directive into a parallel or another task region?}}
-#pragma omp sections firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp sections firstprivate(i) // expected-error {{firstprivate variable must be shared}}
{
foo();
}
@@ -322,7 +322,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp sections' directive into a parallel or another task region?}}
-#pragma omp sections firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp sections firstprivate(i) // expected-error {{firstprivate variable must be shared}}
{
foo();
}
diff --git a/test/OpenMP/sections_lastprivate_codegen.cpp b/test/OpenMP/sections_lastprivate_codegen.cpp
index b1d242a..a1ff007 100644
--- a/test/OpenMP/sections_lastprivate_codegen.cpp
+++ b/test/OpenMP/sections_lastprivate_codegen.cpp
@@ -23,7 +23,6 @@
// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, i{{[0-9]+}}* }
// CHECK: [[S_INT_TY:%.+]] = type { i32 }
-// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-DAG: [[SINGLE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-DAG: [[SECTIONS_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
// CHECK-DAG: [[X:@.+]] = global double 0.0
@@ -256,7 +255,6 @@
// CHECK: call void @__kmpc_end_single(
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SINGLE_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
//
@@ -287,7 +285,6 @@
// CHECK: [[LAST_DONE]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SECTIONS_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
@@ -364,9 +361,6 @@
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SECTIONS_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
-// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
#endif
diff --git a/test/OpenMP/sections_reduction_codegen.cpp b/test/OpenMP/sections_reduction_codegen.cpp
index 2904d97..f67977c 100644
--- a/test/OpenMP/sections_reduction_codegen.cpp
+++ b/test/OpenMP/sections_reduction_codegen.cpp
@@ -23,7 +23,6 @@
// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
// CHECK-DAG: [[ATOMIC_REDUCE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
-// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-DAG: [[SINGLE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
@@ -213,7 +212,6 @@
// CHECK: call void @__kmpc_end_single(
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SINGLE_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
@@ -372,7 +370,6 @@
// CHECK: [[RED_DONE]]
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
diff --git a/test/OpenMP/sections_reduction_messages.cpp b/test/OpenMP/sections_reduction_messages.cpp
index 561c45e..79473d4 100644
--- a/test/OpenMP/sections_reduction_messages.cpp
+++ b/test/OpenMP/sections_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
void foo() {
}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
diff --git a/test/OpenMP/simd_aligned_messages.cpp b/test/OpenMP/simd_aligned_messages.cpp
index 408cc2e..6be7529 100644
--- a/test/OpenMP/simd_aligned_messages.cpp
+++ b/test/OpenMP/simd_aligned_messages.cpp
@@ -50,7 +50,7 @@
T sum = (T)0;
T ind2 = - num * L;
// Negative number is passed as L.
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp simd aligned(arr:L)
for (i = 0; i < num; ++i) {
T cur = arr[(int)ind2];
@@ -65,7 +65,7 @@
template<int LEN> int test_warn() {
int *ind2 = 0;
- // expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
#pragma omp simd aligned(ind2:LEN)
for (int i = 0; i < 100; i++) {
ind2 += LEN;
diff --git a/test/OpenMP/simd_collapse_messages.cpp b/test/OpenMP/simd_collapse_messages.cpp
index 56ff201..e34f0a1 100644
--- a/test/OpenMP/simd_collapse_messages.cpp
+++ b/test/OpenMP/simd_collapse_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp simd collapse (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp simd', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd collapse (1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp simd collapse (N) // expected-error {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp simd'}}
@@ -63,7 +63,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp simd' cannot contain more than one 'collapse' clause}}
- // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp simd collapse (foobool(argc)), collapse (true), collapse (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/simd_loop_messages.cpp b/test/OpenMP/simd_loop_messages.cpp
index 677f2b9..96b4caf 100644
--- a/test/OpenMP/simd_loop_messages.cpp
+++ b/test/OpenMP/simd_loop_messages.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fopenmp -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
#pragma omp threadprivate(sii)
static int globalii;
@@ -252,6 +253,7 @@
#pragma omp parallel
{
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp simd' directive may not be threadprivate or thread local, predetermined as linear}}
#pragma omp simd
for (sii = 0; sii < 10; sii+=1)
c[sii] = a[sii];
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index bf03aa8..1e15482 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -152,15 +152,15 @@
#pragma omp simd safelen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp simd safelen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp simd safelen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp simd safelen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -237,15 +237,15 @@
#pragma omp simd simdlen(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp simd simdlen(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp simd simdlen(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp simd simdlen(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -338,15 +338,15 @@
#pragma omp simd collapse(foo())
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp simd collapse(-5)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp simd collapse(0)
for (i = 0; i < 16; ++i)
;
-// expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp simd collapse(5 - 5)
for (i = 0; i < 16; ++i)
;
@@ -356,12 +356,18 @@
for (i = 0; i < 16; ++i)
// expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}}
for (int j = 0; j < 16; ++j)
-// expected-error@+3 {{reduction variable must be shared}}
-// expected-error@+2 {{private variable cannot be reduction}}
+// expected-error@+2 2 {{reduction variable must be shared}}
// expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}}
#pragma omp for reduction(+ : i, j)
for (int k = 0; k < 16; ++k)
i += j;
+#pragma omp parallel
+#pragma omp for
+ for (i = 0; i < 16; ++i)
+ for (int j = 0; j < 16; ++j)
+#pragma omp simd reduction(+ : i, j)
+ for (int k = 0; k < 16; ++k)
+ i += j;
}
void test_linear() {
diff --git a/test/OpenMP/simd_reduction_messages.cpp b/test/OpenMP/simd_reduction_messages.cpp
index 82a966c..e082921c 100644
--- a/test/OpenMP/simd_reduction_messages.cpp
+++ b/test/OpenMP/simd_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s
void foo() {
}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
diff --git a/test/OpenMP/simd_safelen_messages.cpp b/test/OpenMP/simd_safelen_messages.cpp
index b7300c3..aa31b7d 100644
--- a/test/OpenMP/simd_safelen_messages.cpp
+++ b/test/OpenMP/simd_safelen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp simd safelen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp simd safelen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+2 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd safelen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp simd safelen (N) // expected-error {{argument to 'safelen' clause must be a positive integer value}}
+ #pragma omp simd safelen (N) // expected-error {{argument to 'safelen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp simd' cannot contain more than one 'safelen' clause}}
- // expected-error@+1 2 {{argument to 'safelen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
#pragma omp simd safelen (foobool(argc)), safelen (true), safelen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/simd_simdlen_messages.cpp b/test/OpenMP/simd_simdlen_messages.cpp
index b9b0004..91656f8 100644
--- a/test/OpenMP/simd_simdlen_messages.cpp
+++ b/test/OpenMP/simd_simdlen_messages.cpp
@@ -22,7 +22,7 @@
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp simd simdlen (argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp simd simdlen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd simdlen (1)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}}
@@ -30,7 +30,7 @@
#pragma omp simd simdlen ((ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+3 2 {{directive '#pragma omp simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+2 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+2 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
@@ -41,7 +41,7 @@
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp simd simdlen (4)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- #pragma omp simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a positive integer value}}
+ #pragma omp simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a strictly positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}
@@ -61,7 +61,7 @@
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp simd' cannot contain more than one 'simdlen' clause}}
- // expected-error@+1 2 {{argument to 'simdlen' clause must be a positive integer value}}
+ // expected-error@+1 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
#pragma omp simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp simd simdlen (S1) // expected-error {{'S1' does not refer to a value}}
diff --git a/test/OpenMP/single_firstprivate_codegen.cpp b/test/OpenMP/single_firstprivate_codegen.cpp
index 316595b..cc72add 100644
--- a/test/OpenMP/single_firstprivate_codegen.cpp
+++ b/test/OpenMP/single_firstprivate_codegen.cpp
@@ -276,7 +276,6 @@
// CHECK: call void @__kmpc_end_single(
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SINGLE_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: ret void
#endif
diff --git a/test/OpenMP/single_firstprivate_messages.cpp b/test/OpenMP/single_firstprivate_messages.cpp
index 3fd00ae..32de9fd 100644
--- a/test/OpenMP/single_firstprivate_messages.cpp
+++ b/test/OpenMP/single_firstprivate_messages.cpp
@@ -109,7 +109,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp single' directive into a parallel or another task region?}}
-#pragma omp single firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
foo();
v += i;
}
@@ -232,7 +232,7 @@
{
int v = 0;
int i; // expected-note {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp single' directive into a parallel or another task region?}}
-#pragma omp single firstprivate(i) // expected-error {{private variable cannot be firstprivate}}
+#pragma omp single firstprivate(i) // expected-error {{firstprivate variable must be shared}}
foo();
v += i;
}
diff --git a/test/OpenMP/target_ast_print.cpp b/test/OpenMP/target_ast_print.cpp
index 89b5205..acf032a 100644
--- a/test/OpenMP/target_ast_print.cpp
+++ b/test/OpenMP/target_ast_print.cpp
@@ -10,39 +10,77 @@
template <typename T, int C>
T tmain(T argc, T *argv) {
+ T i, j, a[20];
#pragma omp target
foo();
#pragma omp target if (target:argc > 0)
foo();
#pragma omp target if (C)
foo();
+#pragma omp target map(i)
+ foo();
+#pragma omp target map(a[0:10], i)
+ foo();
+#pragma omp target map(to: i) map(from: j)
+ foo();
+#pragma omp target map(always,alloc: i)
+ foo();
return 0;
}
// CHECK: template <typename T = int, int C = 5> int tmain(int argc, int *argv) {
+// CHECK-NEXT: int i, j, a[20]
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: foo();
// CHECK-NEXT: #pragma omp target if(target: argc > 0)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target if(5)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: a[0:10],i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(to: i) map(from: j)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,alloc: i)
+// CHECK-NEXT: foo()
// CHECK: template <typename T = char, int C = 1> char tmain(char argc, char *argv) {
+// CHECK-NEXT: char i, j, a[20]
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: foo();
// CHECK-NEXT: #pragma omp target if(target: argc > 0)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target if(1)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: a[0:10],i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(to: i) map(from: j)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,alloc: i)
+// CHECK-NEXT: foo()
// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
+// CHECK-NEXT: T i, j, a[20]
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: foo();
// CHECK-NEXT: #pragma omp target if(target: argc > 0)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target if(C)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: a[0:10],i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(to: i) map(from: j)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,alloc: i)
+// CHECK-NEXT: foo()
// CHECK-LABEL: int main(int argc, char **argv) {
int main (int argc, char **argv) {
+ int i, j, a[20];
+// CHECK-NEXT: int i, j, a[20]
#pragma omp target
// CHECK-NEXT: #pragma omp target
foo();
@@ -51,6 +89,32 @@
// CHECK-NEXT: #pragma omp target if(argc > 0)
foo();
// CHECK-NEXT: foo();
+
+#pragma omp target map(i) if(argc>0)
+// CHECK-NEXT: #pragma omp target map(tofrom: i) if(argc > 0)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target map(i)
+// CHECK-NEXT: #pragma omp target map(tofrom: i)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target map(a[0:10], i)
+// CHECK-NEXT: #pragma omp target map(tofrom: a[0:10],i)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target map(to: i) map(from: j)
+// CHECK-NEXT: #pragma omp target map(to: i) map(from: j)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target map(always,alloc: i)
+// CHECK-NEXT: #pragma omp target map(always,alloc: i)
+ foo();
+// CHECK-NEXT: foo();
+
return tmain<int, 5>(argc, &argc) + tmain<char, 1>(argv[0][0], argv[0]);
}
diff --git a/test/OpenMP/target_codegen.cpp b/test/OpenMP/target_codegen.cpp
index 0b6f91e..c2e08d6 100644
--- a/test/OpenMP/target_codegen.cpp
+++ b/test/OpenMP/target_codegen.cpp
@@ -1,30 +1,47 @@
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
// CHECK-DAG: [[TT:%.+]] = type { i64, i8 }
// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]] }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}} }
// We have 8 target regions, but only 7 that actually will generate offloading
// code, only 6 will have mapped arguments, and only 4 have all-constant map
// sizes.
// CHECK-DAG: [[SIZET2:@.+]] = private unnamed_addr constant [1 x i{{32|64}}] [i[[SZ:32|64]] 2]
-// CHECK-DAG: [[MAPT2:@.+]] = private unnamed_addr constant [1 x i32] [i32 3]
+// CHECK-DAG: [[MAPT2:@.+]] = private unnamed_addr constant [1 x i32] [i32 128]
// CHECK-DAG: [[SIZET3:@.+]] = private unnamed_addr constant [2 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2]
-// CHECK-DAG: [[MAPT3:@.+]] = private unnamed_addr constant [2 x i32] [i32 3, i32 3]
-// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 3, i32 3, i32 1, i32 3, i32 3, i32 1, i32 1, i32 3, i32 3]
+// CHECK-DAG: [[MAPT3:@.+]] = private unnamed_addr constant [2 x i32] [i32 128, i32 128]
+// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 128, i32 3, i32 128, i32 3, i32 3, i32 128, i32 128, i32 3, i32 3]
// CHECK-DAG: [[SIZET5:@.+]] = private unnamed_addr constant [3 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 40]
-// CHECK-DAG: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 3, i32 3, i32 3]
+// CHECK-DAG: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 128, i32 128, i32 3]
// CHECK-DAG: [[SIZET6:@.+]] = private unnamed_addr constant [4 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 1, i[[SZ]] 40]
-// CHECK-DAG: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 3, i32 3, i32 3, i32 3]
-// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 3, i32 3, i32 1, i32 1, i32 3]
+// CHECK-DAG: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 128, i32 128, i32 128, i32 3]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 3, i32 128, i32 128, i32 128, i32 3]
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -33,6 +50,27 @@
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK-NOT: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
template<typename tx, typename ty>
struct TT{
tx X;
@@ -66,7 +104,7 @@
// CHECK: store i32 -1, i32* [[RHV]], align 4
// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
- // CHECK: call void [[HVT1:@.+]](i32* {{[^,]+}})
+ // CHECK: call void [[HVT1:@.+]](i[[SZ]] {{[^,]+}})
#pragma omp target if(0)
{
a += 1;
@@ -79,15 +117,15 @@
// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PR]], i32 0, i32 [[IDX0]]
// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
- // CHECK-DAG: [[BP0]] = bitcast i16* %{{.+}} to i8*
- // CHECK-DAG: [[P0]] = bitcast i16* %{{.+}} to i8*
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
- // CHECK: call void [[HVT2:@.+]](i16* {{[^,]+}})
+ // CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
#pragma omp target if(1)
@@ -106,15 +144,15 @@
// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 0
// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
- // CHECK-DAG: [[BP0]] = bitcast i32* %{{.+}} to i8*
- // CHECK-DAG: [[P0]] = bitcast i32* %{{.+}} to i8*
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP]], i32 0, i32 1
// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 1
// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
- // CHECK-DAG: [[BP1]] = bitcast i16* %{{.+}} to i8*
- // CHECK-DAG: [[P1]] = bitcast i16* %{{.+}} to i8*
+ // CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P1]] = inttoptr i[[SZ]] %{{.+}} to i8*
// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
// CHECK-NEXT: br label %[[IFEND:.+]]
@@ -137,12 +175,17 @@
}
// We capture 3 VLA sizes in this target region
- // CHECK: store i[[SZ]] [[BNELEMSIZE:%.+]], i[[SZ]]* [[VLA0:%[^,]+]]
- // CHECK: store i[[SZ]] 5, i[[SZ]]* [[VLA1:%[^,]+]]
- // CHECK: store i[[SZ]] [[CNELEMSIZE1:%.+]], i[[SZ]]* [[VLA2:%[^,]+]]
+ // CHECK-64: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-64: [[A_ADDR:%.+]] = bitcast i[[SZ]]* [[A_CADDR:%.+]] to i32*
+ // CHECK-64: store i32 [[A_VAL]], i32* [[A_ADDR]],
+ // CHECK-64: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
- // CHECK: [[BNSIZE:%.+]] = mul nuw i[[SZ]] [[BNELEMSIZE]], 4
- // CHECK: [[CNELEMSIZE2:%.+]] = mul nuw i[[SZ]] 5, [[CNELEMSIZE1]]
+ // CHECK-32: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-32: store i32 [[A_VAL]], i32* [[A_CADDR:%.+]],
+ // CHECK-32: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
+
+ // CHECK: [[BNSIZE:%.+]] = mul nuw i[[SZ]] [[VLA0:%.+]], 4
+ // CHECK: [[CNELEMSIZE2:%.+]] = mul nuw i[[SZ]] 5, [[VLA1:%.+]]
// CHECK: [[CNSIZE:%.+]] = mul nuw i[[SZ]] [[CNELEMSIZE2]], 8
// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 20
@@ -183,26 +226,24 @@
// The names below are not necessarily consistent with the names used for the
// addresses above as some are repeated.
- // CHECK-DAG: [[BP0:%[^,]+]] = bitcast i[[SZ]]* [[VLA0]] to i8*
- // CHECK-DAG: [[P0:%[^,]+]] = bitcast i[[SZ]]* [[VLA0]] to i8*
+ // CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+ // CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
// CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
// CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
- // CHECK-DAG: [[BP1:%[^,]+]] = bitcast i[[SZ]]* [[VLA1]] to i8*
- // CHECK-DAG: [[P1:%[^,]+]] = bitcast i[[SZ]]* [[VLA1]] to i8*
+ // CHECK-DAG: [[BP1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
+ // CHECK-DAG: [[P1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
// CHECK-DAG: store i8* [[BP1]], i8** {{%[^,]+}}
// CHECK-DAG: store i8* [[P1]], i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
- // CHECK-DAG: [[BP2:%[^,]+]] = bitcast i[[SZ]]* [[VLA2]] to i8*
- // CHECK-DAG: [[P2:%[^,]+]] = bitcast i[[SZ]]* [[VLA2]] to i8*
- // CHECK-DAG: store i8* [[BP2]], i8** {{%[^,]+}}
- // CHECK-DAG: store i8* [[P2]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
- // CHECK-DAG: [[BP3:%[^,]+]] = bitcast i32* %{{.+}} to i8*
- // CHECK-DAG: [[P3:%[^,]+]] = bitcast i32* %{{.+}} to i8*
+ // CHECK-DAG: [[BP3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
+ // CHECK-DAG: [[P3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
// CHECK-DAG: store i8* [[BP3]], i8** {{%[^,]+}}
// CHECK-DAG: store i8* [[P3]], i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
@@ -265,67 +306,67 @@
// CHECK: define internal void [[HVT0]]()
-// CHECK: define internal void [[HVT1]](i32* dereferenceable(4) %{{.+}})
+// CHECK: define internal void [[HVT1]](i[[SZ]] %{{.+}})
// Create stack storage and store argument in there.
-// CHECK: [[A_ADDR:%.+]] = alloca i32*, align
-// CHECK: store i32* %{{.+}}, i32** [[A_ADDR]], align
-// CHECK: [[A_ADDR2:%.+]] = load i32*, i32** [[A_ADDR]], align
-// CHECK: load i32, i32* [[A_ADDR2]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i32*
+// CHECK-64: load i32, i32* [[AA_CADDR]], align
+// CHECK-32: load i32, i32* [[AA_ADDR]], align
-// CHECK: define internal void [[HVT2]](i16* dereferenceable(2) %{{.+}})
+// CHECK: define internal void [[HVT2]](i[[SZ]] %{{.+}})
// Create stack storage and store argument in there.
-// CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
-// CHECK: store i16* %{{.+}}, i16** [[AA_ADDR]], align
-// CHECK: [[AA_ADDR2:%.+]] = load i16*, i16** [[AA_ADDR]], align
-// CHECK: load i16, i16* [[AA_ADDR2]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: load i16, i16* [[AA_CADDR]], align
// CHECK: define internal void [[HVT3]]
// Create stack storage and store argument in there.
-// CHECK-DAG: [[A_ADDR:%.+]] = alloca i32*, align
-// CHECK-DAG: [[AA_ADDR:%.+]] = alloca i16*, align
-// CHECK-DAG: store i32* %{{.+}}, i32** [[A_ADDR]], align
-// CHECK-DAG: store i16* %{{.+}}, i16** [[AA_ADDR]], align
-// CHECK-DAG: [[A_ADDR2:%.+]] = load i32*, i32** [[A_ADDR]], align
-// CHECK-DAG: [[AA_ADDR2:%.+]] = load i16*, i16** [[AA_ADDR]], align
-// CHECK-DAG: load i32, i32* [[A_ADDR2]], align
-// CHECK-DAG: load i16, i16* [[AA_ADDR2]], align
+// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[A_ADDR]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64-DAG:[[A_CADDR:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i32*
+// CHECK-DAG: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK-64-DAG:load i32, i32* [[A_CADDR]], align
+// CHECK-32-DAG:load i32, i32* [[A_ADDR]], align
+// CHECK-DAG: load i16, i16* [[AA_CADDR]], align
// CHECK: define internal void [[HVT4]]
// Create local storage for each capture.
-// CHECK-DAG: [[LOCAL_A:%.+]] = alloca i32*
-// CHECK-DAG: [[LOCAL_B:%.+]] = alloca [10 x float]*
-// CHECK-DAG: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]*
-// CHECK-DAG: [[LOCAL_BN:%.+]] = alloca float*
-// CHECK-DAG: [[LOCAL_C:%.+]] = alloca [5 x [10 x double]]*
-// CHECK-DAG: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]*
-// CHECK-DAG: [[LOCAL_VLA3:%.+]] = alloca i[[SZ]]*
-// CHECK-DAG: [[LOCAL_CN:%.+]] = alloca double*
-// CHECK-DAG: [[LOCAL_D:%.+]] = alloca [[TT]]*
-// CHECK-DAG: store i32* [[ARG_A:%.+]], i32** [[LOCAL_A]]
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x float]*
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_BN:%.+]] = alloca float*
+// CHECK: [[LOCAL_C:%.+]] = alloca [5 x [10 x double]]*
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA3:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_CN:%.+]] = alloca double*
+// CHECK: [[LOCAL_D:%.+]] = alloca [[TT]]*
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
// CHECK-DAG: store [10 x float]* [[ARG_B:%.+]], [10 x float]** [[LOCAL_B]]
-// CHECK-DAG: store i[[SZ]]* [[ARG_VLA1:%.+]], i[[SZ]]** [[LOCAL_VLA1]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
// CHECK-DAG: store float* [[ARG_BN:%.+]], float** [[LOCAL_BN]]
// CHECK-DAG: store [5 x [10 x double]]* [[ARG_C:%.+]], [5 x [10 x double]]** [[LOCAL_C]]
-// CHECK-DAG: store i[[SZ]]* [[ARG_VLA2:%.+]], i[[SZ]]** [[LOCAL_VLA2]]
-// CHECK-DAG: store i[[SZ]]* [[ARG_VLA3:%.+]], i[[SZ]]** [[LOCAL_VLA3]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA3:%.+]], i[[SZ]]* [[LOCAL_VLA3]]
// CHECK-DAG: store double* [[ARG_CN:%.+]], double** [[LOCAL_CN]]
// CHECK-DAG: store [[TT]]* [[ARG_D:%.+]], [[TT]]** [[LOCAL_D]]
-// CHECK-DAG: [[REF_A:%.+]] = load i32*, i32** [[LOCAL_A]],
+// CHECK-64-DAG:[[REF_A:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
// CHECK-DAG: [[REF_B:%.+]] = load [10 x float]*, [10 x float]** [[LOCAL_B]],
-// CHECK-DAG: [[REF_VLA1:%.+]] = load i[[SZ]]*, i[[SZ]]** [[LOCAL_VLA1]],
-// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[REF_VLA1]],
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
// CHECK-DAG: [[REF_BN:%.+]] = load float*, float** [[LOCAL_BN]],
// CHECK-DAG: [[REF_C:%.+]] = load [5 x [10 x double]]*, [5 x [10 x double]]** [[LOCAL_C]],
-// CHECK-DAG: [[REF_VLA2:%.+]] = load i[[SZ]]*, i[[SZ]]** [[LOCAL_VLA2]],
-// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[REF_VLA2]],
-// CHECK-DAG: [[REF_VLA3:%.+]] = load i[[SZ]]*, i[[SZ]]** [[LOCAL_VLA3]],
-// CHECK-DAG: [[VAL_VLA3:%.+]] = load i[[SZ]], i[[SZ]]* [[REF_VLA3]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
+// CHECK-DAG: [[VAL_VLA3:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA3]],
// CHECK-DAG: [[REF_CN:%.+]] = load double*, double** [[LOCAL_CN]],
// CHECK-DAG: [[REF_D:%.+]] = load [[TT]]*, [[TT]]** [[LOCAL_D]],
// Use captures.
-// CHECK-DAG: load i32, i32* [[REF_A]]
+// CHECK-64-DAG: load i32, i32* [[REF_A]]
+// CHECK-32-DAG: load i32, i32* [[LOCAL_A]]
// CHECK-DAG: getelementptr inbounds [10 x float], [10 x float]* [[REF_B]], i[[SZ]] 0, i[[SZ]] 2
// CHECK-DAG: getelementptr inbounds float, float* [[REF_BN]], i[[SZ]] 3
// CHECK-DAG: getelementptr inbounds [5 x [10 x double]], [5 x [10 x double]]* [[REF_C]], i[[SZ]] 0, i[[SZ]] 1
@@ -406,10 +447,16 @@
//
// CHECK: define {{.*}}[[FS1]]
//
+// CHECK: i8* @llvm.stacksave()
+// CHECK-64: [[B_ADDR:%.+]] = bitcast i[[SZ]]* [[B_CADDR:%.+]] to i32*
+// CHECK-64: store i32 %{{.+}}, i32* [[B_ADDR]],
+// CHECK-64: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_CADDR]],
+
+// CHECK-32: store i32 %{{.+}}, i32* [[B_ADDR:%.+]],
+// CHECK-32: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_ADDR]],
+
// We capture 2 VLA sizes in this target region
-// CHECK: store i[[SZ]] 2, i[[SZ]]* [[VLA0:%[^,]+]]
-// CHECK: store i[[SZ]] [[CELEMSIZE1:%.+]], i[[SZ]]* [[VLA1:%[^,]+]]
-// CHECK: [[CELEMSIZE2:%.+]] = mul nuw i[[SZ]] 2, [[CELEMSIZE1]]
+// CHECK: [[CELEMSIZE2:%.+]] = mul nuw i[[SZ]] 2, [[VLA0:%.+]]
// CHECK: [[CSIZE:%.+]] = mul nuw i[[SZ]] [[CELEMSIZE2]], 2
// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 60
@@ -434,20 +481,18 @@
// The names below are not necessarily consistent with the names used for the
// addresses above as some are repeated.
-// CHECK-DAG: [[BP0:%[^,]+]] = bitcast i[[SZ]]* [[VLA0]] to i8*
-// CHECK-DAG: [[P0:%[^,]+]] = bitcast i[[SZ]]* [[VLA0]] to i8*
+// CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+// CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
// CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
// CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
-// CHECK-DAG: [[BP1:%[^,]+]] = bitcast i[[SZ]]* [[VLA1]] to i8*
-// CHECK-DAG: [[P1:%[^,]+]] = bitcast i[[SZ]]* [[VLA1]] to i8*
-// CHECK-DAG: store i8* [[BP1]], i8** {{%[^,]+}}
-// CHECK-DAG: store i8* [[P1]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
-// CHECK-DAG: [[BP2:%[^,]+]] = bitcast i32* %{{.+}} to i8*
-// CHECK-DAG: [[P2:%[^,]+]] = bitcast i32* %{{.+}} to i8*
+// CHECK-DAG: [[BP2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
+// CHECK-DAG: [[P2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
// CHECK-DAG: store i8* [[BP2]], i8** {{%[^,]+}}
// CHECK-DAG: store i8* [[P2]], i8** {{%[^,]+}}
// CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
@@ -488,15 +533,15 @@
// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 0
// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
-// CHECK-DAG: [[BP0]] = bitcast i32* %{{.+}} to i8*
-// CHECK-DAG: [[P0]] = bitcast i32* %{{.+}} to i8*
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 1
// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 1
// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
-// CHECK-DAG: [[BP1]] = bitcast i16* %{{.+}} to i8*
-// CHECK-DAG: [[P1]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 2
// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 2
@@ -540,15 +585,15 @@
// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 0
// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
-// CHECK-DAG: [[BP0]] = bitcast i32* %{{.+}} to i8*
-// CHECK-DAG: [[P0]] = bitcast i32* %{{.+}} to i8*
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 1
// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 1
// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
-// CHECK-DAG: [[BP1]] = bitcast i16* %{{.+}} to i8*
-// CHECK-DAG: [[P1]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 2
// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 2
@@ -580,65 +625,66 @@
// CHECK: define internal void [[HVT7]]
// Create local storage for each capture.
-// CHECK-DAG: [[LOCAL_THIS:%.+]] = alloca [[S1]]*
-// CHECK-DAG: [[LOCAL_B:%.+]] = alloca i32*
-// CHECK-DAG: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]*
-// CHECK-DAG: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]*
-// CHECK-DAG: [[LOCAL_C:%.+]] = alloca i16*
+// CHECK: [[LOCAL_THIS:%.+]] = alloca [[S1]]*
+// CHECK: [[LOCAL_B:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_C:%.+]] = alloca i16*
// CHECK-DAG: store [[S1]]* [[ARG_THIS:%.+]], [[S1]]** [[LOCAL_THIS]]
-// CHECK-DAG: store i32* [[ARG_B:%.+]], i32** [[LOCAL_B]]
-// CHECK-DAG: store i[[SZ]]* [[ARG_VLA1:%.+]], i[[SZ]]** [[LOCAL_VLA1]]
-// CHECK-DAG: store i[[SZ]]* [[ARG_VLA2:%.+]], i[[SZ]]** [[LOCAL_VLA2]]
+// CHECK-DAG: store i[[SZ]] [[ARG_B:%.+]], i[[SZ]]* [[LOCAL_B]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
// CHECK-DAG: store i16* [[ARG_C:%.+]], i16** [[LOCAL_C]]
// Store captures in the context.
// CHECK-DAG: [[REF_THIS:%.+]] = load [[S1]]*, [[S1]]** [[LOCAL_THIS]],
-// CHECK-DAG: [[REF_B:%.+]] = load i32*, i32** [[LOCAL_B]],
-// CHECK-DAG: [[REF_VLA1:%.+]] = load i[[SZ]]*, i[[SZ]]** [[LOCAL_VLA1]],
-// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[REF_VLA1]],
-// CHECK-DAG: [[REF_VLA2:%.+]] = load i[[SZ]]*, i[[SZ]]** [[LOCAL_VLA2]],
-// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[REF_VLA2]],
+// CHECK-64-DAG:[[REF_B:%.+]] = bitcast i[[SZ]]* [[LOCAL_B]] to i32*
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
// CHECK-DAG: [[REF_C:%.+]] = load i16*, i16** [[LOCAL_C]],
// Use captures.
// CHECK-DAG: getelementptr inbounds [[S1]], [[S1]]* [[REF_THIS]], i32 0, i32 0
-// CHECK-DAG: load i32, i32* [[REF_B]]
+// CHECK-64-DAG:load i32, i32* [[REF_B]]
+// CHECK-32-DAG:load i32, i32* [[LOCAL_B]]
// CHECK-DAG: getelementptr inbounds i16, i16* [[REF_C]], i[[SZ]] %{{.+}}
// CHECK: define internal void [[HVT6]]
// Create local storage for each capture.
-// CHECK-DAG: [[LOCAL_A:%.+]] = alloca i32*
-// CHECK-DAG: [[LOCAL_AA:%.+]] = alloca i16*
-// CHECK-DAG: [[LOCAL_AAA:%.+]] = alloca i8*
-// CHECK-DAG: [[LOCAL_B:%.+]] = alloca [10 x i32]*
-// CHECK-DAG: store i32* [[ARG_A:%.+]], i32** [[LOCAL_A]]
-// CHECK-DAG: store i16* [[ARG_AA:%.+]], i16** [[LOCAL_AA]]
-// CHECK-DAG: store i8* [[ARG_AAA:%.+]], i8** [[LOCAL_AAA]]
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AAA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AAA:%.+]], i[[SZ]]* [[LOCAL_AAA]]
// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
// Store captures in the context.
-// CHECK-DAG: [[REF_A:%.+]] = load i32*, i32** [[LOCAL_A]],
-// CHECK-DAG: [[REF_AA:%.+]] = load i16*, i16** [[LOCAL_AA]],
-// CHECK-DAG: [[REF_AAA:%.+]] = load i8*, i8** [[LOCAL_AAA]],
-// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
+// CHECK-64-DAG: [[REF_A:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[REF_AA:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
+// CHECK-DAG: [[REF_AAA:%.+]] = bitcast i[[SZ]]* [[LOCAL_AAA]] to i8*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
// Use captures.
-// CHECK-DAG: load i32, i32* [[REF_A]]
-// CHECK-DAG: load i16, i16* [[REF_AA]]
-// CHECK-DAG: load i8, i8* [[REF_AAA]]
-// CHECK-DAG: getelementptr inbounds [10 x i32], [10 x i32]* [[REF_B]], i[[SZ]] 0, i[[SZ]] 2
+// CHECK-64-DAG: load i32, i32* [[REF_A]]
+// CHECK-DAG: load i16, i16* [[REF_AA]]
+// CHECK-DAG: load i8, i8* [[REF_AAA]]
+// CHECK-32-DAG: load i32, i32* [[LOCAL_A]]
+// CHECK-DAG: getelementptr inbounds [10 x i32], [10 x i32]* [[REF_B]], i[[SZ]] 0, i[[SZ]] 2
// CHECK: define internal void [[HVT5]]
// Create local storage for each capture.
-// CHECK-DAG: [[LOCAL_A:%.+]] = alloca i32*
-// CHECK-DAG: [[LOCAL_AA:%.+]] = alloca i16*
-// CHECK-DAG: [[LOCAL_B:%.+]] = alloca [10 x i32]*
-// CHECK-DAG: store i32* [[ARG_A:%.+]], i32** [[LOCAL_A]]
-// CHECK-DAG: store i16* [[ARG_AA:%.+]], i16** [[LOCAL_AA]]
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
// Store captures in the context.
-// CHECK-DAG: [[REF_A:%.+]] = load i32*, i32** [[LOCAL_A]],
-// CHECK-DAG: [[REF_AA:%.+]] = load i16*, i16** [[LOCAL_AA]],
+// CHECK-64-DAG:[[REF_A:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[REF_AA:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
// Use captures.
-// CHECK-DAG: load i32, i32* [[REF_A]]
+// CHECK-64-DAG: load i32, i32* [[REF_A]]
+// CHECK-32-DAG: load i32, i32* [[LOCAL_A]]
// CHECK-DAG: load i16, i16* [[REF_AA]]
// CHECK-DAG: getelementptr inbounds [10 x i32], [10 x i32]* [[REF_B]], i[[SZ]] 0, i[[SZ]] 2
#endif
diff --git a/test/OpenMP/target_codegen_global_capture.cpp b/test/OpenMP/target_codegen_global_capture.cpp
index af6b9ef..211a3cc 100644
--- a/test/OpenMP/target_codegen_global_capture.cpp
+++ b/test/OpenMP/target_codegen_global_capture.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
@@ -41,27 +41,88 @@
static float Sc = 7.0;
static float Sd = 8.0;
- // CHECK-DAG: [[REFB:%.+]] = bitcast i16* [[LB]] to i8*
- // CHECK-DAG: store i8* [[REFB]], i8** [[GEPB:%.+]], align
- // CHECK-DAG: [[REFC:%.+]] = bitcast i16* [[LC]] to i8*
- // CHECK-DAG: store i8* [[REFC]], i8** [[GEPC:%.+]], align
- // CHECK-DAG: [[REFD:%.+]] = bitcast i16* [[LD]] to i8*
- // CHECK-DAG: store i8* [[REFD]], i8** [[GEPD:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GB]] to i8*), i8** [[GEPGB:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GC]] to i8*), i8** [[GEPGC:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GD]] to i8*), i8** [[GEPGD:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[FB]] to i8*), i8** [[GEPFB:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[FC]] to i8*), i8** [[GEPFC:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[FD]] to i8*), i8** [[GEPFD:%.+]], align
- // CHECK-DAG: [[GEPB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
+ // CHECK-DAG: [[VALLB:%.+]] = load i16, i16* [[LB]],
+ // CHECK-64-DAG: [[VALGB:%.+]] = load double, double* @Gb,
+ // CHECK-DAG: [[VALFB:%.+]] = load float, float* @_ZZ3foossssE2Sb,
+ // CHECK-64-DAG: [[VALGC:%.+]] = load double, double* @Gc,
+ // CHECK-DAG: [[VALLC:%.+]] = load i16, i16* [[LC]],
+ // CHECK-DAG: [[VALFC:%.+]] = load float, float* @_ZZ3foossssE2Sc,
+ // CHECK-DAG: [[VALLD:%.+]] = load i16, i16* [[LD]],
+ // CHECK-64-DAG: [[VALGD:%.+]] = load double, double* @Gd,
+ // CHECK-DAG: [[VALFD:%.+]] = load float, float* @_ZZ3foossssE2Sd,
+
+ // 3 local vars being captured.
+
+ // CHECK-DAG: store i16 [[VALLB]], i16* [[CONVLB:%.+]],
+ // CHECK-DAG: [[CONVLB]] = bitcast i[[sz:64|32]]* [[CADDRLB:%.+]] to i16*
+ // CHECK-DAG: [[CVALLB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLB]],
+ // CHECK-DAG: [[CPTRLB:%.+]] = inttoptr i[[sz]] [[CVALLB]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLB]], i8** [[GEPLB:%.+]],
+ // CHECK-DAG: [[GEPLB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store i16 [[VALLC]], i16* [[CONVLC:%.+]],
+ // CHECK-DAG: [[CONVLC]] = bitcast i[[sz]]* [[CADDRLC:%.+]] to i16*
+ // CHECK-DAG: [[CVALLC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLC]],
+ // CHECK-DAG: [[CPTRLC:%.+]] = inttoptr i[[sz]] [[CVALLC]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLC]], i8** [[GEPLC:%.+]],
+ // CHECK-DAG: [[GEPLC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store i16 [[VALLD]], i16* [[CONVLD:%.+]],
+ // CHECK-DAG: [[CONVLD]] = bitcast i[[sz]]* [[CADDRLD:%.+]] to i16*
+ // CHECK-DAG: [[CVALLD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLD]],
+ // CHECK-DAG: [[CPTRLD:%.+]] = inttoptr i[[sz]] [[CVALLD]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLD]], i8** [[GEPLD:%.+]],
+ // CHECK-DAG: [[GEPLD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // 3 static vars being captured.
+
+ // CHECK-DAG: store float [[VALFB]], float* [[CONVFB:%.+]],
+ // CHECK-DAG: [[CONVFB]] = bitcast i[[sz]]* [[CADDRFB:%.+]] to float*
+ // CHECK-DAG: [[CVALFB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFB]],
+ // CHECK-DAG: [[CPTRFB:%.+]] = inttoptr i[[sz]] [[CVALFB]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFB]], i8** [[GEPFB:%.+]],
+ // CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store float [[VALFC]], float* [[CONVFC:%.+]],
+ // CHECK-DAG: [[CONVFC]] = bitcast i[[sz]]* [[CADDRFC:%.+]] to float*
+ // CHECK-DAG: [[CVALFC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFC]],
+ // CHECK-DAG: [[CPTRFC:%.+]] = inttoptr i[[sz]] [[CVALFC]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFC]], i8** [[GEPFC:%.+]],
+ // CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store float [[VALFD]], float* [[CONVFD:%.+]],
+ // CHECK-DAG: [[CONVFD]] = bitcast i[[sz]]* [[CADDRFD:%.+]] to float*
+ // CHECK-DAG: [[CVALFD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFD]],
+ // CHECK-DAG: [[CPTRFD:%.+]] = inttoptr i[[sz]] [[CVALFD]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFD]], i8** [[GEPFD:%.+]],
+ // CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // 3 static global vars being captured.
+
+ // CHECK-64-DAG: store double [[VALGB]], double* [[CONVGB:%.+]],
+ // CHECK-64-DAG: [[CONVGB]] = bitcast i[[sz]]* [[CADDRGB:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGB]],
+ // CHECK-64-DAG: [[CPTRGB:%.+]] = inttoptr i[[sz]] [[CVALGB]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGB]], i8** [[GEPGB:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gb to i8*), i8** [[GEPGB:%.+]],
+ // CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-64-DAG: store double [[VALGC]], double* [[CONVGC:%.+]],
+ // CHECK-64-DAG: [[CONVGC]] = bitcast i[[sz]]* [[CADDRGC:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGC]],
+ // CHECK-64-DAG: [[CPTRGC:%.+]] = inttoptr i[[sz]] [[CVALGC]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGC]], i8** [[GEPGC:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gc to i8*), i8** [[GEPGC:%.+]],
+ // CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-64-DAG: store double [[VALGD]], double* [[CONVGD:%.+]],
+ // CHECK-64-DAG: [[CONVGD]] = bitcast i[[sz]]* [[CADDRGD:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGD]],
+ // CHECK-64-DAG: [[CPTRGD:%.+]] = inttoptr i[[sz]] [[CVALGD]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGD]], i8** [[GEPGD:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gd to i8*), i8** [[GEPGD:%.+]],
+ // CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
// CHECK: call i32 @__tgt_target
// CHECK: call void [[OFFLOADF:@.+]](
// Capture b, Gb, Sb, Gc, c, Sc, d, Gd, Sd
@@ -71,7 +132,7 @@
Gb += 1.0;
Sb += 1.0;
- // CHECK: define internal void [[OFFLOADF]]({{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}})
+ // CHECK: define internal void [[OFFLOADF]]({{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}})
// The parallel region only uses 3 captures.
// CHECK: call {{.*}}@__kmpc_fork_call(%ident_t* {{.+}}, i32 {{.+}}, void (i32*, i32*, ...)* bitcast ({{.*}}[[PARF:@.+]] to {{.*}}), {{.+}}* %{{.+}}, {{.+}}* %{{.+}}, {{.+}}* %{{.+}})
// CHECK: call void @.omp_outlined.(i32* %{{.+}}, i32* %{{.+}}, {{.+}}* %{{.+}}, {{.+}}* %{{.+}}, {{.+}}* %{{.+}})
@@ -106,45 +167,98 @@
// CHECK: call void {{.*}}@__kmpc_fork_call(%ident_t* {{.+}}, i32 {{.+}}, void (i32*, i32*, ...)* bitcast ({{.*}}[[PARF:@.+]] to {{.*}}), i16* %{{.+}}, i16* %{{.+}}, i16* %{{.+}}, i16* %{{.+}})
// CHECK: define internal void [[PARF]](i32* noalias %{{.*}}, i32* noalias %{{.*}}, i16* dereferenceable(2) [[A:%.+]], i16* dereferenceable(2) [[B:%.+]], i16* dereferenceable(2) [[C:%.+]], i16* dereferenceable(2) [[D:%.+]])
// Capture a, b, c, d
+ // CHECK: [[ALLOCLA:%.+]] = alloca i16
+ // CHECK: [[ALLOCLB:%.+]] = alloca i16
+ // CHECK: [[ALLOCLC:%.+]] = alloca i16
+ // CHECK: [[ALLOCLD:%.+]] = alloca i16
+ // CHECK: [[LLA:%.+]] = load i16*, i16** [[ALLOCLA]],
+ // CHECK: [[LLB:%.+]] = load i16*, i16** [[ALLOCLB]],
+ // CHECK: [[LLC:%.+]] = load i16*, i16** [[ALLOCLC]],
+ // CHECK: [[LLD:%.+]] = load i16*, i16** [[ALLOCLD]],
#pragma omp parallel
{
- // CHECK: [[ADRA:%.+]] = alloca i16*, align
- // CHECK: [[ADRB:%.+]] = alloca i16*, align
- // CHECK: [[ADRC:%.+]] = alloca i16*, align
- // CHECK: [[ADRD:%.+]] = alloca i16*, align
- // CHECK: store i16* [[A]], i16** [[ADRA]], align
- // CHECK: store i16* [[B]], i16** [[ADRB]], align
- // CHECK: store i16* [[C]], i16** [[ADRC]], align
- // CHECK: store i16* [[D]], i16** [[ADRD]], align
- // CHECK: [[REFA:%.+]] = load i16*, i16** [[ADRA]],
- // CHECK: [[REFB:%.+]] = load i16*, i16** [[ADRB]],
- // CHECK: [[REFC:%.+]] = load i16*, i16** [[ADRC]],
- // CHECK: [[REFD:%.+]] = load i16*, i16** [[ADRD]],
+ // CHECK-DAG: [[VALLB:%.+]] = load i16, i16* [[LLB]],
+ // CHECK-64-DAG: [[VALGB:%.+]] = load double, double* @Gb,
+ // CHECK-DAG: [[VALFB:%.+]] = load float, float* @_ZZ3barssssE2Sb,
+ // CHECK-64-DAG: [[VALGC:%.+]] = load double, double* @Gc,
+ // CHECK-DAG: [[VALLC:%.+]] = load i16, i16* [[LLC]],
+ // CHECK-DAG: [[VALFC:%.+]] = load float, float* @_ZZ3barssssE2Sc,
+ // CHECK-DAG: [[VALLD:%.+]] = load i16, i16* [[LLD]],
+ // CHECK-64-DAG: [[VALGD:%.+]] = load double, double* @Gd,
+ // CHECK-DAG: [[VALFD:%.+]] = load float, float* @_ZZ3barssssE2Sd,
- // CHECK: load float, float* [[BA]]
+ // 3 local vars being captured.
- // CHECK-DAG: [[CSTB:%.+]] = bitcast i16* [[REFB]] to i8*
- // CHECK-DAG: [[CSTC:%.+]] = bitcast i16* [[REFC]] to i8*
- // CHECK-DAG: [[CSTD:%.+]] = bitcast i16* [[REFD]] to i8*
- // CHECK-DAG: store i8* [[CSTB]], i8** [[GEPB:%.+]], align
- // CHECK-DAG: store i8* [[CSTC]], i8** [[GEPC:%.+]], align
- // CHECK-DAG: store i8* [[CSTD]], i8** [[GEPD:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GB]] to i8*), i8** [[GEPGB:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GC]] to i8*), i8** [[GEPGC:%.+]], align
- // CHECK-DAG: store i8* bitcast (double* [[GD]] to i8*), i8** [[GEPGD:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[BB]] to i8*), i8** [[GEPBB:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[BC]] to i8*), i8** [[GEPBC:%.+]], align
- // CHECK-DAG: store i8* bitcast (float* [[BD]] to i8*), i8** [[GEPBD:%.+]], align
+ // CHECK-DAG: store i16 [[VALLB]], i16* [[CONVLB:%.+]],
+ // CHECK-DAG: [[CONVLB]] = bitcast i[[sz:64|32]]* [[CADDRLB:%.+]] to i16*
+ // CHECK-DAG: [[CVALLB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLB]],
+ // CHECK-DAG: [[CPTRLB:%.+]] = inttoptr i[[sz]] [[CVALLB]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLB]], i8** [[GEPLB:%.+]],
+ // CHECK-DAG: [[GEPLB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
- // CHECK-DAG: [[GEPB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPBB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPBC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
- // CHECK-DAG: [[GEPBD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{.+}}
+ // CHECK-DAG: store i16 [[VALLC]], i16* [[CONVLC:%.+]],
+ // CHECK-DAG: [[CONVLC]] = bitcast i[[sz]]* [[CADDRLC:%.+]] to i16*
+ // CHECK-DAG: [[CVALLC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLC]],
+ // CHECK-DAG: [[CPTRLC:%.+]] = inttoptr i[[sz]] [[CVALLC]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLC]], i8** [[GEPLC:%.+]],
+ // CHECK-DAG: [[GEPLC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store i16 [[VALLD]], i16* [[CONVLD:%.+]],
+ // CHECK-DAG: [[CONVLD]] = bitcast i[[sz]]* [[CADDRLD:%.+]] to i16*
+ // CHECK-DAG: [[CVALLD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLD]],
+ // CHECK-DAG: [[CPTRLD:%.+]] = inttoptr i[[sz]] [[CVALLD]] to i8*
+ // CHECK-DAG: store i8* [[CPTRLD]], i8** [[GEPLD:%.+]],
+ // CHECK-DAG: [[GEPLD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // 3 static vars being captured.
+
+ // CHECK-DAG: store float [[VALFB]], float* [[CONVFB:%.+]],
+ // CHECK-DAG: [[CONVFB]] = bitcast i[[sz]]* [[CADDRFB:%.+]] to float*
+ // CHECK-DAG: [[CVALFB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFB]],
+ // CHECK-DAG: [[CPTRFB:%.+]] = inttoptr i[[sz]] [[CVALFB]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFB]], i8** [[GEPFB:%.+]],
+ // CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store float [[VALFC]], float* [[CONVFC:%.+]],
+ // CHECK-DAG: [[CONVFC]] = bitcast i[[sz]]* [[CADDRFC:%.+]] to float*
+ // CHECK-DAG: [[CVALFC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFC]],
+ // CHECK-DAG: [[CPTRFC:%.+]] = inttoptr i[[sz]] [[CVALFC]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFC]], i8** [[GEPFC:%.+]],
+ // CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-DAG: store float [[VALFD]], float* [[CONVFD:%.+]],
+ // CHECK-DAG: [[CONVFD]] = bitcast i[[sz]]* [[CADDRFD:%.+]] to float*
+ // CHECK-DAG: [[CVALFD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFD]],
+ // CHECK-DAG: [[CPTRFD:%.+]] = inttoptr i[[sz]] [[CVALFD]] to i8*
+ // CHECK-DAG: store i8* [[CPTRFD]], i8** [[GEPFD:%.+]],
+ // CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // 3 static global vars being captured.
+
+ // CHECK-64-DAG: store double [[VALGB]], double* [[CONVGB:%.+]],
+ // CHECK-64-DAG: [[CONVGB]] = bitcast i[[sz]]* [[CADDRGB:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGB]],
+ // CHECK-64-DAG: [[CPTRGB:%.+]] = inttoptr i[[sz]] [[CVALGB]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGB]], i8** [[GEPGB:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gb to i8*), i8** [[GEPGB:%.+]],
+ // CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-64-DAG: store double [[VALGC]], double* [[CONVGC:%.+]],
+ // CHECK-64-DAG: [[CONVGC]] = bitcast i[[sz]]* [[CADDRGC:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGC]],
+ // CHECK-64-DAG: [[CPTRGC:%.+]] = inttoptr i[[sz]] [[CVALGC]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGC]], i8** [[GEPGC:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gc to i8*), i8** [[GEPGC:%.+]],
+ // CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
+ // CHECK-64-DAG: store double [[VALGD]], double* [[CONVGD:%.+]],
+ // CHECK-64-DAG: [[CONVGD]] = bitcast i[[sz]]* [[CADDRGD:%.+]] to double*
+ // CHECK-64-DAG: [[CVALGD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGD]],
+ // CHECK-64-DAG: [[CPTRGD:%.+]] = inttoptr i[[sz]] [[CVALGD]] to i8*
+ // CHECK-64-DAG: store i8* [[CPTRGD]], i8** [[GEPGD:%.+]],
+ // CHECK-32-DAG: store i8* bitcast (double* @Gd to i8*), i8** [[GEPGD:%.+]],
+ // CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
+
// CHECK: call i32 @__tgt_target
// CHECK: call void [[OFFLOADF:@.+]](
// Capture b, Gb, Sb, Gc, c, Sc, d, Gd, Sd
@@ -154,7 +268,7 @@
Gb += 1.0;
Sb += 1.0;
- // CHECK: define internal void [[OFFLOADF]]({{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}}, {{.+}}* {{.*}}%{{.+}})
+ // CHECK: define internal void [[OFFLOADF]]({{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}}, {{.+}} {{.*}}%{{.+}})
// CHECK: call void {{.*}}@__kmpc_fork_call(%ident_t* {{.+}}, i32 {{.+}}, void (i32*, i32*, ...)* bitcast ({{.*}}[[PARF:@.+]] to {{.*}})
// CHECK: define internal void [[PARF]](i32* noalias %{{.*}}, i32* noalias %{{.*}}, {{.+}}* dereferenceable({{.+}}) %{{.+}}, {{.+}}* dereferenceable({{.+}}) %{{.+}}, {{.+}}* dereferenceable({{.+}}) %{{.+}})
diff --git a/test/OpenMP/target_codegen_registration.cpp b/test/OpenMP/target_codegen_registration.cpp
new file mode 100644
index 0000000..7d515bb
--- /dev/null
+++ b/test/OpenMP/target_codegen_registration.cpp
@@ -0,0 +1,437 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// Check that no target code is emmitted if no omptests flag was provided.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-NTARGET
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]] }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]] }
+
+// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
+// CHECK-DAG: [[A2:@.+]] = global [[SA]]
+// CHECK-DAG: [[B1:@.+]] = global [[SB]]
+// CHECK-DAG: [[B2:@.+]] = global [[SB]]
+// CHECK-DAG: [[C1:@.+]] = internal global [[SC]]
+// CHECK-DAG: [[D1:@.+]] = global [[SD]]
+// CHECK-DAG: [[E1:@.+]] = global [[SE]]
+// CHECK-DAG: [[T1:@.+]] = global [[ST1]]
+// CHECK-DAG: [[T2:@.+]] = global [[ST2]]
+
+// CHECK-NTARGET-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-NTARGET-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-NTARGET-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-NTARGET-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-NTARGET-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-NTARGET-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-NTARGET-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-NTARGET-NOT: type { i8*,
+// CHECK-NTARGET-NOT: type { i32,
+
+// We have 7 target regions
+
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// TCHECK-NOT: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 128]
+
+// CHECK-NTARGET-NOT: private constant i8 0
+// CHECK-NTARGET-NOT: private unnamed_addr constant [1 x i
+
+// CHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:\.omp_offloading\.[0-9a-f]+\.[0-9a-f]+\._Z.+\.l[0-9]+\.c[0-9]+]]\00"
+// CHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// CHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// CHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// CHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// CHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// CHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// CHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// CHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// CHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// CHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// CHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// CHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+
+// TCHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:\.omp_offloading\.[0-9a-f]+\.[0-9a-f]+\._Z.+\.l[0-9]+\.c[0-9]+]]\00"
+// TCHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// TCHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// TCHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// TCHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// TCHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// TCHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// TCHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// TCHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// TCHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// TCHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// TCHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// TCHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0 }, section ".omp_offloading.entries", align 1
+
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// We have 4 initializers, one for the 500 priority, another one for 501, or more for the default priority, and the last one for the offloading registration function.
+// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [
+// CHECK-SAME: { i32, void ()*, i8* } { i32 500, void ()* [[P500:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 501, void ()* [[P501:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 65535, void ()* [[PMAX:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
+
+extern int *R;
+
+struct SA {
+ int arr[4];
+ void foo() {
+ int a = *R;
+ a += 1;
+ *R = a;
+ }
+ SA() {
+ int a = *R;
+ a += 2;
+ *R = a;
+ }
+ ~SA() {
+ int a = *R;
+ a += 3;
+ *R = a;
+ }
+};
+
+struct SB {
+ int arr[8];
+ void foo() {
+ int a = *R;
+ #pragma omp target
+ a += 4;
+ *R = a;
+ }
+ SB() {
+ int a = *R;
+ a += 5;
+ *R = a;
+ }
+ ~SB() {
+ int a = *R;
+ a += 6;
+ *R = a;
+ }
+};
+
+struct SC {
+ int arr[16];
+ void foo() {
+ int a = *R;
+ a += 7;
+ *R = a;
+ }
+ SC() {
+ int a = *R;
+ #pragma omp target
+ a += 8;
+ *R = a;
+ }
+ ~SC() {
+ int a = *R;
+ a += 9;
+ *R = a;
+ }
+};
+
+struct SD {
+ int arr[32];
+ void foo() {
+ int a = *R;
+ a += 10;
+ *R = a;
+ }
+ SD() {
+ int a = *R;
+ a += 11;
+ *R = a;
+ }
+ ~SD() {
+ int a = *R;
+ #pragma omp target
+ a += 12;
+ *R = a;
+ }
+};
+
+struct SE {
+ int arr[64];
+ void foo() {
+ int a = *R;
+ #pragma omp target if(0)
+ a += 13;
+ *R = a;
+ }
+ SE() {
+ int a = *R;
+ #pragma omp target
+ a += 14;
+ *R = a;
+ }
+ ~SE() {
+ int a = *R;
+ #pragma omp target
+ a += 15;
+ *R = a;
+ }
+};
+
+template <int x>
+struct ST {
+ int arr[128 + x];
+ void foo() {
+ int a = *R;
+ #pragma omp target
+ a += 16 + x;
+ *R = a;
+ }
+ ST() {
+ int a = *R;
+ #pragma omp target
+ a += 17 + x;
+ *R = a;
+ }
+ ~ST() {
+ int a = *R;
+ #pragma omp target
+ a += 18 + x;
+ *R = a;
+ }
+};
+
+// We have to make sure we us all the target regions:
+//CHECK-DAG: define internal void @[[NAME1]](
+//CHECK-DAG: call void @[[NAME1]](
+//CHECK-DAG: define internal void @[[NAME2]](
+//CHECK-DAG: call void @[[NAME2]](
+//CHECK-DAG: define internal void @[[NAME3]](
+//CHECK-DAG: call void @[[NAME3]](
+//CHECK-DAG: define internal void @[[NAME4]](
+//CHECK-DAG: call void @[[NAME4]](
+//CHECK-DAG: define internal void @[[NAME5]](
+//CHECK-DAG: call void @[[NAME5]](
+//CHECK-DAG: define internal void @[[NAME6]](
+//CHECK-DAG: call void @[[NAME6]](
+//CHECK-DAG: define internal void @[[NAME7]](
+//CHECK-DAG: call void @[[NAME7]](
+//CHECK-DAG: define internal void @[[NAME8]](
+//CHECK-DAG: call void @[[NAME8]](
+//CHECK-DAG: define internal void @[[NAME9]](
+//CHECK-DAG: call void @[[NAME9]](
+//CHECK-DAG: define internal void @[[NAME10]](
+//CHECK-DAG: call void @[[NAME10]](
+//CHECK-DAG: define internal void @[[NAME11]](
+//CHECK-DAG: call void @[[NAME11]](
+//CHECK-DAG: define internal void @[[NAME12]](
+//CHECK-DAG: call void @[[NAME12]](
+
+//TCHECK-DAG: define void @[[NAME1]](
+//TCHECK-DAG: define void @[[NAME2]](
+//TCHECK-DAG: define void @[[NAME3]](
+//TCHECK-DAG: define void @[[NAME4]](
+//TCHECK-DAG: define void @[[NAME5]](
+//TCHECK-DAG: define void @[[NAME6]](
+//TCHECK-DAG: define void @[[NAME7]](
+//TCHECK-DAG: define void @[[NAME8]](
+//TCHECK-DAG: define void @[[NAME9]](
+//TCHECK-DAG: define void @[[NAME10]](
+//TCHECK-DAG: define void @[[NAME11]](
+//TCHECK-DAG: define void @[[NAME12]](
+
+// CHECK-NTARGET-NOT: __tgt_target
+// CHECK-NTARGET-NOT: __tgt_register_lib
+// CHECK-NTARGET-NOT: __tgt_unregister_lib
+
+// TCHECK-NOT: __tgt_target
+// TCHECK-NOT: __tgt_register_lib
+// TCHECK-NOT: __tgt_unregister_lib
+
+// We have 2 initializers with priority 500
+//CHECK: define internal void [[P500]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 1 initializers with priority 501
+//CHECK: define internal void [[P501]](
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 6 initializers with default priority
+//CHECK: define internal void [[PMAX]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// Check registration and unregistration
+
+//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: call i32 @__tgt_unregister_lib([[DSCTY]]* [[DESC]])
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_unregister_lib([[DSCTY]]*)
+
+//CHECK: define internal void [[REGFN]](i8*)
+//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
+//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
+
+static __attribute__((init_priority(500))) SA a1;
+SA a2;
+SB __attribute__((init_priority(500))) b1;
+SB __attribute__((init_priority(501))) b2;
+static SC c1;
+SD d1;
+SE e1;
+ST<100> t1;
+ST<1000> t2;
+
+
+int bar(int a){
+ int r = a;
+
+ a1.foo();
+ a2.foo();
+ b1.foo();
+ b2.foo();
+ c1.foo();
+ d1.foo();
+ e1.foo();
+ t1.foo();
+ t2.foo();
+
+ #pragma omp target
+ ++r;
+
+ return r + *R;
+}
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 11, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 13, i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 11, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 13, i32 {{[0-9]+}}}
+
+#endif
diff --git a/test/OpenMP/target_codegen_registration_naming.cpp b/test/OpenMP/target_codegen_registration_naming.cpp
new file mode 100644
index 0000000..ab7a469
--- /dev/null
+++ b/test/OpenMP/target_codegen_registration_naming.cpp
@@ -0,0 +1,66 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -omptargets=powerpc64le-ibm-linux-gnu -fopenmp-is-device -omp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -omptargets=i386-pc-linux-gnu -fopenmp-is-device -omp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[CA:%.+]] = type { i32* }
+
+// CHECK: define {{.*}}i32 @[[NNAME:.+]](i32 {{.*}}%{{.+}})
+int nested(int a){
+ // CHECK: call void @.omp_offloading.[[FILEID:[0-9a-f]+\.[0-9a-f]+]].[[NNAME]].l[[T1L:[0-9]+]].c[[T1C:[0-9]+]](
+ #pragma omp target
+ ++a;
+
+ // CHECK: call void @"[[LNAME:.+]]"([[CA]]*
+ auto F = [&](){
+ #pragma omp parallel
+ {
+ #pragma omp target
+ ++a;
+ }
+ };
+
+ F();
+
+ return a;
+}
+
+// CHECK: define {{.*}}void @.omp_offloading.[[FILEID]].[[NNAME]].l[[T1L]].c[[T1C]](
+// TCHECK: define {{.*}}void @.omp_offloading.[[FILEID:[0-9a-f]+\.[0-9a-f]+]].[[NNAME:.+]].l[[T1L:[0-9]+]].c[[T1C:[0-9]+]](
+
+// CHECK: define {{.*}}void @"[[LNAME]]"(
+// CHECK: call void {{.*}}@__kmpc_fork_call{{.+}}[[PNAME:@.+]] to
+
+// CHECK: define {{.*}}void [[PNAME]](
+// CHECK: call void @.omp_offloading.[[FILEID]].[[NNAME]].l[[T2L:[0-9]+]].c[[T2C:[0-9]+]](
+
+// CHECK: define {{.*}}void @.omp_offloading.[[FILEID]].[[NNAME]].l[[T2L]].c[[T2C]](
+// TCHECK: define {{.*}}void @.omp_offloading.[[FILEID]].[[NNAME:.+]].l[[T2L:[0-9]+]].c[[T2C:[0-9]+]](
+
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
+#endif
diff --git a/test/OpenMP/target_data_ast_print.cpp b/test/OpenMP/target_data_ast_print.cpp
index 06b4616..cdff857 100644
--- a/test/OpenMP/target_data_ast_print.cpp
+++ b/test/OpenMP/target_data_ast_print.cpp
@@ -8,8 +8,113 @@
void foo() {}
+template <typename T, int C>
+T tmain(T argc, T *argv) {
+ T i, j, b, c, d, e, x[20];
+
+#pragma omp target data
+ i = argc;
+
+#pragma omp target data if (target data: j > 0)
+ foo();
+
+#pragma omp target data if (b)
+ foo();
+
+#pragma omp target data map(c)
+ foo();
+
+#pragma omp target data map(c) if(b>e)
+ foo();
+
+#pragma omp target data map(x[0:10], c)
+ foo();
+
+#pragma omp target data map(to: c) map(from: d)
+ foo();
+
+#pragma omp target data map(always,alloc: e)
+ foo();
+
+// nesting a target region
+#pragma omp target data map(e)
+{
+ #pragma omp target map(always, alloc: e)
+ foo();
+}
+
+ return 0;
+}
+
+// CHECK: template <typename T = int, int C = 5> int tmain(int argc, int *argv) {
+// CHECK-NEXT: int i, j, b, c, d, e, x[20];
+// CHECK-NEXT: #pragma omp target data
+// CHECK-NEXT: i = argc;
+// CHECK-NEXT: #pragma omp target data if(target data: j > 0)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data if(b)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c) if(b > e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: x[0:10],c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(to: c) map(from: d)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(always,alloc: e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: e)
+// CHECK-NEXT: {
+// CHECK-NEXT: #pragma omp target map(always,alloc: e)
+// CHECK-NEXT: foo();
+// CHECK: template <typename T = char, int C = 1> char tmain(char argc, char *argv) {
+// CHECK-NEXT: char i, j, b, c, d, e, x[20];
+// CHECK-NEXT: #pragma omp target data
+// CHECK-NEXT: i = argc;
+// CHECK-NEXT: #pragma omp target data if(target data: j > 0)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data if(b)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c) if(b > e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: x[0:10],c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(to: c) map(from: d)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(always,alloc: e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: e)
+// CHECK-NEXT: {
+// CHECK-NEXT: #pragma omp target map(always,alloc: e)
+// CHECK-NEXT: foo();
+// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
+// CHECK-NEXT: T i, j, b, c, d, e, x[20];
+// CHECK-NEXT: #pragma omp target data
+// CHECK-NEXT: i = argc;
+// CHECK-NEXT: #pragma omp target data if(target data: j > 0)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data if(b)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: c) if(b > e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: x[0:10],c)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(to: c) map(from: d)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(always,alloc: e)
+// CHECK-NEXT: foo();
+// CHECK-NEXT: #pragma omp target data map(tofrom: e)
+// CHECK-NEXT: {
+// CHECK-NEXT: #pragma omp target map(always,alloc: e)
+// CHECK-NEXT: foo();
+
int main (int argc, char **argv) {
- int b = argc, c, d, e, f, g;
+ int b = argc, c, d, e, f, g, x[20];
static int a;
// CHECK: static int a;
@@ -27,7 +132,42 @@
foo();
// CHECK-NEXT: foo();
- return (0);
+#pragma omp target data map(c)
+// CHECK-NEXT: #pragma omp target data map(tofrom: c)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target data map(c) if(b>g)
+// CHECK-NEXT: #pragma omp target data map(tofrom: c) if(b > g)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target data map(x[0:10], c)
+// CHECK-NEXT: #pragma omp target data map(tofrom: x[0:10],c)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target data map(to: c) map(from: d)
+// CHECK-NEXT: #pragma omp target data map(to: c) map(from: d)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target data map(always,alloc: e)
+// CHECK-NEXT: #pragma omp target data map(always,alloc: e)
+ foo();
+// CHECK-NEXT: foo();
+
+// nesting a target region
+#pragma omp target data map(e)
+// CHECK-NEXT: #pragma omp target data map(tofrom: e)
+{
+// CHECK-NEXT: {
+ #pragma omp target map(always, alloc: e)
+// CHECK-NEXT: #pragma omp target map(always,alloc: e)
+ foo();
+// CHECK-NEXT: foo();
+}
+ return tmain<int, 5>(argc, &argc) + tmain<char, 1>(argv[0][0], argv[0]);
}
#endif
diff --git a/test/OpenMP/target_data_device_messages.cpp b/test/OpenMP/target_data_device_messages.cpp
index 6544a14..9e8e31a 100644
--- a/test/OpenMP/target_data_device_messages.cpp
+++ b/test/OpenMP/target_data_device_messages.cpp
@@ -19,7 +19,7 @@
#pragma omp target data device (argc + argc)
#pragma omp target data device (argc), device (argc+1) // expected-error {{directive '#pragma omp target data' cannot contain more than one 'device' clause}}
#pragma omp target data device (S1) // expected-error {{'S1' does not refer to a value}}
- #pragma omp target data device (-2) // expected-error {{argument to 'device' clause must be a positive integer value}}
+ #pragma omp target data device (-2) // expected-error {{argument to 'device' clause must be a non-negative integer value}}
#pragma omp target device (-10u)
#pragma omp target device (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
foo();
diff --git a/test/OpenMP/target_device_messages.cpp b/test/OpenMP/target_device_messages.cpp
index 53ae8c5..fb0f2de 100644
--- a/test/OpenMP/target_device_messages.cpp
+++ b/test/OpenMP/target_device_messages.cpp
@@ -19,7 +19,7 @@
#pragma omp target device (argc + argc)
#pragma omp target device (argc), device (argc+1) // expected-error {{directive '#pragma omp target' cannot contain more than one 'device' clause}}
#pragma omp target device (S1) // expected-error {{'S1' does not refer to a value}}
- #pragma omp target device (-2) // expected-error {{argument to 'device' clause must be a positive integer value}}
+ #pragma omp target device (-2) // expected-error {{argument to 'device' clause must be a non-negative integer value}}
#pragma omp target device (-10u)
#pragma omp target device (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
foo();
diff --git a/test/OpenMP/target_map_codegen.cpp b/test/OpenMP/target_map_codegen.cpp
new file mode 100644
index 0000000..942cc4c
--- /dev/null
+++ b/test/OpenMP/target_map_codegen.cpp
@@ -0,0 +1,1015 @@
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+///
+/// Implicit maps.
+///
+
+///==========================================================================///
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
+// RUN: %clang_cc1 -DCK1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
+#ifdef CK1
+
+// CK1-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK1-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK1-LABEL: implicit_maps_integer
+void implicit_maps_integer (int a){
+ int i = a;
+
+ // CK1-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK1-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK1-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK1-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK1-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK1-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK1-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK1: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ ++i;
+ }
+}
+
+// CK1: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK1: [[ADDR:%.+]] = alloca i[[sz]],
+// CK1: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK1-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK1-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK1-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-32
+// RUN: %clang_cc1 -DCK2 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-32
+#ifdef CK2
+
+// CK2-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK2-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK2-LABEL: implicit_maps_integer_reference
+void implicit_maps_integer_reference (int a){
+ int &i = a;
+ // CK2-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK2-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK2-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK2-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK2-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK2-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK2-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK2-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK2-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK2-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK2: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ ++i;
+ }
+}
+
+// CK2: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK2: [[ADDR:%.+]] = alloca i[[sz]],
+// CK2: [[REF:%.+]] = alloca i32*,
+// CK2: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK2-64: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+// CK2-64: store i32* [[CADDR]], i32** [[REF]],
+// CK2-64: [[RVAL:%.+]] = load i32*, i32** [[REF]],
+// CK2-64: {{.+}} = load i32, i32* [[RVAL]],
+// CK2-32: store i32* [[ADDR]], i32** [[REF]],
+// CK2-32: [[RVAL:%.+]] = load i32*, i32** [[REF]],
+// CK2-32: {{.+}} = load i32, i32* [[RVAL]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK3 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-64
+// RUN: %clang_cc1 -DCK3 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-64
+// RUN: %clang_cc1 -DCK3 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-32
+// RUN: %clang_cc1 -DCK3 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-32
+#ifdef CK3
+
+// CK3-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK3-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK3-LABEL: implicit_maps_parameter
+void implicit_maps_parameter (int a){
+
+ // CK3-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK3-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK3-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK3-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK3-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK3-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK3-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK3-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK3-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK3-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK3-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK3-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK3: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ ++a;
+ }
+}
+
+// CK3: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK3: [[ADDR:%.+]] = alloca i[[sz]],
+// CK3: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK3-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK3-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK3-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK4 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-64
+// RUN: %clang_cc1 -DCK4 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-64
+// RUN: %clang_cc1 -DCK4 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-32
+// RUN: %clang_cc1 -DCK4 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-32
+#ifdef CK4
+
+// CK4-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK4-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK4-LABEL: implicit_maps_nested_integer
+void implicit_maps_nested_integer (int a){
+ int i = a;
+
+ // The captures in parallel are by reference. Only the capture in target is by
+ // copy.
+
+ // CK4: call void {{.+}}@__kmpc_fork_call({{.+}} [[KERNELP1:@.+]] to void (i32*, i32*, ...)*), i32* {{.+}})
+ // CK4: define internal void [[KERNELP1]](i32* {{[^,]+}}, i32* {{[^,]+}}, i32* {{[^,]+}})
+ #pragma omp parallel
+ {
+ // CK4-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK4-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK4-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK4-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK4-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK4-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK4-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK4-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK4-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK4-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK4-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK4-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK4: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ #pragma omp parallel
+ {
+ ++i;
+ }
+ }
+ }
+}
+
+// CK4: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK4: [[ADDR:%.+]] = alloca i[[sz]],
+// CK4: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK4-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK4-64: call void {{.+}}@__kmpc_fork_call({{.+}} [[KERNELP2:@.+]] to void (i32*, i32*, ...)*), i32* [[CADDR]])
+// CK4-32: call void {{.+}}@__kmpc_fork_call({{.+}} [[KERNELP2:@.+]] to void (i32*, i32*, ...)*), i32* [[ADDR]])
+// CK4: define internal void [[KERNELP2]](i32* {{[^,]+}}, i32* {{[^,]+}}, i32* {{[^,]+}})
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK5 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK5 --check-prefix CK5-64
+// RUN: %clang_cc1 -DCK5 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK5 --check-prefix CK5-64
+// RUN: %clang_cc1 -DCK5 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK5 --check-prefix CK5-32
+// RUN: %clang_cc1 -DCK5 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK5 --check-prefix CK5-32
+#ifdef CK5
+
+// CK5-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK5-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK5-LABEL: implicit_maps_nested_integer_and_enum
+void implicit_maps_nested_integer_and_enum (int a){
+ enum Bla {
+ SomeEnum = 0x09
+ };
+
+ // Using an enum should not change the mapping information.
+ int i = a;
+
+ // CK5-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK5-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK5-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK5-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK5-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK5-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK5-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK5-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK5-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK5-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK5-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK5-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK5: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ ++i;
+ i += SomeEnum;
+ }
+}
+
+// CK5: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK5: [[ADDR:%.+]] = alloca i[[sz]],
+// CK5: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK5-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK5-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK5-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK6 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK6 --check-prefix CK6-64
+// RUN: %clang_cc1 -DCK6 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK6 --check-prefix CK6-64
+// RUN: %clang_cc1 -DCK6 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK6 --check-prefix CK6-32
+// RUN: %clang_cc1 -DCK6 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK6 --check-prefix CK6-32
+#ifdef CK6
+// CK6-DAG: [[GBL:@Gi]] = global i32 0
+// CK6-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK6-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK6-LABEL: implicit_maps_host_global
+int Gi;
+void implicit_maps_host_global (int a){
+ // CK6-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK6-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK6-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK6-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK6-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK6-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK6-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK6-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK6-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK6-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK6-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK6-64-DAG: store i32 [[GBLVAL:%.+]], i32* [[CADDR]],
+ // CK6-64-DAG: [[GBLVAL]] = load i32, i32* [[GBL]],
+ // CK6-32-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[GBLVAL:%.+]],
+
+ // CK6: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ ++Gi;
+ }
+}
+
+// CK6: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK6: [[ADDR:%.+]] = alloca i[[sz]],
+// CK6: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK6-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK6-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK6-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK7 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK7 --check-prefix CK7-64
+// RUN: %clang_cc1 -DCK7 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK7 --check-prefix CK7-64
+// RUN: %clang_cc1 -DCK7 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK7 --check-prefix CK7-32
+// RUN: %clang_cc1 -DCK7 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK7 --check-prefix CK7-32
+#ifdef CK7
+
+// For a 32-bit targets, the value doesn't fit the size of the pointer,
+// therefore it is passed by reference with a map 'to' specification.
+
+// CK7-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 8]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK7-64-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+// Map types: OMP_MAP_TO = 1
+// CK7-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 1]
+
+// CK7-LABEL: implicit_maps_double
+void implicit_maps_double (int a){
+ double d = (double)a;
+
+ // CK7-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK7-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK7-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK7-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK7-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+
+ // CK7-64-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK7-64-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK7-64-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK7-64-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK7-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK7-64-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to double*
+ // CK7-64-64-DAG: store double {{.+}}, double* [[CADDR]],
+
+ // CK7-32-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK7-32-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK7-32-DAG: [[VALBP]] = bitcast double* [[DECL:%.+]] to i8*
+ // CK7-32-DAG: [[VALP]] = bitcast double* [[DECL]] to i8*
+
+ // CK7-64: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ // CK7-32: call void [[KERNEL:@.+]](double* [[DECL]])
+ #pragma omp target
+ {
+ d += 1.0;
+ }
+}
+
+// CK7-64: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK7-64: [[ADDR:%.+]] = alloca i[[sz]],
+// CK7-64: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK7-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to double*
+// CK7-64: {{.+}} = load double, double* [[CADDR]],
+
+// CK7-32: define internal void [[KERNEL]](double* {{.+}}[[ARG:%.+]])
+// CK7-32: [[ADDR:%.+]] = alloca double*,
+// CK7-32: store double* [[ARG]], double** [[ADDR]],
+// CK7-32: [[REF:%.+]] = load double*, double** [[ADDR]],
+// CK7-32: {{.+}} = load double, double* [[REF]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK8 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK8
+// RUN: %clang_cc1 -DCK8 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK8
+// RUN: %clang_cc1 -DCK8 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK8
+// RUN: %clang_cc1 -DCK8 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK8
+#ifdef CK8
+
+// CK8-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK8-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+// CK8-LABEL: implicit_maps_float
+void implicit_maps_float (int a){
+ float f = (float)a;
+
+ // CK8-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK8-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK8-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK8-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK8-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK8-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK8-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK8-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK8-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK8-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK8-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to float*
+ // CK8-DAG: store float {{.+}}, float* [[CADDR]],
+
+ // CK8: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ #pragma omp target
+ {
+ f += 1.0;
+ }
+}
+
+// CK8: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK8: [[ADDR:%.+]] = alloca i[[sz]],
+// CK8: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK8: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to float*
+// CK8: {{.+}} = load float, float* [[CADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK9 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK9
+// RUN: %clang_cc1 -DCK9 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK9
+// RUN: %clang_cc1 -DCK9 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK9
+// RUN: %clang_cc1 -DCK9 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK9
+#ifdef CK9
+
+// CK9-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 16]
+// Map types: OMP_MAP_TO + OMP_MAP_FROM = 2 + 1
+// CK9-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 3]
+
+// CK9-LABEL: implicit_maps_array
+void implicit_maps_array (int a){
+ double darr[2] = {(double)a, (double)a};
+
+ // CK9-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK9-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK9-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK9-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK9-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK9-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK9-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK9-DAG: [[VALBP]] = bitcast [2 x double]* [[DECL:%.+]] to i8*
+ // CK9-DAG: [[VALP]] = bitcast [2 x double]* [[DECL]] to i8*
+
+ // CK9: call void [[KERNEL:@.+]]([2 x double]* [[DECL]])
+ #pragma omp target
+ {
+ darr[0] += 1.0;
+ darr[1] += 1.0;
+ }
+}
+
+// CK9: define internal void [[KERNEL]]([2 x double]* {{.+}}[[ARG:%.+]])
+// CK9: [[ADDR:%.+]] = alloca [2 x double]*,
+// CK9: store [2 x double]* [[ARG]], [2 x double]** [[ADDR]],
+// CK9: [[REF:%.+]] = load [2 x double]*, [2 x double]** [[ADDR]],
+// CK9: {{.+}} = getelementptr inbounds [2 x double], [2 x double]* [[REF]], i[[sz]] 0, i[[sz]] 0
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK10 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK10
+// RUN: %clang_cc1 -DCK10 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK10
+// RUN: %clang_cc1 -DCK10 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK10
+// RUN: %clang_cc1 -DCK10 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK10
+#ifdef CK10
+
+// CK10-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} {{8|4}}]
+// Map types: OMP_MAP_BYCOPY | OMP_MAP_PTR = 128 + 32
+// CK10-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 160]
+
+// CK10-LABEL: implicit_maps_pointer
+void implicit_maps_pointer (){
+ double *ddyn;
+
+ // CK10-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK10-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK10-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK10-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK10-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK10-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK10-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK10-DAG: [[VALBP]] = bitcast double* [[PTR:%.+]] to i8*
+ // CK10-DAG: [[VALP]] = bitcast double* [[PTR]] to i8*
+
+ // CK10: call void [[KERNEL:@.+]](double* [[PTR]])
+ #pragma omp target
+ {
+ ddyn[0] += 1.0;
+ ddyn[1] += 1.0;
+ }
+}
+
+// CK10: define internal void [[KERNEL]](double* {{.*}}[[ARG:%.+]])
+// CK10: [[ADDR:%.+]] = alloca double*,
+// CK10: store double* [[ARG]], double** [[ADDR]],
+// CK10: [[REF:%.+]] = load double*, double** [[ADDR]],
+// CK10: {{.+}} = getelementptr inbounds double, double* [[REF]], i[[sz]] 0
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK11 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK11
+// RUN: %clang_cc1 -DCK11 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK11
+// RUN: %clang_cc1 -DCK11 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK11
+// RUN: %clang_cc1 -DCK11 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK11
+#ifdef CK11
+
+// CK11-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 16]
+// Map types: OMP_MAP_TO = 1
+// CK11-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 1]
+
+// CK11-LABEL: implicit_maps_double_complex
+void implicit_maps_double_complex (int a){
+ double _Complex dc = (double)a;
+
+ // CK11-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK11-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK11-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK11-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK11-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK11-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK11-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK11-DAG: [[VALBP]] = bitcast { double, double }* [[PTR:%.+]] to i8*
+ // CK11-DAG: [[VALP]] = bitcast { double, double }* [[PTR]] to i8*
+
+ // CK11: call void [[KERNEL:@.+]]({ double, double }* [[PTR]])
+ #pragma omp target
+ {
+ dc *= dc;
+ }
+}
+
+// CK11: define internal void [[KERNEL]]({ double, double }* {{.*}}[[ARG:%.+]])
+// CK11: [[ADDR:%.+]] = alloca { double, double }*,
+// CK11: store { double, double }* [[ARG]], { double, double }** [[ADDR]],
+// CK11: [[REF:%.+]] = load { double, double }*, { double, double }** [[ADDR]],
+// CK11: {{.+}} = getelementptr inbounds { double, double }, { double, double }* [[REF]], i32 0, i32 0
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK12 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK12 --check-prefix CK12-64
+// RUN: %clang_cc1 -DCK12 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK12 --check-prefix CK12-64
+// RUN: %clang_cc1 -DCK12 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK12 --check-prefix CK12-32
+// RUN: %clang_cc1 -DCK12 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK12 --check-prefix CK12-32
+#ifdef CK12
+
+// For a 32-bit targets, the value doesn't fit the size of the pointer,
+// therefore it is passed by reference with a map 'to' specification.
+
+// CK12-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 8]
+// Map types: OMP_MAP_BYCOPY = 128
+// CK12-64-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+// Map types: OMP_MAP_TO = 1
+// CK12-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 1]
+
+// CK12-LABEL: implicit_maps_float_complex
+void implicit_maps_float_complex (int a){
+ float _Complex fc = (float)a;
+
+ // CK12-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK12-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK12-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK12-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK12-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+
+ // CK12-64-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK12-64-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK12-64-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK12-64-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK12-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK12-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to { float, float }*
+ // CK12-64-DAG: store { float, float } {{.+}}, { float, float }* [[CADDR]],
+
+ // CK12-32-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK12-32-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK12-32-DAG: [[VALBP]] = bitcast { float, float }* [[DECL:%.+]] to i8*
+ // CK12-32-DAG: [[VALP]] = bitcast { float, float }* [[DECL]] to i8*
+
+ // CK12-64: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ // CK12-32: call void [[KERNEL:@.+]]({ float, float }* [[DECL]])
+ #pragma omp target
+ {
+ fc *= fc;
+ }
+}
+
+// CK12-64: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK12-64: [[ADDR:%.+]] = alloca i[[sz]],
+// CK12-64: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK12-64: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to { float, float }*
+// CK12-64: {{.+}} = getelementptr inbounds { float, float }, { float, float }* [[CADDR]], i32 0, i32 0
+
+// CK12-32: define internal void [[KERNEL]]({ float, float }* {{.+}}[[ARG:%.+]])
+// CK12-32: [[ADDR:%.+]] = alloca { float, float }*,
+// CK12-32: store { float, float }* [[ARG]], { float, float }** [[ADDR]],
+// CK12-32: [[REF:%.+]] = load { float, float }*, { float, float }** [[ADDR]],
+// CK12-32: {{.+}} = getelementptr inbounds { float, float }, { float, float }* [[REF]], i32 0, i32 0
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK13 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK13
+// RUN: %clang_cc1 -DCK13 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK13
+// RUN: %clang_cc1 -DCK13 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK13
+// RUN: %clang_cc1 -DCK13 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK13
+#ifdef CK13
+
+// We don't have a constant map size for VLAs.
+// Map types:
+// - OMP_MAP_BYCOPY = 128 (vla size)
+// - OMP_MAP_BYCOPY = 128 (vla size)
+// - OMP_MAP_TO + OMP_MAP_FROM = 2 + 1
+// CK13-DAG: [[TYPES:@.+]] = {{.+}}constant [3 x i32] [i32 128, i32 128, i32 3]
+
+// CK13-LABEL: implicit_maps_variable_length_array
+void implicit_maps_variable_length_array (int a){
+ double vla[2][a];
+
+ // CK13-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 3, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], i[[sz:64|32]]* [[SGEP:%[^,]+]], {{.+}}[[TYPES]]{{.+}})
+ // CK13-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK13-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK13-DAG: [[SGEP]] = getelementptr inbounds {{.+}}[[SS:%[^,]+]], i32 0, i32 0
+
+ // CK13-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK13-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK13-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 0
+ // CK13-DAG: store i8* inttoptr (i[[sz]] 2 to i8*), i8** [[BP0]],
+ // CK13-DAG: store i8* inttoptr (i[[sz]] 2 to i8*), i8** [[P0]],
+ // CK13-DAG: store i[[sz]] {{8|4}}, i[[sz]]* [[S0]],
+
+ // CK13-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
+ // CK13-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
+ // CK13-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 1
+ // CK13-DAG: store i8* [[VALBP1:%.+]], i8** [[BP1]],
+ // CK13-DAG: store i8* [[VALP1:%.+]], i8** [[P1]],
+ // CK13-DAG: [[VALBP1]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK13-DAG: [[VALP1]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK13-DAG: store i[[sz]] {{8|4}}, i[[sz]]* [[S1]],
+
+ // CK13-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 2
+ // CK13-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 2
+ // CK13-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 2
+ // CK13-DAG: store i8* [[VALBP2:%.+]], i8** [[BP2]],
+ // CK13-DAG: store i8* [[VALP2:%.+]], i8** [[P2]],
+ // CK13-DAG: store i[[sz]] [[VALS2:%.+]], i[[sz]]* [[S2]],
+ // CK13-DAG: [[VALBP2]] = bitcast double* [[DECL:%.+]] to i8*
+ // CK13-DAG: [[VALP2]] = bitcast double* [[DECL]] to i8*
+ // CK13-DAG: [[VALS2]] = mul nuw i[[sz]] %{{.+}}, 8
+
+ // CK13: call void [[KERNEL:@.+]](i[[sz]] {{.+}}, i[[sz]] {{.+}}, double* [[DECL]])
+ #pragma omp target
+ {
+ vla[1][3] += 1.0;
+ }
+}
+
+// CK13: define internal void [[KERNEL]](i[[sz]] [[VLA0:%.+]], i[[sz]] [[VLA1:%.+]], double* {{.+}}[[ARG:%.+]])
+// CK13: [[ADDR0:%.+]] = alloca i[[sz]],
+// CK13: [[ADDR1:%.+]] = alloca i[[sz]],
+// CK13: [[ADDR2:%.+]] = alloca double*,
+// CK13: store i[[sz]] [[VLA0]], i[[sz]]* [[ADDR0]],
+// CK13: store i[[sz]] [[VLA1]], i[[sz]]* [[ADDR1]],
+// CK13: store double* [[ARG]], double** [[ADDR2]],
+// CK13: {{.+}} = load i[[sz]], i[[sz]]* [[ADDR0]],
+// CK13: {{.+}} = load i[[sz]], i[[sz]]* [[ADDR1]],
+// CK13: [[REF:%.+]] = load double*, double** [[ADDR2]],
+// CK13: {{.+}} = getelementptr inbounds double, double* [[REF]], i[[sz]] %{{.+}}
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK14 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK14 --check-prefix CK14-64
+// RUN: %clang_cc1 -DCK14 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK14 --check-prefix CK14-64
+// RUN: %clang_cc1 -DCK14 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK14 --check-prefix CK14-32
+// RUN: %clang_cc1 -DCK14 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK14 --check-prefix CK14-32
+#ifdef CK14
+
+// CK14-DAG: [[ST:%.+]] = type { i32, double }
+// CK14-DAG: [[SIZES:@.+]] = {{.+}}constant [2 x i[[sz:64|32]]] [i{{64|32}} {{16|12}}, i{{64|32}} 4]
+// Map types:
+// - OMP_MAP_TO | OMP_MAP_FROM = 1 + 2
+// - OMP_MAP_BYCOPY = 128
+// CK14-DAG: [[TYPES:@.+]] = {{.+}}constant [2 x i32] [i32 3, i32 128]
+
+class SSS {
+public:
+ int a;
+ double b;
+
+ void foo(int c) {
+ #pragma omp target
+ {
+ a += c;
+ b += (double)c;
+ }
+ }
+
+ SSS(int a, double b) : a(a), b(b) {}
+};
+
+// CK14-LABEL: implicit_maps_class
+void implicit_maps_class (int a){
+ SSS sss(a, (double)a);
+
+ // CK14: define {{.*}}void @{{.+}}foo{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
+ // CK14-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK14-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK14-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+
+ // CK14-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK14-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK14-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
+ // CK14-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
+ // CK14-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
+ // CK14-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+
+ // CK14-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
+ // CK14-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
+ // CK14-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK14-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK14-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK14-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK14-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK14-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK14-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK14: call void [[KERNEL:@.+]]([[ST]]* [[DECL]], i[[sz]] {{.+}})
+ sss.foo(123);
+}
+
+// CK14: define internal void [[KERNEL]]([[ST]]* [[THIS:%.+]], i[[sz]] [[ARG:%.+]])
+// CK14: [[ADDR0:%.+]] = alloca [[ST]]*,
+// CK14: [[ADDR1:%.+]] = alloca i[[sz]],
+// CK14: store [[ST]]* [[THIS]], [[ST]]** [[ADDR0]],
+// CK14: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR1]],
+// CK14: [[REF0:%.+]] = load [[ST]]*, [[ST]]** [[ADDR0]],
+// CK14-64: [[CADDR1:%.+]] = bitcast i[[sz]]* [[ADDR1]] to i32*
+// CK14-64: {{.+}} = load i32, i32* [[CADDR1]],
+// CK14-32: {{.+}} = load i32, i32* [[ADDR1]],
+// CK14: {{.+}} = getelementptr inbounds [[ST]], [[ST]]* [[REF0]], i32 0, i32 0
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK15 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK15 --check-prefix CK15-64
+// RUN: %clang_cc1 -DCK15 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK15 --check-prefix CK15-64
+// RUN: %clang_cc1 -DCK15 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK15 --check-prefix CK15-32
+// RUN: %clang_cc1 -DCK15 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK15 --check-prefix CK15-32
+#ifdef CK15
+
+// CK15: [[ST:%.+]] = type { i32, double, i32* }
+// CK15: [[SIZES:@.+]] = {{.+}}constant [2 x i[[sz:64|32]]] [i{{64|32}} {{24|16}}, i{{64|32}} 4]
+// Map types:
+// - OMP_MAP_TO | OMP_MAP_FROM = 1 + 2
+// - OMP_MAP_BYCOPY = 128
+// CK15: [[TYPES:@.+]] = {{.+}}constant [2 x i32] [i32 3, i32 128]
+
+// CK15: [[SIZES2:@.+]] = {{.+}}constant [2 x i[[sz]]] [i{{64|32}} {{24|16}}, i{{64|32}} 4]
+// Map types:
+// - OMP_MAP_TO | OMP_MAP_FROM = 1 + 2
+// - OMP_MAP_BYCOPY = 128
+// CK15: [[TYPES2:@.+]] = {{.+}}constant [2 x i32] [i32 3, i32 128]
+
+template<int x>
+class SSST {
+public:
+ int a;
+ double b;
+ int &r;
+
+ void foo(int c) {
+ #pragma omp target
+ {
+ a += c + x;
+ b += (double)(c + x);
+ r += x;
+ }
+ }
+ template<int y>
+ void bar(int c) {
+ #pragma omp target
+ {
+ a += c + x + y;
+ b += (double)(c + x + y);
+ r += x + y;
+ }
+ }
+
+ SSST(int a, double b, int &r) : a(a), b(b), r(r) {}
+};
+
+// CK15-LABEL: implicit_maps_templated_class
+void implicit_maps_templated_class (int a){
+ SSST<123> ssst(a, (double)a, a);
+
+ // CK15: define {{.*}}void @{{.+}}foo{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
+ // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK15-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK15-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+
+ // CK15-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK15-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK15-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
+ // CK15-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
+ // CK15-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
+ // CK15-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+
+ // CK15-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
+ // CK15-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
+ // CK15-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK15-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK15-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK15-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK15-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK15: call void [[KERNEL:@.+]]([[ST]]* [[DECL]], i[[sz]] {{.+}})
+ ssst.foo(456);
+
+ // CK15: define {{.*}}void @{{.+}}bar{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
+ // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES2]]{{.+}}, {{.+}}[[TYPES2]]{{.+}})
+ // CK15-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK15-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+
+ // CK15-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK15-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK15-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
+ // CK15-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
+ // CK15-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
+ // CK15-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+
+ // CK15-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
+ // CK15-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
+ // CK15-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK15-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK15-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK15-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK15-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK15: call void [[KERNEL2:@.+]]([[ST]]* [[DECL]], i[[sz]] {{.+}})
+ ssst.bar<210>(789);
+}
+
+// CK15: define internal void [[KERNEL]]([[ST]]* [[THIS:%.+]], i[[sz]] [[ARG:%.+]])
+// CK15: [[ADDR0:%.+]] = alloca [[ST]]*,
+// CK15: [[ADDR1:%.+]] = alloca i[[sz]],
+// CK15: store [[ST]]* [[THIS]], [[ST]]** [[ADDR0]],
+// CK15: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR1]],
+// CK15: [[REF0:%.+]] = load [[ST]]*, [[ST]]** [[ADDR0]],
+// CK15-64: [[CADDR1:%.+]] = bitcast i[[sz]]* [[ADDR1]] to i32*
+// CK15-64: {{.+}} = load i32, i32* [[CADDR1]],
+// CK15-32: {{.+}} = load i32, i32* [[ADDR1]],
+// CK15: {{.+}} = getelementptr inbounds [[ST]], [[ST]]* [[REF0]], i32 0, i32 0
+
+// CK15: define internal void [[KERNEL2]]([[ST]]* [[THIS:%.+]], i[[sz]] [[ARG:%.+]])
+// CK15: [[ADDR0:%.+]] = alloca [[ST]]*,
+// CK15: [[ADDR1:%.+]] = alloca i[[sz]],
+// CK15: store [[ST]]* [[THIS]], [[ST]]** [[ADDR0]],
+// CK15: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR1]],
+// CK15: [[REF0:%.+]] = load [[ST]]*, [[ST]]** [[ADDR0]],
+// CK15-64: [[CADDR1:%.+]] = bitcast i[[sz]]* [[ADDR1]] to i32*
+// CK15-64: {{.+}} = load i32, i32* [[CADDR1]],
+// CK15-32: {{.+}} = load i32, i32* [[ADDR1]],
+// CK15: {{.+}} = getelementptr inbounds [[ST]], [[ST]]* [[REF0]], i32 0, i32 0
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK16 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK16 --check-prefix CK16-64
+// RUN: %clang_cc1 -DCK16 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK16 --check-prefix CK16-64
+// RUN: %clang_cc1 -DCK16 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK16 --check-prefix CK16-32
+// RUN: %clang_cc1 -DCK16 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK16 --check-prefix CK16-32
+#ifdef CK16
+
+// CK16-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types:
+// - OMP_MAP_BYCOPY = 128
+// CK16-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+template<int y>
+int foo(int d) {
+ int res = d;
+ #pragma omp target
+ {
+ res += y;
+ }
+ return res;
+}
+// CK16-LABEL: implicit_maps_templated_function
+void implicit_maps_templated_function (int a){
+ int i = a;
+
+ // CK16: define {{.*}}i32 @{{.+}}foo{{.+}}(i32 {{[^,]+}})
+ // CK16-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK16-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK16-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+
+ // CK16-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK16-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK16-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK16-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK16-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK16-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK16-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK16-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK16-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK16: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ i = foo<543>(i);
+}
+// CK16: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK16: [[ADDR:%.+]] = alloca i[[sz]],
+// CK16: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK16-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK16-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK16-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK17 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK17
+// RUN: %clang_cc1 -DCK17 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK17
+// RUN: %clang_cc1 -DCK17 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK17
+// RUN: %clang_cc1 -DCK17 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK17
+#ifdef CK17
+
+// CK17-DAG: [[ST:%.+]] = type { i32, double }
+// CK17-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} {{16|12}}]
+// Map types: OMP_MAP_TO + OMP_MAP_FROM = 2 + 1
+// CK17-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 3]
+
+class SSS {
+public:
+ int a;
+ double b;
+};
+
+// CK17-LABEL: implicit_maps_struct
+void implicit_maps_struct (int a){
+ SSS s = {a, (double)a};
+
+ // CK17-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK17-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK17-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+ // CK17-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK17-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK17-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK17-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK17-DAG: [[VALBP]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
+ // CK17-DAG: [[VALP]] = bitcast [[ST]]* [[DECL]] to i8*
+
+ // CK17: call void [[KERNEL:@.+]]([[ST]]* [[DECL]])
+ #pragma omp target
+ {
+ s.a += 1;
+ s.b += 1.0;
+ }
+}
+
+// CK17: define internal void [[KERNEL]]([[ST]]* {{.+}}[[ARG:%.+]])
+// CK17: [[ADDR:%.+]] = alloca [[ST]]*,
+// CK17: store [[ST]]* [[ARG]], [[ST]]** [[ADDR]],
+// CK17: [[REF:%.+]] = load [[ST]]*, [[ST]]** [[ADDR]],
+// CK17: {{.+}} = getelementptr inbounds [[ST]], [[ST]]* [[REF]], i32 0, i32 0
+#endif
+///==========================================================================///
+// RUN: %clang_cc1 -DCK18 -verify -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK18 --check-prefix CK18-64
+// RUN: %clang_cc1 -DCK18 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=powerpc64le-ibm-linux-gnu -x c++ -triple powerpc64le-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK18 --check-prefix CK18-64
+// RUN: %clang_cc1 -DCK18 -verify -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix CK18 --check-prefix CK18-32
+// RUN: %clang_cc1 -DCK18 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -std=c++11 -triple i386-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -omptargets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK18 --check-prefix CK18-32
+#ifdef CK18
+
+// CK18-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
+// Map types:
+// - OMP_MAP_BYCOPY = 128
+// CK18-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 128]
+
+template<typename T>
+int foo(T d) {
+ #pragma omp target
+ {
+ d += (T)1;
+ }
+ return d;
+}
+// CK18-LABEL: implicit_maps_template_type_capture
+void implicit_maps_template_type_capture (int a){
+ int i = a;
+
+ // CK18: define {{.*}}i32 @{{.+}}foo{{.+}}(i32 {{[^,]+}})
+ // CK18-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK18-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
+ // CK18-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
+
+ // CK18-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
+ // CK18-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
+ // CK18-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
+ // CK18-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
+ // CK18-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK18-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK18-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
+ // CK18-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
+ // CK18-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
+
+ // CK18: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
+ i = foo(i);
+}
+// CK18: define internal void [[KERNEL]](i[[sz]] [[ARG:%.+]])
+// CK18: [[ADDR:%.+]] = alloca i[[sz]],
+// CK18: store i[[sz]] [[ARG]], i[[sz]]* [[ADDR]],
+// CK18-64: [[CADDR:%.+]] = bitcast i64* [[ADDR]] to i32*
+// CK18-64: {{.+}} = load i32, i32* [[CADDR]],
+// CK18-32: {{.+}} = load i32, i32* [[ADDR]],
+
+#endif
+#endif
diff --git a/test/OpenMP/target_map_messages.cpp b/test/OpenMP/target_map_messages.cpp
new file mode 100644
index 0000000..d61e766
--- /dev/null
+++ b/test/OpenMP/target_map_messages.cpp
@@ -0,0 +1,207 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+ S2(S2 &s2):a(s2.a) { }
+ static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
+ static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+ S3(S3 &s3):a(s3.a) { }
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4);
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+ S5(const S5 &s5):a(s5.a) { }
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+typedef int from;
+
+template <typename T, int I> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = 5;
+ const T da[5] = { 0 };
+ S4 e(4);
+ S5 g(5);
+ T i, t[20];
+ T &j = i;
+ T *k = &j;
+ T x;
+ T y;
+ T to, tofrom, always;
+ const T (&l)[5] = da;
+
+
+#pragma omp target map // expected-error {{expected '(' after 'map'}}
+#pragma omp target map( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+#pragma omp target map() // expected-error {{expected expression}}
+#pragma omp target map(alloc) // expected-error {{use of undeclared identifier 'alloc'}}
+#pragma omp target map(to argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected ',' or ')' in 'map' clause}}
+#pragma omp target map(to:) // expected-error {{expected expression}}
+#pragma omp target map(from: argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp target map(x: y) // expected-error {{incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'}}
+#pragma omp target map(x)
+ foo();
+#pragma omp target map(tofrom: t[:I])
+ foo();
+#pragma omp target map(T: a) // expected-error {{incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'}}
+ foo();
+#pragma omp target map(T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp target map(I) // expected-error 2 {{expected variable name, array element or array section}}
+ foo();
+#pragma omp target map(S2::S2s)
+ foo();
+#pragma omp target map(S2::S2sc)
+ foo();
+#pragma omp target map(x)
+ foo();
+#pragma omp target map(to: x)
+ foo();
+#pragma omp target map(to: to)
+ foo();
+#pragma omp target map(to)
+ foo();
+#pragma omp target map(to, x)
+ foo();
+#pragma omp target map(to x) // expected-error {{expected ',' or ')' in 'map' clause}}
+#pragma omp target map(tofrom: argc > 0 ? x : y) // expected-error 2 {{expected variable name, array element or array section}}
+#pragma omp target map(argc)
+#pragma omp target map(S1) // expected-error {{'S1' does not refer to a value}}
+#pragma omp target map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target map(ca)
+#pragma omp target map(da)
+#pragma omp target map(S2::S2s)
+#pragma omp target map(S2::S2sc)
+#pragma omp target map(e, g)
+#pragma omp target map(h) // expected-error {{threadprivate variables are not allowed in map clause}}
+#pragma omp target map(k), map(k) // expected-error 2 {{variable already marked as mapped in current construct}} expected-note 2 {{used here}}
+#pragma omp target map(k), map(k[:5]) // expected-error 2 {{variable already marked as mapped in current construct}} expected-note 2 {{used here}}
+ foo();
+#pragma omp target map(da)
+#pragma omp target map(da[:4])
+ foo();
+#pragma omp target map(k, j, l) // expected-note 4 {{used here}}
+#pragma omp target map(k[:4]) // expected-error 2 {{variable already marked as mapped in current construct}}
+#pragma omp target map(j)
+#pragma omp target map(l[:5]) // expected-error 2 {{variable already marked as mapped in current construct}}
+ foo();
+#pragma omp target map(k[:4], j, l[:5]) // expected-note 4 {{used here}}
+#pragma omp target map(k) // expected-error 2 {{variable already marked as mapped in current construct}}
+#pragma omp target map(j)
+#pragma omp target map(l) // expected-error 2 {{variable already marked as mapped in current construct}}
+ foo();
+
+#pragma omp target map(always, tofrom: x)
+#pragma omp target map(always: x) // expected-error {{missing map type}}
+#pragma omp target map(tofrom, always: x) // expected-error {{incorrect map type modifier, expected 'always'}} expected-error {{incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'}}
+#pragma omp target map(always, tofrom: always, tofrom, x)
+#pragma omp target map(tofrom j) // expected-error {{expected ',' or ')' in 'map' clause}}
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = { 0 };
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+ int *k = &j;
+ int x;
+ int y;
+ int to, tofrom, always;
+ const int (&l)[5] = da;
+#pragma omp target map // expected-error {{expected '(' after 'map'}}
+#pragma omp target map( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+#pragma omp target map() // expected-error {{expected expression}}
+#pragma omp target map(alloc) // expected-error {{use of undeclared identifier 'alloc'}}
+#pragma omp target map(to argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected ',' or ')' in 'map' clause}}
+#pragma omp target map(to:) // expected-error {{expected expression}}
+#pragma omp target map(from: argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp target map(x: y) // expected-error {{incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'}}
+#pragma omp target map(x)
+ foo();
+#pragma omp target map(to: x)
+ foo();
+#pragma omp target map(to: to)
+ foo();
+#pragma omp target map(to)
+ foo();
+#pragma omp target map(to, x)
+ foo();
+#pragma omp target map(to x) // expected-error {{expected ',' or ')' in 'map' clause}}
+#pragma omp target map(tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target map(argc)
+#pragma omp target map(S1) // expected-error {{'S1' does not refer to a value}}
+#pragma omp target map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target map(argv[1])
+#pragma omp target map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target map(ca)
+#pragma omp target map(da)
+#pragma omp target map(S2::S2s)
+#pragma omp target map(S2::S2sc)
+#pragma omp target map(e, g)
+#pragma omp target map(h) // expected-error {{threadprivate variables are not allowed in map clause}}
+#pragma omp target map(k), map(k) // expected-error {{variable already marked as mapped in current construct}} expected-note {{used here}}
+#pragma omp target map(k), map(k[:5]) // expected-error {{variable already marked as mapped in current construct}} expected-note {{used here}}
+ foo();
+#pragma omp target map(da)
+#pragma omp target map(da[:4])
+ foo();
+#pragma omp target map(k, j, l) // expected-note 2 {{used here}}
+#pragma omp target map(k[:4]) // expected-error {{variable already marked as mapped in current construct}}
+#pragma omp target map(j)
+#pragma omp target map(l[:5]) // expected-error {{variable already marked as mapped in current construct}}
+ foo();
+#pragma omp target map(k[:4], j, l[:5]) // expected-note 2 {{used here}}
+#pragma omp target map(k) // expected-error {{variable already marked as mapped in current construct}}
+#pragma omp target map(j)
+#pragma omp target map(l) // expected-error {{variable already marked as mapped in current construct}}
+ foo();
+
+#pragma omp target map(always, tofrom: x)
+#pragma omp target map(always: x) // expected-error {{missing map type}}
+#pragma omp target map(tofrom, always: x) // expected-error {{incorrect map type modifier, expected 'always'}} expected-error {{incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'}}
+#pragma omp target map(always, tofrom: always, tofrom, x)
+#pragma omp target map(tofrom j) // expected-error {{expected ',' or ')' in 'map' clause}}
+ foo();
+
+ return tmain<int, 3>(argc)+tmain<from, 4>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 3>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<int, 4>' requested here}}
+}
+
diff --git a/test/OpenMP/target_messages.cpp b/test/OpenMP/target_messages.cpp
index ebac51a..86a9183 100644
--- a/test/OpenMP/target_messages.cpp
+++ b/test/OpenMP/target_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - %s
+// RUN: not %clang_cc1 -fopenmp -std=c++11 -omptargets=aaa-bbb-ccc-ddd -o - %s 2>&1 | FileCheck %s
+// CHECK: error: OpenMP target is invalid: 'aaa-bbb-ccc-ddd'
void foo() {
}
diff --git a/test/OpenMP/task_ast_print.cpp b/test/OpenMP/task_ast_print.cpp
index dae967e..723139b 100644
--- a/test/OpenMP/task_ast_print.cpp
+++ b/test/OpenMP/task_ast_print.cpp
@@ -36,9 +36,9 @@
T arr[argc];
#pragma omp task untied depend(in : argc, argv[b:argc], arr[:]) if (task : argc > 0)
a = 2;
-#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0)
+#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) priority(argc)
foo();
-#pragma omp task if (C) mergeable
+#pragma omp task if (C) mergeable priority(C)
foo();
return 0;
}
@@ -50,9 +50,9 @@
// CHECK-NEXT: int arr[argc];
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0)
// CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(5) mergeable
+// CHECK-NEXT: #pragma omp task if(5) mergeable priority(5)
// CHECK-NEXT: foo()
// CHECK: template <typename T = long, int C = 1> long tmain(long argc, long *argv) {
// CHECK-NEXT: long b = argc, c, d, e, f, g;
@@ -61,9 +61,9 @@
// CHECK-NEXT: long arr[argc];
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0)
// CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(1) mergeable
+// CHECK-NEXT: #pragma omp task if(1) mergeable priority(1)
// CHECK-NEXT: foo()
// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
// CHECK-NEXT: T b = argc, c, d, e, f, g;
@@ -72,9 +72,9 @@
// CHECK-NEXT: T arr[argc];
// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0)
// CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(C) mergeable
+// CHECK-NEXT: #pragma omp task if(C) mergeable priority(C)
// CHECK-NEXT: foo()
enum Enum {};
@@ -87,12 +87,12 @@
#pragma omp threadprivate(a)
Enum ee;
// CHECK: Enum ee;
-#pragma omp task untied mergeable depend(out:argv[:a][1], (arr)[0:]) if(task: argc > 0)
- // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[:a][1],(arr)[0:]) if(task: argc > 0)
+#pragma omp task untied mergeable depend(out:argv[:a][1], (arr)[0:]) if(task: argc > 0) priority(f)
+ // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[:a][1],(arr)[0:]) if(task: argc > 0) priority(f)
a = 2;
// CHECK-NEXT: a = 2;
-#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a])
- // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a])
+#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23)
+ // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23)
foo();
// CHECK-NEXT: foo();
return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
diff --git a/test/OpenMP/task_codegen.cpp b/test/OpenMP/task_codegen.cpp
index ed59b3d..23dc014 100644
--- a/test/OpenMP/task_codegen.cpp
+++ b/test/OpenMP/task_codegen.cpp
@@ -119,7 +119,7 @@
// CHECK: getelementptr inbounds [[KMP_DEPEND_INFO]], [[KMP_DEPEND_INFO]]* %{{[^,]+}}, i32 0, i32 1
// CHECK: store i64 4, i64*
// CHECK: getelementptr inbounds [[KMP_DEPEND_INFO]], [[KMP_DEPEND_INFO]]* %{{[^,]+}}, i32 0, i32 2
-// CHECK: store i8 2, i8*
+// CHECK: store i8 3, i8*
// CHECK: [[IDX1:%.+]] = mul nsw i64 4, [[A_VAL]]
// CHECK: [[START:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
// CHECK: [[B_VAL:%.+]] = load i8, i8* [[B]]
@@ -141,7 +141,7 @@
// CHECK: getelementptr inbounds [[KMP_DEPEND_INFO]], [[KMP_DEPEND_INFO]]* %{{[^,]+}}, i32 0, i32 1
// CHECK: store i64 [[SIZEOF]], i64*
// CHECK: getelementptr inbounds [[KMP_DEPEND_INFO]], [[KMP_DEPEND_INFO]]* %{{[^,]+}}, i32 0, i32 2
-// CHECK: store i8 2, i8*
+// CHECK: store i8 3, i8*
// CHECK: getelementptr inbounds [2 x [[KMP_DEPEND_INFO]]], [2 x [[KMP_DEPEND_INFO]]]* %{{[^,]+}}, i32 0, i32 0
// CHECK: bitcast [[KMP_DEPEND_INFO]]* %{{.+}} to i8*
// CHECK: call i32 @__kmpc_omp_task_with_deps([[IDENT_T]]* @{{.+}}, i32 [[GTID]], i8* [[ORIG_TASK_PTR]], i32 2, i8* %{{[^,]+}}, i32 0, i8* null)
diff --git a/test/OpenMP/task_depend_messages.cpp b/test/OpenMP/task_depend_messages.cpp
index be96d8e..39bf484 100644
--- a/test/OpenMP/task_depend_messages.cpp
+++ b/test/OpenMP/task_depend_messages.cpp
@@ -24,6 +24,8 @@
#pragma omp task depend ( // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend () // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend (argc // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task depend (source : argc) // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}}
+ #pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
#pragma omp task depend (out: ) // expected-error {{expected expression}}
#pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
diff --git a/test/OpenMP/task_priority_messages.cpp b/test/OpenMP/task_priority_messages.cpp
new file mode 100644
index 0000000..8a5553e
--- /dev/null
+++ b/test/OpenMP/task_priority_messages.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp task priority // expected-error {{expected '(' after 'priority'}}
+ #pragma omp task priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority () // expected-error {{expected expression}}
+ #pragma omp task priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
+ #pragma omp task priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ #pragma omp task priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp task' cannot contain more than one 'priority' clause}}
+ #pragma omp task priority (S) // expected-error {{'S' does not refer to a value}}
+ #pragma omp task priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority(0)
+ #pragma omp task priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp task priority // expected-error {{expected '(' after 'priority'}}
+ #pragma omp task priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority () // expected-error {{expected expression}}
+ #pragma omp task priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
+ #pragma omp task priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ #pragma omp task priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp task' cannot contain more than one 'priority' clause}}
+ #pragma omp task priority (S1) // expected-error {{'S1' does not refer to a value}}
+ #pragma omp task priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp task priority(0)
+ #pragma omp task priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/task_private_codegen.cpp b/test/OpenMP/task_private_codegen.cpp
index f522473..1455fd1 100644
--- a/test/OpenMP/task_private_codegen.cpp
+++ b/test/OpenMP/task_private_codegen.cpp
@@ -138,6 +138,8 @@
s_arr[0] = var;
sivar = 8;
}
+#pragma omp task
+ g+=1;
return tmain<int>();
#endif
}
@@ -188,6 +190,7 @@
// Start task.
// CHECK: call i32 @__kmpc_omp_task([[LOC]], i32 [[GTID]], i8* [[RES]])
+// CHECK: call i32 @__kmpc_omp_task([[LOC]], i32 [[GTID]], i8*
// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
diff --git a/test/OpenMP/task_private_messages.cpp b/test/OpenMP/task_private_messages.cpp
index a1af7e9..6bce135 100644
--- a/test/OpenMP/task_private_messages.cpp
+++ b/test/OpenMP/task_private_messages.cpp
@@ -14,7 +14,7 @@
public:
S2() : a(0) {}
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
};
const S2 b;
const S2 ba[5];
@@ -78,7 +78,7 @@
#pragma omp task private(ba)
#pragma omp task private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp task private(da) // expected-error {{shared variable cannot be private}}
-#pragma omp task private(S2::S2s)
+#pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}}
#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp task private(threadvar, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
#pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
diff --git a/test/OpenMP/taskloop_ast_print.cpp b/test/OpenMP/taskloop_ast_print.cpp
new file mode 100644
index 0000000..06164ab
--- /dev/null
+++ b/test/OpenMP/taskloop_ast_print.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T, int N>
+T tmain(T argc) {
+ T b = argc, c, d, e, f, g;
+ static T a;
+// CHECK: static T a;
+#pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N)
+ // CHECK-NEXT: #pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N)
+ for (int i = 0; i < 2; ++i)
+ a = 2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp parallel
+#pragma omp taskloop private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) nogroup num_tasks(N)
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ foo();
+ // CHECK-NEXT: #pragma omp parallel
+ // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) nogroup num_tasks(N)
+ // CHECK-NEXT: for (int i = 0; i < 2; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int i = 0; i < 2; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: foo();
+ return T();
+}
+
+int main(int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc)
+ // CHECK-NEXT: #pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc)
+ for (int i = 0; i < 2; ++i)
+ a = 2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp parallel
+#pragma omp taskloop private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ foo();
+ // CHECK-NEXT: #pragma omp parallel
+ // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc)
+ // CHECK-NEXT: for (int i = 0; i < 10; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+ // CHECK-NEXT: foo();
+ return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
+}
+
+#endif
diff --git a/test/OpenMP/taskloop_collapse_messages.cpp b/test/OpenMP/taskloop_collapse_messages.cpp
new file mode 100644
index 0000000..f33da11
--- /dev/null
+++ b/test/OpenMP/taskloop_collapse_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp taskloop collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp taskloop collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp taskloop collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp taskloop', but found only 1}}
+ // expected-error@+3 2 {{directive '#pragma omp taskloop' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp taskloop'}}
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop collapse (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+ #pragma omp taskloop collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+ #pragma omp taskloop collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp taskloop' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp taskloop collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop collapse (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp taskloop collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp taskloop' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp taskloop collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ #pragma omp taskloop collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp taskloop'}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/taskloop_final_messages.cpp b/test/OpenMP/taskloop_final_messages.cpp
new file mode 100644
index 0000000..a2d7cda
--- /dev/null
+++ b/test/OpenMP/taskloop_final_messages.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+#pragma omp taskloop final // expected-error {{expected '(' after 'final'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final() // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc > 0 ? argv[1] : argv[2])
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(foobool(argc)), final(true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'final' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#pragma omp taskloop final // expected-error {{expected '(' after 'final'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final() // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc > 0 ? argv[1] : argv[2])
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(foobool(argc)), final(true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'final' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop final(if (tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_firstprivate_messages.cpp b/test/OpenMP/taskloop_firstprivate_messages.cpp
new file mode 100644
index 0000000..e2e87e4
--- /dev/null
+++ b/test/OpenMP/taskloop_firstprivate_messages.cpp
@@ -0,0 +1,313 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {} // expected-note 2 {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+ S3(S3 &s3) : a(s3.a) {} // expected-note 2 {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
+
+public:
+ S5() : a(0) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ C g(5);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop firstprivate(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel private(i)
+#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+ foo();
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop firstprivate(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(ba) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(ca) // expected-error {{no matching constructor for initialization of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(da) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp taskloop firstprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(S2::S2s) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(S2::S2sc) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp taskloop'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(m) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+ foo();
+#pragma omp parallel shared(xa)
+#pragma omp taskloop firstprivate(xa) // OK: may be firstprivate
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(j)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel private(i)
+#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ static int si;
+#pragma omp taskloop firstprivate(si) // OK
+ for (i = 0; i < argc; ++i)
+ si = i + 1;
+
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
+
diff --git a/test/OpenMP/taskloop_grainsize_messages.cpp b/test/OpenMP/taskloop_grainsize_messages.cpp
new file mode 100644
index 0000000..047f925
--- /dev/null
+++ b/test/OpenMP/taskloop_grainsize_messages.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop grainsize // expected-error {{expected '(' after 'grainsize'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (foobool(argc)), grainsize (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'grainsize' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(0) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(-1) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(argc) num_tasks(argc) // expected-error {{'num_tasks' and 'grainsize' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'grainsize' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop grainsize // expected-error {{expected '(' after 'grainsize'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (foobool(argc)), grainsize (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'grainsize' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(0) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(-1) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop grainsize(argc) num_tasks(argc) // expected-error {{'num_tasks' and 'grainsize' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'grainsize' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_lastprivate_messages.cpp b/test/OpenMP/taskloop_lastprivate_messages.cpp
new file mode 100644
index 0000000..e436444
--- /dev/null
+++ b/test/OpenMP/taskloop_lastprivate_messages.cpp
@@ -0,0 +1,287 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator =(const S2&) const;
+ S2 &operator =(const S2&);
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S3() : a(0) {}
+ S3(S3 &s3) : a(s3.a) {}
+};
+const S3 c; // expected-note {{global variable is predetermined as shared}}
+const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
+extern const int f; // expected-note {{global variable is predetermined as shared}}
+class S4 {
+ int a;
+ S4(); // expected-note 3 {{implicitly declared private here}}
+ S4(const S4 &s4);
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(const S5 &s5) : a(s5.a) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop lastprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop lastprivate(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop lastprivate(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{constant variable is predetermined as shared}}
+ const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(ba)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp taskloop'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(i)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel private(xa)
+#pragma omp taskloop lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : xa)
+#pragma omp taskloop lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(j)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ static int si;
+#pragma omp taskloop lastprivate(si) // OK
+ for (i = 0; i < argc; ++i)
+ si = i + 1;
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_loop_messages.cpp b/test/OpenMP/taskloop_loop_messages.cpp
new file mode 100644
index 0000000..02518e5
--- /dev/null
+++ b/test/OpenMP/taskloop_loop_messages.cpp
@@ -0,0 +1,738 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+class S {
+ int a;
+ S() : a(0) {}
+
+public:
+ S(int v) : a(v) {}
+ S(const S &s) : a(s.a) {}
+};
+
+static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
+#pragma omp threadprivate(sii)
+static int globalii;
+
+// Currently, we cannot use "0" for global register variables.
+// register int reg0 __asm__("0");
+int reg0;
+
+int test_iteration_spaces() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ int ii, jj, kk;
+ float fii;
+ double dii;
+ register int reg; // expected-warning {{'register' storage class specifier is deprecated}}
+#pragma omp parallel
+#pragma omp taskloop
+ for (int i = 0; i < 10; i += 1) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop
+ for (char i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop
+ for (char i = 0; i < 10; i += '\1') {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop
+ for (long long i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+#pragma omp taskloop
+ for (long long i = 0; i < 10; i += 1.5) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop
+ for (long long i = 0; i < 'z'; i += 1u) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp taskloop
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp taskloop
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (int &ref = ii; ref < 10; ref++) {
+ }
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (int i; i < 10; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (int i = 0, j = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (ii + 1; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (c[ii] = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok to skip parenthesises.
+#pragma omp taskloop
+ for (((ii)) = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop
+ for (int i = 0; i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+#pragma omp taskloop
+ for (int i = 0; jj < kk; ii++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop
+ for (int i = 0; !!i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop
+ for (int i = 0; i != 1; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop
+ for (int i = 0;; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop
+ for (int i = 11; i > 10; i--)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ++jj)
+ c[ii] = a[jj];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ++++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok but undefined behavior (in general, cannot check that incr
+// is really loop-invariant).
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii + ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii + 1.0f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok - step was converted to integer type.
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; jj = ii + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{relational comparison result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii<10; jj> kk + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10;)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; !ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii < 10)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii + 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; (ii) < 10; ii -= 25)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; (ii < 10); ii -= 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; ii > 10; (ii += 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; ii < 10; (ii) = (1 - 1) + (ii))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for ((ii = 0); ii > 10; (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (ii = 0; (ii < 10); (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+2 {{defined as firstprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
+#pragma omp taskloop firstprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{unexpected OpenMP clause 'linear' in directive '#pragma omp taskloop'}}
+// expected-note@+1 {{defined as linear}}
+#pragma omp taskloop linear(ii)
+// expected-error@+1 {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be linear, predetermined as private}}
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+#pragma omp taskloop private(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+#pragma omp taskloop lastprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be threadprivate or thread local, predetermined as private}}
+#pragma omp taskloop
+ for (sii = 0; sii < 10; sii += 1)
+ c[sii] = a[sii];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop
+ for (reg0 = 0; reg0 < 10; reg0 += 1)
+ c[reg0] = a[reg0];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop
+ for (reg = 0; reg < 10; reg += 1)
+ c[reg] = a[reg];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
+#pragma omp parallel
+// expected-error@+2 {{statement after '#pragma omp taskloop' must be a for loop}}
+#pragma omp taskloop
+ for (auto &item : a) {
+ item = item + 1;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (unsigned i = 9; i < 10; i--) {
+ c[i] = a[i] + b[i];
+ }
+
+ int(*lb)[4] = nullptr;
+#pragma omp parallel
+#pragma omp taskloop
+ for (int(*p)[4] = lb; p < lb + 8; ++p) {
+ }
+
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (int a{0}; a < 10; ++a) {
+ }
+
+ return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag {};
+template <class Iter>
+struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+public:
+ Iter0() {}
+ Iter0(const Iter0 &) {}
+ Iter0 operator++() { return *this; }
+ Iter0 operator--() { return *this; }
+ bool operator<(Iter0 a) { return true; }
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
+int operator-(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+public:
+ Iter1(float f = 0.0f, double d = 0.0) {}
+ Iter1(const Iter1 &) {}
+ Iter1 operator++() { return *this; }
+ Iter1 operator--() { return *this; }
+ bool operator<(Iter1 a) { return true; }
+ bool operator>=(Iter1 a) { return false; }
+};
+class GoodIter {
+public:
+ GoodIter() {}
+ GoodIter(const GoodIter &) {}
+ GoodIter(int fst, int snd) {}
+ GoodIter &operator=(const GoodIter &that) { return *this; }
+ GoodIter &operator=(const Iter0 &that) { return *this; }
+ GoodIter &operator+=(int x) { return *this; }
+ GoodIter &operator-=(int x) { return *this; }
+ explicit GoodIter(void *) {}
+ GoodIter operator++() { return *this; }
+ GoodIter operator--() { return *this; }
+ bool operator!() { return true; }
+ bool operator<(GoodIter a) { return true; }
+ bool operator<=(GoodIter a) { return true; }
+ bool operator>=(GoodIter a) { return false; }
+ typedef int difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
+GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
+GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
+GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
+GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+ GoodIter begin, end;
+ Iter0 begin0, end0;
+#pragma omp parallel
+#pragma omp taskloop
+ for (GoodIter I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (GoodIter &I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; --I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (GoodIter I(begin); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (GoodIter I(nullptr); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (GoodIter I(0); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (GoodIter I(1, 2); I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop
+ for (begin = GoodIter(0); begin < end; ++begin)
+ ++begin;
+// expected-error@+4 {{invalid operands to binary expression ('GoodIter' and 'Iter0')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel
+#pragma omp taskloop
+ for (begin = begin0; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (++begin; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+#pragma omp taskloop
+ for (begin = end; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop
+ for (GoodIter I = begin; I - I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop
+ for (GoodIter I = begin; begin < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop
+ for (GoodIter I = begin; !I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; I = I + 1)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; I = I - 1)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; I = -I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; I = 2 + I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp taskloop
+ for (GoodIter I = begin; I >= end; I = 2 - I)
+ ++I;
+// In the following example, we cannot update the loop variable using '+='
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+#pragma omp parallel
+#pragma omp taskloop
+ for (Iter0 I = begin0; I < end0; ++I)
+ ++I;
+#pragma omp parallel
+// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (Iter0 I; I < end0; ++I)
+ ++I;
+ Iter1 begin1, end1;
+// expected-error@+4 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel
+#pragma omp taskloop
+ for (Iter1 I = begin1; I < end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (Iter1 I = begin1; I >= end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'float')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+// Initializer is constructor with all default params.
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop
+ for (Iter1 I; I < end1; ++I) {
+ }
+ return 0;
+}
+
+template <typename IT, int ST>
+class TC {
+public:
+ int dotest_lt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (IT I = begin; I < end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (IT I = begin; I <= end; I += ST) {
+ ++I;
+ }
+#pragma omp parallel
+#pragma omp taskloop
+ for (IT I = begin; I < end; ++I) {
+ ++I;
+ }
+ }
+
+ static IT step() {
+ return IT(ST);
+ }
+};
+template <typename IT, int ST = 0>
+int dotest_gt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (IT I = begin; I >= end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (IT I = begin; I >= end; I += ST) {
+ ++I;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop
+ for (IT I = begin; I >= end; ++I) {
+ ++I;
+ }
+
+#pragma omp parallel
+#pragma omp taskloop
+ for (IT I = begin; I < end; I += TC<int, ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp taskloop
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ break; // OK in nested loop
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ if (c[i] > 10)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+ if (c[i] > 11)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ }
+
+#pragma omp parallel
+#pragma omp taskloop
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ c[i] = a[i] + b[i];
+ if (c[i] > 10) {
+ if (c[i] < 20) {
+ break; // OK
+ }
+ }
+ }
+ }
+}
+
+void test_loop_eh() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp taskloop
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ try {
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ throw a[i];
+ }
+ throw a[i];
+ } catch (float f) {
+ if (f > 0.1)
+ throw a[i];
+ return; // expected-error {{cannot return from OpenMP region}}
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ for (int j = 0; j < 10; j++) {
+ if (c[i] > 10)
+ throw c[i];
+ }
+ }
+ if (c[9] > 10)
+ throw c[9]; // OK
+
+#pragma omp parallel
+#pragma omp taskloop
+ for (int i = 0; i < 10; ++i) {
+ struct S {
+ void g() { throw 0; }
+ };
+ }
+}
+
+void test_loop_firstprivate_lastprivate() {
+ S s(4);
+#pragma omp parallel
+#pragma omp taskloop lastprivate(s) firstprivate(s)
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
diff --git a/test/OpenMP/taskloop_misc_messages.c b/test/OpenMP/taskloop_misc_messages.c
new file mode 100644
index 0000000..f9e084e
--- /dev/null
+++ b/test/OpenMP/taskloop_misc_messages.c
@@ -0,0 +1,373 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -triple x86_64-unknown-unknown -verify %s
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp taskloop'}}
+#pragma omp taskloop
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp taskloop'}}
+#pragma omp taskloop foo
+
+void test_no_clause() {
+ int i;
+#pragma omp taskloop
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+2 {{statement after '#pragma omp taskloop' must be a for loop}}
+#pragma omp taskloop
+ ++i;
+}
+
+void test_branch_protected_scope() {
+ int i = 0;
+L1:
+ ++i;
+
+ int x[24];
+
+#pragma omp parallel
+#pragma omp taskloop
+ for (i = 0; i < 16; ++i) {
+ if (i == 5)
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ else if (i == 6)
+ return; // expected-error {{cannot return from OpenMP region}}
+ else if (i == 7)
+ goto L2;
+ else if (i == 8) {
+ L2:
+ x[i]++;
+ }
+ }
+
+ if (x[0] == 0)
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ else if (x[1] == 1)
+ goto L1;
+}
+
+void test_invalid_clause() {
+ int i;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+#pragma omp taskloop foo bar
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{directive '#pragma omp taskloop' cannot contain more than one 'nogroup' clause}}
+#pragma omp taskloop nogroup nogroup
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_non_identifiers() {
+ int i, x;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+#pragma omp taskloop;
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+3 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+// expected-error@+2 {{unexpected OpenMP clause 'linear' in directive '#pragma omp taskloop'}}
+#pragma omp parallel
+#pragma omp taskloop linear(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+#pragma omp taskloop private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+#pragma omp taskloop, private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+extern int foo();
+
+void test_collapse() {
+ int i;
+#pragma omp parallel
+// expected-error@+1 {{expected '('}}
+#pragma omp taskloop collapse
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop collapse(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop collapse()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop collapse(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop collapse(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp taskloop collapse 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4,
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4, )
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+#pragma omp taskloop collapse(4)
+ for (int i1 = 0; i1 < 16; ++i1)
+ for (int i2 = 0; i2 < 16; ++i2)
+ for (int i3 = 0; i3 < 16; ++i3)
+ for (int i4 = 0; i4 < 16; ++i4)
+ foo();
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop collapse(4, 8)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop', but found only 1}}
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp taskloop collapse(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp taskloop collapse(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop collapse(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop collapse(0)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop collapse(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_private() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop private(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop private(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop private(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop private()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop private(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop private(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop private(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop private(x, y, z)
+ for (i = 0; i < 16; ++i) {
+ x = y * i + z;
+ }
+}
+
+void test_lastprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop lastprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop lastprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop lastprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop lastprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop lastprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop lastprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_firstprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop firstprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop firstprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop firstprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop firstprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop firstprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop firstprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x) firstprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x, y) firstprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop lastprivate(x, y, z) firstprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_loop_messages() {
+ float a[100], b[100], c[100];
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp taskloop
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp taskloop
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+
+ // expected-warning@+2 {{OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed}}
+ #pragma omp taskloop
+ for (__int128 ii = 0; ii < 10; ii++) {
+ c[ii] = a[ii] + b[ii];
+ }
+}
+
diff --git a/test/OpenMP/taskloop_num_tasks_messages.cpp b/test/OpenMP/taskloop_num_tasks_messages.cpp
new file mode 100644
index 0000000..94d74eb
--- /dev/null
+++ b/test/OpenMP/taskloop_num_tasks_messages.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop num_tasks // expected-error {{expected '(' after 'num_tasks'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (foobool(argc)), num_tasks (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'num_tasks' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(0) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(-1) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(argc) grainsize(argc) // expected-error {{'grainsize' and 'num_tasks' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'num_tasks' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop num_tasks // expected-error {{expected '(' after 'num_tasks'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (foobool(argc)), num_tasks (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'num_tasks' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(0) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(-1) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop num_tasks(argc) grainsize(argc) // expected-error {{'grainsize' and 'num_tasks' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'num_tasks' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_priority_messages.cpp b/test/OpenMP/taskloop_priority_messages.cpp
new file mode 100644
index 0000000..6c15845
--- /dev/null
+++ b/test/OpenMP/taskloop_priority_messages.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop priority // expected-error {{expected '(' after 'priority'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'priority' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority(0)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop priority // expected-error {{expected '(' after 'priority'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp taskloop' cannot contain more than one 'priority' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority(0)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_private_messages.cpp b/test/OpenMP/taskloop_private_messages.cpp
new file mode 100644
index 0000000..3d00d3f
--- /dev/null
+++ b/test/OpenMP/taskloop_private_messages.cpp
@@ -0,0 +1,195 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i;
+#pragma omp taskloop private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(e, g)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop shared(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop private(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop private(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop private(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+#pragma omp taskloop private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(B::x) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop shared(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int i;
+#pragma omp taskloop private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop private(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ static int si;
+#pragma omp taskloop private(si) // OK
+ for(int k = 0; k < argc; ++k)
+ si = k + 1;
+
+ return 0;
+}
+
diff --git a/test/OpenMP/taskloop_simd_aligned_messages.cpp b/test/OpenMP/taskloop_simd_aligned_messages.cpp
new file mode 100644
index 0000000..b62af04
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_aligned_messages.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -verify -fopenmp %s
+
+struct B {
+ static int ib[20]; // expected-note 0 {{'B::ib' declared here}}
+ static constexpr int bfoo() { return 8; }
+};
+namespace X {
+ B x; // expected-note {{'x' defined here}}
+};
+constexpr int bfoo() { return 4; }
+
+int **z;
+const int C1 = 1;
+const int C2 = 2;
+void test_aligned_colons(int *&rp)
+{
+ int *B = 0;
+ #pragma omp taskloop simd aligned(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp taskloop simd aligned(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp taskloop simd aligned(z:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd aligned(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'int **'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'B'}}
+ #pragma omp taskloop simd aligned(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'B'}}
+ #pragma omp taskloop simd aligned(B,rp,::z: X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd aligned(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp taskloop simd aligned(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ #pragma omp taskloop simd aligned(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+// expected-note@+1 {{'num' defined here}}
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L;
+ // Negative number is passed as L.
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd aligned(arr:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp taskloop simd aligned(num:4)
+ for (i = 0; i < num; ++i);
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int *ind2 = 0;
+ // expected-error@+1 {{argument to 'aligned' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd aligned(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return 0;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+extern S1 a; // expected-note {{'a' declared here}}
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 1 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h; // expected-note 2 {{'h' defined here}}
+#pragma omp threadprivate(h)
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(argc);
+ I g(argc);
+ int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
+ // expected-note@+2 {{declared here}}
+ // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int &j = i;
+ #pragma omp taskloop simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned () // expected-error {{expected expression}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned(e, g)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp taskloop simd aligned(h)
+ for (I k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp taskloop simd aligned(i)
+ for (I k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int *v = 0;
+ I i;
+ #pragma omp taskloop simd aligned(v:16)
+ for (I k = 0; k < argc; ++k) { i = k; v += 2; }
+ }
+ float *f;
+ #pragma omp taskloop simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ // expected-note@+2 {{initializer of 'j' is not a constant expression}}
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd aligned(f:j)
+ for (I k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp taskloop simd aligned(f)
+ for (I k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+// expected-note@+1 2 {{'argc' defined here}}
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ test_warn<4>(); // ok
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ int i;
+ int &j = i;
+ #pragma omp taskloop simd aligned // expected-error {{expected '(' after 'aligned'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argv // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp taskloop simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
+ #pragma omp taskloop simd aligned (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S1'}}
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S2'}}
+ #pragma omp taskloop simd aligned (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd aligned (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
+ #pragma omp taskloop simd aligned(h)
+ for (int k = 0; k < argc; ++k) ++k;
+ int *pargc = &argc;
+ foomain<int*,char>(pargc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/taskloop_simd_ast_print.cpp b/test/OpenMP/taskloop_simd_ast_print.cpp
new file mode 100644
index 0000000..3e3b7e4
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_ast_print.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void foo() {}
+
+template <class T, int N>
+T tmain(T argc) {
+ T b = argc, c, d, e, f, g;
+ T *ptr;
+ static T a;
+// CHECK: static T a;
+#pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N)
+ // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N)
+ for (int i = 0; i < 2; ++i)
+ a = 2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp parallel
+#pragma omp taskloop simd private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N)
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; ++j)
+ foo();
+ // CHECK-NEXT: #pragma omp parallel
+ // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N)
+ // CHECK-NEXT: for (int i = 0; i < 2; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int i = 0; i < 2; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: for (int j = 0; j < 2; ++j)
+ // CHECK-NEXT: foo();
+ return T();
+}
+
+int main(int argc, char **argv) {
+ int b = argc, c, d, e, f, g;
+ static int a;
+// CHECK: static int a;
+#pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b), aligned(argv) nogroup num_tasks(argc)
+ // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b) aligned(argv) nogroup num_tasks(argc)
+ for (int i = 0; i < 2; ++i)
+ a = 2;
+// CHECK-NEXT: for (int i = 0; i < 2; ++i)
+// CHECK-NEXT: a = 2;
+#pragma omp parallel
+#pragma omp taskloop simd private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ foo();
+ // CHECK-NEXT: #pragma omp parallel
+ // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc)
+ // CHECK-NEXT: for (int i = 0; i < 10; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+ // CHECK-NEXT: foo();
+ return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
+}
+
+#endif
diff --git a/test/OpenMP/taskloop_simd_collapse_messages.cpp b/test/OpenMP/taskloop_simd_collapse_messages.cpp
new file mode 100644
index 0000000..d178c08
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_collapse_messages.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp taskloop simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp taskloop simd collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd collapse (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp taskloop simd', but found only 1}}
+ // expected-error@+3 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse (N) // expected-error {{argument to 'collapse' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp taskloop simd'}}
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd collapse (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+ #pragma omp taskloop simd collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}} expected-note {{as specified in 'collapse' clause}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+ #pragma omp taskloop simd collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd collapse (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp taskloop simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp taskloop simd collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ #pragma omp taskloop simd collapse (2) // expected-note {{as specified in 'collapse' clause}}
+ foo(); // expected-error {{expected 2 for loops after '#pragma omp taskloop simd'}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
+ return tmain<int, char, 1, 0>(argc, argv);
+}
+
diff --git a/test/OpenMP/taskloop_simd_final_messages.cpp b/test/OpenMP/taskloop_simd_final_messages.cpp
new file mode 100644
index 0000000..c6580fb
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_final_messages.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+#pragma omp taskloop simd final // expected-error {{expected '(' after 'final'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final() // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc > 0 ? argv[1] : argv[2])
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(foobool(argc)), final(true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'final' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#pragma omp taskloop simd final // expected-error {{expected '(' after 'final'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final() // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc > 0 ? argv[1] : argv[2])
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(foobool(argc)), final(true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'final' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd final(if (tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_simd_firstprivate_messages.cpp b/test/OpenMP/taskloop_simd_firstprivate_messages.cpp
new file mode 100644
index 0000000..8394669
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_firstprivate_messages.cpp
@@ -0,0 +1,313 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(const S2 &s2) : a(s2.a) {}
+ static float S2s;
+ static const float S2sc;
+};
+const float S2::S2sc = 0;
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3);
+
+public:
+ S3() : a(0) {} // expected-note 2 {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+ S3(S3 &s3) : a(s3.a) {} // expected-note 2 {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
+};
+const S3 c;
+const S3 ca[5];
+extern const int f;
+class S4 {
+ int a;
+ S4();
+ S4(const S4 &s4); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5(const S5 &s5) : a(s5.a) {} // expected-note 4 {{implicitly declared private here}}
+
+public:
+ S5() : a(0) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ C g(5);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(a, b) // expected-error {{firstprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop simd firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop simd firstprivate(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel private(i)
+#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5;
+ const int da[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate // expected-error {{expected '(' after 'firstprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(ba) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(ca) // expected-error {{no matching constructor for initialization of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(da) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(S2::S2s) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(S2::S2sc) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd safelen(5)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(m) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel shared(xa)
+#pragma omp taskloop simd firstprivate(xa) // OK: may be firstprivate
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(j)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(g) firstprivate(g) // expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop simd firstprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel private(i)
+#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel reduction(+ : i)
+#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ static int si;
+#pragma omp taskloop simd firstprivate(si) // OK
+ for (i = 0; i < argc; ++i)
+ si = i + 1;
+
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
+
diff --git a/test/OpenMP/taskloop_simd_grainsize_messages.cpp b/test/OpenMP/taskloop_simd_grainsize_messages.cpp
new file mode 100644
index 0000000..45ccb31
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_grainsize_messages.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop simd grainsize // expected-error {{expected '(' after 'grainsize'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (foobool(argc)), grainsize (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'grainsize' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(0) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(-1) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(argc) num_tasks(argc) // expected-error {{'num_tasks' and 'grainsize' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'grainsize' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd grainsize // expected-error {{expected '(' after 'grainsize'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (foobool(argc)), grainsize (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'grainsize' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(0) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(-1) // expected-error {{argument to 'grainsize' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd grainsize(argc) num_tasks(argc) // expected-error {{'num_tasks' and 'grainsize' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'grainsize' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_simd_lastprivate_messages.cpp b/test/OpenMP/taskloop_simd_lastprivate_messages.cpp
new file mode 100644
index 0000000..ed1bdf5
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_lastprivate_messages.cpp
@@ -0,0 +1,287 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator =(const S2&) const;
+ S2 &operator =(const S2&);
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
+ static const float S2sc;
+};
+const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
+
+public:
+ S3() : a(0) {}
+ S3(S3 &s3) : a(s3.a) {}
+};
+const S3 c; // expected-note {{global variable is predetermined as shared}}
+const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
+extern const int f; // expected-note {{global variable is predetermined as shared}}
+class S4 {
+ int a;
+ S4(); // expected-note 3 {{implicitly declared private here}}
+ S4(const S4 &s4);
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(const S5 &s5) : a(s5.a) {}
+ S5(int v) : a(v) {}
+};
+class S6 {
+ int a;
+ S6() : a(0) {}
+
+public:
+ S6(const S6 &s6) : a(s6.a) {}
+ S6(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(int argc, char **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(a, b) // expected-error {{lastprivate variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop simd lastprivate(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop simd lastprivate(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note {{constant variable is predetermined as shared}}
+ const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
+ S6 n(2);
+ int i;
+ int &j = i;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate() // expected-error {{expected expression}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argc)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(S1) // expected-error {{'S1' does not refer to a value}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(argv[1]) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(2 * 2) // expected-error {{expected variable name}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(ba)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+ int xa;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(xa) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd safelen(5)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(i) // expected-note {{defined as lastprivate}}
+ for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be lastprivate, predetermined as linear}}
+ foo();
+#pragma omp parallel private(xa)
+#pragma omp taskloop simd lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel reduction(+ : xa)
+#pragma omp taskloop simd lastprivate(xa)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(j)
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(n) firstprivate(n) // OK
+ for (i = 0; i < argc; ++i)
+ foo();
+ static int si;
+#pragma omp taskloop simd lastprivate(si) // OK
+ for (i = 0; i < argc; ++i)
+ si = i + 1;
+ return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_simd_linear_messages.cpp b/test/OpenMP/taskloop_simd_linear_messages.cpp
new file mode 100644
index 0000000..c9a82b9
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_linear_messages.cpp
@@ -0,0 +1,249 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+namespace X {
+ int x;
+};
+
+struct B {
+ static int ib; // expected-note {{'B::ib' declared here}}
+ static int bfoo() { return 8; }
+};
+
+int bfoo() { return 4; }
+
+int z;
+const int C1 = 1;
+const int C2 = 2;
+void test_linear_colons()
+{
+ int B = 0;
+ #pragma omp taskloop simd linear(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp taskloop simd linear(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'ib'; did you mean 'B::ib'}}
+ #pragma omp taskloop simd linear(B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp taskloop simd linear(z:B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd linear(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd linear(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd linear(B,::z, X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd linear(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp taskloop simd linear(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp taskloop simd linear(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L; // expected-note {{'ind2' defined here}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
+#pragma omp taskloop simd linear(ind2:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[(int)ind2];
+ ind2 += L;
+ sum += cur;
+ }
+ return T();
+}
+
+template<int LEN> int test_warn() {
+ int ind2 = 0;
+ // expected-warning@+1 {{zero linear step (ind2 should probably be const)}}
+ #pragma omp taskloop simd linear(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return ind2;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i;
+ #pragma omp taskloop simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (val // expected-error {{use of undeclared identifier 'val'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (uval( // expected-error {{expected expression}} expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (ref() // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (foo() // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (val argc // expected-error {{use of undeclared identifier 'val'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (val(argc, // expected-error {{expected expression}} expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc : 5)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp taskloop simd linear (val(a, b):B::ib)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(ref(e, g)) // expected-error 2 {{variable of non-reference type 'int' can be used only with 'val' modifier, but used with 'ref'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(uval(i)) // expected-error {{variable of non-reference type 'int' can be used only with 'val' modifier, but used with 'uval'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp taskloop simd linear(v:i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp taskloop simd linear(ref(j))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(uval(j))
+ for (int k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ #pragma omp taskloop simd linear(v:j)
+ for (int k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp taskloop simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace C {
+using A::x;
+}
+
+void linear_modifiers(int argc) {
+ int &f = argc;
+ #pragma omp taskloop simd linear(f)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(val(f))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(uval(f))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(ref(f))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(foo(f)) // expected-error {{expected one of 'ref', val' or 'uval' modifiers}}
+ for (int k = 0; k < argc; ++k) ++k;
+}
+
+int f;
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i;
+ #pragma omp taskloop simd linear(f) linear(f) // expected-error {{linear variable cannot be linear}} expected-note {{defined as linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (val // expected-error {{use of undeclared identifier 'val'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (ref()) // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (foo()) // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp taskloop simd linear(a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of a linear clause should be of integral or pointer type, not 'S4'}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
+ #pragma omp taskloop simd linear(val(e, g))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(h, C::x) // expected-error 2 {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int i;
+ #pragma omp taskloop simd linear(val(i))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(uval(i) : 4) // expected-error {{variable of non-reference type 'int' can be used only with 'val' modifier, but used with 'uval'}}
+ for (int k = 0; k < argc; ++k) { ++k; i += 4; }
+ }
+ #pragma omp taskloop simd linear(ref(j))
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp taskloop simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+
+ foomain<int,char>(argc,argv); // expected-note {{in instantiation of function template specialization 'foomain<int, char>' requested here}}
+ return 0;
+}
+
diff --git a/test/OpenMP/taskloop_simd_loop_messages.cpp b/test/OpenMP/taskloop_simd_loop_messages.cpp
new file mode 100644
index 0000000..4731872
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_loop_messages.cpp
@@ -0,0 +1,739 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+class S {
+ int a;
+ S() : a(0) {}
+
+public:
+ S(int v) : a(v) {}
+ S(const S &s) : a(s.a) {}
+};
+
+static int sii;
+// expected-note@+1 {{defined as threadprivate or thread local}}
+#pragma omp threadprivate(sii)
+static int globalii;
+
+// Currently, we cannot use "0" for global register variables.
+// register int reg0 __asm__("0");
+int reg0;
+
+int test_iteration_spaces() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ int ii, jj, kk;
+ float fii;
+ double dii;
+ register int reg; // expected-warning {{'register' storage class specifier is deprecated}}
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; i += 1) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (char i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (char i = 0; i < 10; i += '\1') {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (long long i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+#pragma omp taskloop simd
+ for (long long i = 0; i < 10; i += 1.5) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (long long i = 0; i < 'z'; i += 1u) {
+ c[i] = a[i] + b[i];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp taskloop simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or random access iterator type}}
+#pragma omp taskloop simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (int &ref = ii; ref < 10; ref++) {
+ }
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (int i; i < 10; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (int i = 0, j = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (ii + 1; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (c[ii] = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok to skip parenthesises.
+#pragma omp taskloop simd
+ for (((ii)) = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop simd
+ for (int i = 0; i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+#pragma omp taskloop simd
+ for (int i = 0; jj < kk; ii++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop simd
+ for (int i = 0; !!i; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop simd
+ for (int i = 0; i != 1; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+#pragma omp taskloop simd
+ for (int i = 0;; i++)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop simd
+ for (int i = 11; i > 10; i--)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; ++i)
+ c[i] = a[i];
+
+#pragma omp parallel
+// Ok.
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ++jj)
+ c[ii] = a[jj];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ++++ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok but undefined behavior (in general, cannot check that incr
+// is really loop-invariant).
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii + ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii + 1.0f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// Ok - step was converted to integer type.
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; jj = ii + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{relational comparison result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii<10; jj> kk + 2)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10;)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-warning@+3 {{expression result unused}}
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; !ii)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii < 10)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii + 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; (ii) < 10; ii -= 25)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; (ii < 10); ii -= 0)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; ii > 10; (ii += 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; ii < 10; (ii) = (1 - 1) + (ii))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for ((ii = 0); ii > 10; (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (ii = 0; (ii < 10); (ii -= 0))
+ c[ii] = a[ii];
+
+#pragma omp parallel
+// expected-note@+2 {{defined as firstprivate}}
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
+#pragma omp taskloop simd firstprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+#pragma omp taskloop simd linear(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{defined as private}}
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be private, predetermined as linear}}
+#pragma omp parallel
+#pragma omp taskloop simd private(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+// expected-note@+3 {{defined as lastprivate}}
+// expected-error@+3 {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be lastprivate, predetermined as linear}}
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+#pragma omp parallel
+ {
+// expected-error@+2 {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be threadprivate or thread local, predetermined as linear}}
+#pragma omp taskloop simd
+ for (sii = 0; sii < 10; sii += 1)
+ c[sii] = a[sii];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop simd
+ for (reg0 = 0; reg0 < 10; reg0 += 1)
+ c[reg0] = a[reg0];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop simd
+ for (reg = 0; reg < 10; reg += 1)
+ c[reg] = a[reg];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop simd
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] = a[globalii];
+ }
+
+#pragma omp parallel
+ {
+#pragma omp taskloop simd collapse(2)
+ for (ii = 0; ii < 10; ii += 1)
+ for (globalii = 0; globalii < 10; globalii += 1)
+ c[globalii] += a[globalii] + ii;
+ }
+
+#pragma omp parallel
+// expected-error@+2 {{statement after '#pragma omp taskloop simd' must be a for loop}}
+#pragma omp taskloop simd
+ for (auto &item : a) {
+ item = item + 1;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (unsigned i = 9; i < 10; i--) {
+ c[i] = a[i] + b[i];
+ }
+
+ int(*lb)[4] = nullptr;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int(*p)[4] = lb; p < lb + 8; ++p) {
+ }
+
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (int a{0}; a < 10; ++a) {
+ }
+
+ return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag {};
+template <class Iter>
+struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+public:
+ Iter0() {}
+ Iter0(const Iter0 &) {}
+ Iter0 operator++() { return *this; }
+ Iter0 operator--() { return *this; }
+ bool operator<(Iter0 a) { return true; }
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'Iter0' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'Iter0' for 1st argument}}
+int operator-(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+public:
+ Iter1(float f = 0.0f, double d = 0.0) {}
+ Iter1(const Iter1 &) {}
+ Iter1 operator++() { return *this; }
+ Iter1 operator--() { return *this; }
+ bool operator<(Iter1 a) { return true; }
+ bool operator>=(Iter1 a) { return false; }
+};
+class GoodIter {
+public:
+ GoodIter() {}
+ GoodIter(const GoodIter &) {}
+ GoodIter(int fst, int snd) {}
+ GoodIter &operator=(const GoodIter &that) { return *this; }
+ GoodIter &operator=(const Iter0 &that) { return *this; }
+ GoodIter &operator+=(int x) { return *this; }
+ GoodIter &operator-=(int x) { return *this; }
+ explicit GoodIter(void *) {}
+ GoodIter operator++() { return *this; }
+ GoodIter operator--() { return *this; }
+ bool operator!() { return true; }
+ bool operator<(GoodIter a) { return true; }
+ bool operator<=(GoodIter a) { return true; }
+ bool operator>=(GoodIter a) { return false; }
+ typedef int difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+};
+// expected-note@+2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+int operator-(GoodIter a, GoodIter b) { return 0; }
+// expected-note@+1 3 {{candidate function not viable: requires single argument 'a', but 2 arguments were provided}}
+GoodIter operator-(GoodIter a) { return a; }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 2nd argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'GoodIter' for 1st argument}}
+GoodIter operator-(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'GoodIter' for 1st argument}}
+GoodIter operator+(GoodIter a, int v) { return GoodIter(); }
+// expected-note@+2 {{candidate function not viable: no known conversion from 'GoodIter' to 'int' for 1st argument}}
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter1' to 'int' for 1st argument}}
+GoodIter operator-(int v, GoodIter a) { return GoodIter(); }
+// expected-note@+1 2 {{candidate function not viable: no known conversion from 'Iter0' to 'int' for 1st argument}}
+GoodIter operator+(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+ GoodIter begin, end;
+ Iter0 begin0, end0;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (GoodIter &I = begin; I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; --I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (GoodIter I(begin); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (GoodIter I(nullptr); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (GoodIter I(0); I < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (GoodIter I(1, 2); I < end; ++I)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (begin = GoodIter(0); begin < end; ++begin)
+ ++begin;
+// expected-error@+4 {{invalid operands to binary expression ('GoodIter' and 'Iter0')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (begin = begin0; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (++begin; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (begin = end; begin < end; ++begin)
+ ++begin;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I - I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; begin < end; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; !I; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; I = I + 1)
+ ++I;
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; I = I - 1)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; I = -I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; I = 2 + I)
+ ++I;
+#pragma omp parallel
+// expected-error@+2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+#pragma omp taskloop simd
+ for (GoodIter I = begin; I >= end; I = 2 - I)
+ ++I;
+// In the following example, we cannot update the loop variable using '+='
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (Iter0 I = begin0; I < end0; ++I)
+ ++I;
+#pragma omp parallel
+// Initializer is constructor without params.
+// expected-error@+3 {{invalid operands to binary expression ('Iter0' and 'int')}}
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (Iter0 I; I < end0; ++I)
+ ++I;
+ Iter1 begin1, end1;
+// expected-error@+4 {{invalid operands to binary expression ('Iter1' and 'Iter1')}}
+// expected-error@+3 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (Iter1 I = begin1; I < end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (Iter1 I = begin1; I >= end1; ++I)
+ ++I;
+#pragma omp parallel
+// expected-error@+5 {{invalid operands to binary expression ('Iter1' and 'float')}}
+// expected-error@+4 {{could not calculate number of iterations calling 'operator-' with upper and lower loop bounds}}
+// Initializer is constructor with all default params.
+// expected-warning@+2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+#pragma omp taskloop simd
+ for (Iter1 I; I < end1; ++I) {
+ }
+ return 0;
+}
+
+template <typename IT, int ST>
+class TC {
+public:
+ int dotest_lt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (IT I = begin; I < end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be positive due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (IT I = begin; I <= end; I += ST) {
+ ++I;
+ }
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (IT I = begin; I < end; ++I) {
+ ++I;
+ }
+ }
+
+ static IT step() {
+ return IT(ST);
+ }
+};
+template <typename IT, int ST = 0>
+int dotest_gt(IT begin, IT end) {
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (IT I = begin; I >= end; I = I + ST) {
+ ++I;
+ }
+#pragma omp parallel
+// expected-note@+3 2 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (IT I = begin; I >= end; I += ST) {
+ ++I;
+ }
+
+#pragma omp parallel
+// expected-note@+3 {{loop step is expected to be negative due to this condition}}
+// expected-error@+2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+#pragma omp taskloop simd
+ for (IT I = begin; I >= end; ++I) {
+ ++I;
+ }
+
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (IT I = begin; I < end; I += TC<int, ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ break; // OK in nested loop
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ if (c[i] > 10)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+ if (c[i] > 11)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ }
+
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ c[i] = a[i] + b[i];
+ if (c[i] > 10) {
+ if (c[i] < 20) {
+ break; // OK
+ }
+ }
+ }
+ }
+}
+
+void test_loop_eh() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ try { // expected-error {{'try' statement cannot be used in OpenMP simd region}}
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ } catch (float f) {
+ if (f > 0.1)
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ return; // expected-error {{cannot return from OpenMP region}}
+ }
+ switch (i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ for (int j = 0; j < 10; j++) {
+ if (c[i] > 10)
+ throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ }
+ if (c[9] > 10)
+ throw c[9]; // OK
+
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (int i = 0; i < 10; ++i) {
+ struct S {
+ void g() { throw 0; }
+ };
+ }
+}
+
+void test_loop_firstprivate_lastprivate() {
+ S s(4);
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(s) firstprivate(s)
+ for (int i = 0; i < 16; ++i)
+ ;
+}
+
diff --git a/test/OpenMP/taskloop_simd_misc_messages.c b/test/OpenMP/taskloop_simd_misc_messages.c
new file mode 100644
index 0000000..61c7b10
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_misc_messages.c
@@ -0,0 +1,372 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -triple x86_64-unknown-unknown -verify %s
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp taskloop simd'}}
+#pragma omp taskloop simd
+
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp taskloop simd'}}
+#pragma omp taskloop simd foo
+
+void test_no_clause() {
+ int i;
+#pragma omp taskloop simd
+ for (i = 0; i < 16; ++i)
+ ;
+
+// expected-error@+2 {{statement after '#pragma omp taskloop simd' must be a for loop}}
+#pragma omp taskloop simd
+ ++i;
+}
+
+void test_branch_protected_scope() {
+ int i = 0;
+L1:
+ ++i;
+
+ int x[24];
+
+#pragma omp parallel
+#pragma omp taskloop simd
+ for (i = 0; i < 16; ++i) {
+ if (i == 5)
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ else if (i == 6)
+ return; // expected-error {{cannot return from OpenMP region}}
+ else if (i == 7)
+ goto L2;
+ else if (i == 8) {
+ L2:
+ x[i]++;
+ }
+ }
+
+ if (x[0] == 0)
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+ else if (x[1] == 1)
+ goto L1;
+}
+
+void test_invalid_clause() {
+ int i;
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+#pragma omp taskloop simd foo bar
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-error@+1 {{directive '#pragma omp taskloop simd' cannot contain more than one 'nogroup' clause}}
+#pragma omp taskloop simd nogroup nogroup
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_non_identifiers() {
+ int i, x;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+#pragma omp taskloop simd;
+ for (i = 0; i < 16; ++i)
+ ;
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+#pragma omp parallel
+#pragma omp taskloop simd linear(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+#pragma omp taskloop simd private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-warning@+1 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+#pragma omp taskloop simd, private(x);
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+extern int foo();
+
+void test_collapse() {
+ int i;
+#pragma omp parallel
+// expected-error@+1 {{expected '('}}
+#pragma omp taskloop simd collapse
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop simd collapse(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd collapse()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop simd collapse(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop simd collapse(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+// expected-error@+1 {{expected '('}}
+#pragma omp taskloop simd collapse 4)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4,
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4, )
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4, , 4)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+#pragma omp taskloop simd collapse(4)
+ for (int i1 = 0; i1 < 16; ++i1)
+ for (int i2 = 0; i2 < 16; ++i2)
+ for (int i3 = 0; i3 < 16; ++i3)
+ for (int i4 = 0; i4 < 16; ++i4)
+ foo();
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}}
+// expected-note@+1 {{to match this '('}} expected-note@+1 {{as specified in 'collapse' clause}}
+#pragma omp taskloop simd collapse(4, 8)
+ for (i = 0; i < 16; ++i)
+ ; // expected-error {{expected 4 for loops after '#pragma omp taskloop simd', but found only 1}}
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp taskloop simd collapse(2.5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expression is not an integer constant expression}}
+#pragma omp taskloop simd collapse(foo())
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop simd collapse(-5)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop simd collapse(0)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
+#pragma omp taskloop simd collapse(5 - 5)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_private() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+#pragma omp taskloop simd private(
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd private(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd private(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd private()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd private(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop simd private(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop simd private(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd private(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd private(x, y, z)
+ for (i = 0; i < 16; ++i) {
+ x = y * i + z;
+ }
+}
+
+void test_lastprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd lastprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd lastprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd lastprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd lastprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd lastprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop simd lastprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_firstprivate() {
+ int i;
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd firstprivate(
+ for (i = 0; i < 16; ++i)
+ ;
+
+#pragma omp parallel
+// expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}}
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd firstprivate(,
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 2 {{expected expression}}
+#pragma omp taskloop simd firstprivate(, )
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd firstprivate()
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected expression}}
+#pragma omp taskloop simd firstprivate(int)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+// expected-error@+1 {{expected variable name}}
+#pragma omp taskloop simd firstprivate(0)
+ for (i = 0; i < 16; ++i)
+ ;
+
+ int x, y, z;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x) firstprivate(x)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x, y) firstprivate(x, y)
+ for (i = 0; i < 16; ++i)
+ ;
+#pragma omp parallel
+#pragma omp taskloop simd lastprivate(x, y, z) firstprivate(x, y, z)
+ for (i = 0; i < 16; ++i)
+ ;
+}
+
+void test_loop_messages() {
+ float a[100], b[100], c[100];
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp taskloop simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+#pragma omp parallel
+// expected-error@+2 {{variable must be of integer or pointer type}}
+#pragma omp taskloop simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+
+ // expected-warning@+2 {{OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed}}
+ #pragma omp taskloop simd
+ for (__int128 ii = 0; ii < 10; ii++) {
+ c[ii] = a[ii] + b[ii];
+ }
+}
+
diff --git a/test/OpenMP/taskloop_simd_num_tasks_messages.cpp b/test/OpenMP/taskloop_simd_num_tasks_messages.cpp
new file mode 100644
index 0000000..f26ee79
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_num_tasks_messages.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop simd num_tasks // expected-error {{expected '(' after 'num_tasks'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (foobool(argc)), num_tasks (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'num_tasks' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(0) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(-1) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(argc) grainsize(argc) // expected-error {{'grainsize' and 'num_tasks' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'num_tasks' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd num_tasks // expected-error {{expected '(' after 'num_tasks'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (foobool(argc)), num_tasks (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'num_tasks' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(0) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(-1) // expected-error {{argument to 'num_tasks' clause must be a strictly positive integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd num_tasks(argc) grainsize(argc) // expected-error {{'grainsize' and 'num_tasks' clause are mutually exclusive and may not appear on the same directive}} expected-note {{'num_tasks' clause is specified here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_simd_priority_messages.cpp b/test/OpenMP/taskloop_simd_priority_messages.cpp
new file mode 100644
index 0000000..a94798f
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_priority_messages.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, class S> // expected-note {{declared here}}
+int tmain(T argc, S **argv) {
+ #pragma omp taskloop simd priority // expected-error {{expected '(' after 'priority'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'priority' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority(0)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd priority // expected-error {{expected '(' after 'priority'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority () // expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc > 0 ? argv[1][0] : argv[2][argc])
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (foobool(argc)), priority (true) // expected-error {{directive '#pragma omp taskloop simd' cannot contain more than one 'priority' clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority(0)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ #pragma omp taskloop simd priority(-1) // expected-error {{argument to 'priority' clause must be a non-negative integer value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return tmain(argc, argv);
+}
diff --git a/test/OpenMP/taskloop_simd_private_messages.cpp b/test/OpenMP/taskloop_simd_private_messages.cpp
new file mode 100644
index 0000000..4a9b08a
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_private_messages.cpp
@@ -0,0 +1,195 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+
+public:
+ S2() : a(0) {}
+};
+const S2 b;
+const S2 ba[5];
+class S3 {
+ int a;
+
+public:
+ S3() : a(0) {}
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+
+public:
+ S4(int v) : a(v) {}
+};
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+
+public:
+ S5(int v) : a(v) {}
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class I, class C>
+int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i;
+#pragma omp taskloop simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(e, g)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd shared(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int v = 0;
+ int i;
+#pragma omp taskloop simd private(i)
+ for (int k = 0; k < argc; ++k) {
+ i = k;
+ v += i;
+ }
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop simd private(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ return 0;
+}
+
+void bar(S4 a[2]) {
+#pragma omp parallel
+#pragma omp taskloop simd private(a)
+ for (int i = 0; i < 2; ++i)
+ foo();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i;
+#pragma omp taskloop simd private // expected-error {{expected '(' after 'private'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private() // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argc)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(a, b) // expected-error {{private variable with incomplete type 'S1'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(B::x) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd shared(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp parallel
+ {
+ int i;
+#pragma omp taskloop simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ }
+#pragma omp parallel shared(i)
+#pragma omp parallel private(i)
+#pragma omp taskloop simd private(j)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+#pragma omp taskloop simd private(i)
+ for (int k = 0; k < argc; ++k)
+ ++k;
+ static int si;
+#pragma omp taskloop simd private(si) // OK
+ for(int k = 0; k < argc; ++k)
+ si = k + 1;
+
+ return 0;
+}
+
diff --git a/test/OpenMP/taskloop_simd_safelen_messages.cpp b/test/OpenMP/taskloop_simd_safelen_messages.cpp
new file mode 100644
index 0000000..3182c8a
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_safelen_messages.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp taskloop simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp taskloop simd safelen (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{argument to 'safelen' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen ((ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+2 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen (4)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd safelen (N) // expected-error {{argument to 'safelen' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd safelen // expected-error {{expected '(' after 'safelen'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen (4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'safelen' clause}}
+ // expected-error@+1 2 {{argument to 'safelen' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd safelen (foobool(argc)), safelen (true), safelen (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd safelen (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp taskloop simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp taskloop simd safelen(safelen(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 12, 4>' requested here}}
+ return tmain<int, char, 12, 4>(argc, argv);
+}
+
diff --git a/test/OpenMP/taskloop_simd_simdlen_messages.cpp b/test/OpenMP/taskloop_simd_simdlen_messages.cpp
new file mode 100644
index 0000000..ba3f20e
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_simdlen_messages.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+template <class T, typename S, int N, int ST> // expected-note {{declared here}}
+T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
+ #pragma omp taskloop simd simdlen // expected-error {{expected '(' after 'simdlen'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen () // expected-error {{expected expression}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+ // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
+ #pragma omp taskloop simd simdlen (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd simdlen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen (1)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen ((ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'simdlen' clause}}
+ // expected-error@+2 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen (S) // expected-error {{'S' does not refer to a value}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd simdlen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen (4)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp taskloop simd simdlen (N) // expected-error {{argument to 'simdlen' clause must be a strictly positive integer value}}
+ for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ #pragma omp taskloop simd simdlen // expected-error {{expected '(' after 'simdlen'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen (4 // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{expression is not an integral constant expression}}
+ // expected-error@+2 2 {{directive '#pragma omp taskloop simd' cannot contain more than one 'simdlen' clause}}
+ // expected-error@+1 2 {{argument to 'simdlen' clause must be a strictly positive integer value}}
+ #pragma omp taskloop simd simdlen (foobool(argc)), simdlen (true), simdlen (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp taskloop simd simdlen (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+1 {{expression is not an integral constant expression}}
+ #pragma omp taskloop simd simdlen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ // expected-error@+3 {{statement after '#pragma omp taskloop simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp taskloop simd simdlen(simdlen(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
+ foo();
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 12, 4>' requested here}}
+ return tmain<int, char, 12, 4>(argc, argv);
+}
+
diff --git a/test/OpenMP/taskwait_messages.cpp b/test/OpenMP/taskwait_messages.cpp
index 0840513..06e8e6b 100644
--- a/test/OpenMP/taskwait_messages.cpp
+++ b/test/OpenMP/taskwait_messages.cpp
@@ -27,7 +27,7 @@
#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
switch (argc)
case 1: {
#pragma omp taskwait
@@ -35,7 +35,7 @@
switch (argc) {
#pragma omp taskwait
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
break;
default: {
#pragma omp taskwait
@@ -81,7 +81,7 @@
#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
switch (argc)
case 1: {
#pragma omp taskwait
@@ -89,7 +89,7 @@
switch (argc) {
#pragma omp taskwait
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
break;
default: {
#pragma omp taskwait
diff --git a/test/OpenMP/taskyield_messages.cpp b/test/OpenMP/taskyield_messages.cpp
index 23c0b53..cfeaa63 100644
--- a/test/OpenMP/taskyield_messages.cpp
+++ b/test/OpenMP/taskyield_messages.cpp
@@ -27,7 +27,7 @@
#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
switch (argc)
case 1: {
#pragma omp taskyield
@@ -35,7 +35,7 @@
switch (argc) {
#pragma omp taskyield
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
break;
default: {
#pragma omp taskyield
@@ -81,7 +81,7 @@
#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
switch (argc)
case 1: {
#pragma omp taskyield
@@ -89,7 +89,7 @@
switch (argc) {
#pragma omp taskyield
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
break;
default: {
#pragma omp taskyield
diff --git a/test/OpenMP/teams_ast_print.cpp b/test/OpenMP/teams_ast_print.cpp
index 6cea914..292586a 100644
--- a/test/OpenMP/teams_ast_print.cpp
+++ b/test/OpenMP/teams_ast_print.cpp
@@ -37,7 +37,7 @@
#pragma omp teams
a=2;
#pragma omp target
-#pragma omp teams default(none), private(argc,b) firstprivate(argv) shared (d) reduction(+:c) reduction(max:e)
+#pragma omp teams default(none), private(argc,b) firstprivate(argv) shared (d) reduction(+:c) reduction(max:e) num_teams(C) thread_limit(d*C)
foo();
#pragma omp target
#pragma omp teams reduction(^:e, f) reduction(&& : g)
@@ -53,7 +53,7 @@
// CHECK-NEXT: #pragma omp teams
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp target
-// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e) num_teams(5) thread_limit(d * 5)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
@@ -66,7 +66,7 @@
// CHECK-NEXT: #pragma omp teams
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp target
-// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e) num_teams(1) thread_limit(d * 1)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
@@ -79,7 +79,7 @@
// CHECK-NEXT: #pragma omp teams
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp target
-// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e)
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) shared(d) reduction(+: c) reduction(max: e) num_teams(C) thread_limit(d * C)
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target
// CHECK-NEXT: #pragma omp teams reduction(^: e,f) reduction(&&: g)
@@ -101,9 +101,9 @@
a=2;
// CHECK-NEXT: a = 2;
#pragma omp target
-#pragma omp teams default(none), private(argc,b) firstprivate(argv) reduction(| : c, d) reduction(* : e)
+#pragma omp teams default(none), private(argc,b) num_teams(f) firstprivate(argv) reduction(| : c, d) reduction(* : e) thread_limit(f+g)
// CHECK-NEXT: #pragma omp target
-// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) firstprivate(argv) reduction(|: c,d) reduction(*: e)
+// CHECK-NEXT: #pragma omp teams default(none) private(argc,b) num_teams(f) firstprivate(argv) reduction(|: c,d) reduction(*: e) thread_limit(f + g)
foo();
// CHECK-NEXT: foo();
return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
diff --git a/test/OpenMP/teams_num_teams_messages.cpp b/test/OpenMP/teams_num_teams_messages.cpp
new file mode 100644
index 0000000..0187112
--- /dev/null
+++ b/test/OpenMP/teams_num_teams_messages.cpp
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+
+template <typename T, int C> // expected-note {{declared here}}
+T tmain(T argc) {
+ char **a;
+#pragma omp target
+#pragma omp teams num_teams(C)
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams // expected-error {{expected '(' after 'num_teams'}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams() // expected-error {{expected expression}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(argc > 0 ? a[1] : a[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(argc + argc)
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(argc), num_teams (argc+1) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'num_teams' clause}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(-2) // expected-error {{argument to 'num_teams' clause must be a strictly positive integer value}}
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(-10u)
+ foo();
+#pragma omp target
+#pragma omp teams num_teams(3.14) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#pragma omp target
+#pragma omp teams num_teams // expected-error {{expected '(' after 'num_teams'}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams () // expected-error {{expected expression}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (argc + argc)
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (argc), num_teams (argc+1) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'num_teams' clause}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (-2) // expected-error {{argument to 'num_teams' clause must be a strictly positive integer value}}
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (-10u)
+ foo();
+
+#pragma omp target
+#pragma omp teams num_teams (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
+ foo();
+
+ return tmain<int, 10>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 10>' requested here}}
+}
diff --git a/test/OpenMP/teams_private_messages.cpp b/test/OpenMP/teams_private_messages.cpp
index 0b0aa7c..344ef8d 100644
--- a/test/OpenMP/teams_private_messages.cpp
+++ b/test/OpenMP/teams_private_messages.cpp
@@ -13,7 +13,7 @@
mutable int a;
public:
S2():a(0) { }
- static float S2s;
+ static float S2s; // expected-note {{static data member is predetermined as shared}}
};
const S2 b;
const S2 ba[5];
@@ -96,7 +96,7 @@
#pragma omp teams private(da) // expected-error {{shared variable cannot be private}}
foo();
#pragma omp target
- #pragma omp teams private(S2::S2s)
+ #pragma omp teams private(S2::S2s) // expected-error {{shared variable cannot be private}}
foo();
#pragma omp target
#pragma omp teams private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
diff --git a/test/OpenMP/teams_reduction_messages.cpp b/test/OpenMP/teams_reduction_messages.cpp
index 260cb33..87d0348 100644
--- a/test/OpenMP/teams_reduction_messages.cpp
+++ b/test/OpenMP/teams_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - %s
void foo() {
}
@@ -16,7 +18,7 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
- static float S2s;
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
@@ -55,6 +57,9 @@
S5(int v) : a(v) {}
};
class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
int a;
public:
@@ -137,7 +142,7 @@
#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
-#pragma omp teams reduction(&& : S2::S2s)
+#pragma omp teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
foo();
#pragma omp target
#pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
@@ -265,7 +270,7 @@
#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
-#pragma omp teams reduction(&& : S2::S2s)
+#pragma omp teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
foo();
#pragma omp target
#pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
diff --git a/test/OpenMP/teams_thread_limit_messages.cpp b/test/OpenMP/teams_thread_limit_messages.cpp
new file mode 100644
index 0000000..1cb147c
--- /dev/null
+++ b/test/OpenMP/teams_thread_limit_messages.cpp
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 100 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+struct S1; // expected-note 2 {{declared here}}
+
+template <typename T, int C> // expected-note {{declared here}}
+T tmain(T argc) {
+ char **a;
+#pragma omp target
+#pragma omp teams thread_limit(C)
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit // expected-error {{expected '(' after 'thread_limit'}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit() // expected-error {{expected expression}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(argc > 0 ? a[1] : a[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(argc + argc)
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(argc), thread_limit (argc+1) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'thread_limit' clause}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(-2) // expected-error {{argument to 'thread_limit' clause must be a strictly positive integer value}}
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(-10u)
+ foo();
+#pragma omp target
+#pragma omp teams thread_limit(3.14) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+ foo();
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#pragma omp target
+#pragma omp teams thread_limit // expected-error {{expected '(' after 'thread_limit'}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit () // expected-error {{expected expression}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (argc + argc)
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (argc), thread_limit (argc+1) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'thread_limit' clause}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (-2) // expected-error {{argument to 'thread_limit' clause must be a strictly positive integer value}}
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (-10u)
+ foo();
+
+#pragma omp target
+#pragma omp teams thread_limit (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
+ foo();
+
+ return tmain<int, 10>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 10>' requested here}}
+}
diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp
index 97678b4..793f6c5 100644
--- a/test/OpenMP/threadprivate_codegen.cpp
+++ b/test/OpenMP/threadprivate_codegen.cpp
@@ -617,7 +617,7 @@
// CHECK-DEBUG: call {{.*}} [[SMAIN_DTOR:@.+]]([[SMAIN]]*
// CHECK-DEBUG: }
// CHECK-DEBUG: define {{.*}} [[SMAIN_DTOR]]([[SMAIN]]* {{.*}})
-// CHECK-TLS: define internal [[S1]]* [[GS1_TLS_INITD]] {
+// CHECK-TLS: define internal [[S1]]* [[GS1_TLS_INITD]] {{#[0-9]+}} {
// CHECK-TLS-NEXT: call void [[GS1_TLS_INIT]]
// CHECK-TLS-NEXT: ret [[S1]]* [[GS1]]
// CHECK-TLS-NEXT: }
@@ -639,15 +639,15 @@
// CHECK-TLS: call void [[ARR_X_TLS_INIT]]
// CHECK-TLS: ret [2 x [3 x [[S1]]]]* [[ARR_X]]
// CHECK-TLS: }
-// CHECK-TLS: define {{.*}} i32* [[ST_INT_ST_TLS_INITD]] {
+// CHECK-TLS: define {{.*}} i32* [[ST_INT_ST_TLS_INITD]] {{#[0-9]+}} {
// CHECK-TLS: call void [[ST_INT_ST_TLS_INIT]]
// CHECK-TLS: ret i32* [[ST_INT_ST]]
// CHECK-TLS: }
-// CHECK-TLS: define {{.*}} float* [[ST_FLOAT_ST_TLS_INITD]] {
+// CHECK-TLS: define {{.*}} float* [[ST_FLOAT_ST_TLS_INITD]] {{#[0-9]+}} {
// CHECK-TLS: call void [[ST_FLOAT_ST_TLS_INIT]]
// CHECK-TLS: ret float* [[ST_FLOAT_ST]]
// CHECK-TLS: }
-// CHECK-TLS: define {{.*}} [[S4]]* [[ST_S4_ST_TLS_INITD]] {
+// CHECK-TLS: define {{.*}} [[S4]]* [[ST_S4_ST_TLS_INITD]] {{#[0-9]+}} {
// CHECK-TLS: call void [[ST_S4_ST_TLS_INIT]]
// CHECK-TLS: ret [[S4]]* [[ST_S4_ST]]
// CHECK-TLS: }
@@ -939,9 +939,9 @@
// CHECK-TLS: define internal void @__tls_init()
// CHECK-TLS: [[GRD:%.*]] = load i8, i8* @__tls_guard
// CHECK-TLS-NEXT: [[IS_INIT:%.*]] = icmp eq i8 [[GRD]], 0
-// CHECK-TLS-NEXT: store i8 1, i8* @__tls_guard
// CHECK-TLS-NEXT: br i1 [[IS_INIT]], label %[[INIT_LABEL:[^,]+]], label %[[DONE_LABEL:[^,]+]]{{.*}}
// CHECK-TLS: [[INIT_LABEL]]
+// CHECK-TLS-NEXT: store i8 1, i8* @__tls_guard
// CHECK-TLS: call void [[GS1_CXX_INIT]]
// CHECK-TLS-NOT: call void [[GS2_CXX_INIT]]
// CHECK-TLS: call void [[ARR_X_CXX_INIT]]
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index 39a4431..8c442f4 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -96,7 +96,10 @@
static __thread int t; // expected-note {{'t' defined here}}
#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
-register int reg0 __asm__("0"); // expected-note {{'reg0' defined here}}
+// Register "0" is currently an invalid register for global register variables.
+// Use "esp" instead of "0".
+// register int reg0 __asm__("0");
+register int reg0 __asm__("esp"); // expected-note {{'reg0' defined here}}
#pragma omp threadprivate (reg0) // expected-error {{variable 'reg0' cannot be threadprivate because it is a global named register variable}}
int o; // expected-note {{candidate found by name lookup is 'o'}}
@@ -115,6 +118,7 @@
static double d1;
static double d2;
static double d3; // expected-note {{'d3' defined here}}
+ static double d4;
static TestClass LocalClass(y); // expected-error {{variable with local storage in initial value of threadprivate variable}}
#pragma omp threadprivate(LocalClass)
@@ -130,6 +134,8 @@
#pragma omp threadprivate(d3) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd3' variable declaration}}
}
#pragma omp threadprivate(d3)
+label:
+#pragma omp threadprivate(d4) // expected-error {{'#pragma omp threadprivate' cannot be an immediate substatement}}
#pragma omp threadprivate(a) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'a' variable declaration}}
return (y);
diff --git a/test/PCH/chain-default-argument-instantiation.cpp b/test/PCH/chain-default-argument-instantiation.cpp
new file mode 100644
index 0000000..0accd54
--- /dev/null
+++ b/test/PCH/chain-default-argument-instantiation.cpp
@@ -0,0 +1,50 @@
+// Test default argument instantiation in chained PCH.
+
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -include %s -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -chain-include %s -chain-include %s
+
+// With modules
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fmodules %s -chain-include %s -chain-include %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header.
+
+namespace rdar23810407 {
+ template<typename T> int f(T t) {
+ extern T rdar23810407_variable;
+ return 0;
+ }
+ template<typename T> int g(int a = f([] {}));
+}
+
+//===----------------------------------------------------------------------===//
+#elif not defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header.
+
+inline void instantiate_once() {
+ rdar23810407::g<int>();
+}
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+void test() {
+ rdar23810407::g<int>();
+}
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/chain-openmp-threadprivate.cpp b/test/PCH/chain-openmp-threadprivate.cpp
index c75b872..c7f0f41 100644
--- a/test/PCH/chain-openmp-threadprivate.cpp
+++ b/test/PCH/chain-openmp-threadprivate.cpp
@@ -9,8 +9,6 @@
// RUN: %clang_cc1 -fopenmp -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-1
// RUN: %clang_cc1 -fopenmp -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-2
-// REQUIRES: tls
-
#if !defined(PASS1)
#define PASS1
diff --git a/test/PCH/cxx-char-literal.cpp b/test/PCH/cxx-char-literal.cpp
new file mode 100644
index 0000000..0990517
--- /dev/null
+++ b/test/PCH/cxx-char-literal.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t %s
+// RUN: %clang_cc1 -std=c++1z -x ast -ast-print %t | FileCheck %s
+
+// Ensure that character literals are properly surfaced through PCH.
+
+char a = '0';
+// CHECK: char a = '0';
+
+char b = L'1';
+// CHECK: char b = L'1';
+
+char c = u8'2';
+// CHECK: char c = u8'2';
+
+char d = U'3';
+// CHECK: char d = U'3';
+
+char e = u'4';
+// CHECK: char e = u'4';
diff --git a/test/PCH/ocl_types.cl b/test/PCH/ocl_types.cl
index d788a32..21097c4 100644
--- a/test/PCH/ocl_types.cl
+++ b/test/PCH/ocl_types.cl
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s
+// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s -cl-std=CL2.0 -D__OPENCL_VERSION__=200
// Test with pch.
-// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print
+// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -cl-std=CL2.0 -D__OPENCL_VERSION__=200
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print -cl-std=CL2.0 -D__OPENCL_VERSION__=200
void foo1(img1d_t img);
@@ -24,3 +24,15 @@
void foo8(evt_t evt) {
evt_t loc_evt;
}
+
+#if __OPENCL_VERSION__ >= 200
+
+void foo9(pipe int P) {
+ int_pipe_function(P);
+}
+
+void foo10(pipe Person P) {
+ person_pipe_function(P);
+}
+
+#endif
diff --git a/test/PCH/ocl_types.h b/test/PCH/ocl_types.h
index 93cf4f6..bdc4bb1 100644
--- a/test/PCH/ocl_types.h
+++ b/test/PCH/ocl_types.h
@@ -44,6 +44,7 @@
// image2d_array_depth_t
typedef image2d_array_depth_t img2darr_dep_t;
+#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable
// image2d_msaa_t
typedef image2d_msaa_t img2dmsaa_t;
@@ -56,4 +57,14 @@
// image2d_array_msaa_depth_t
typedef image2d_array_msaa_depth_t img2darrmsaadep_t;
+// pipe specifier
+
+typedef struct _person {
+ int id;
+ const char *name;
+} Person;
+
+void int_pipe_function(pipe int);
+
+void person_pipe_function(pipe Person);
#endif
diff --git a/test/Parser/colon-colon-parentheses.cpp b/test/Parser/colon-colon-parentheses.cpp
index e031ce2..b3db4fb 100644
--- a/test/Parser/colon-colon-parentheses.cpp
+++ b/test/Parser/colon-colon-parentheses.cpp
@@ -22,9 +22,9 @@
}
#ifdef PR21815
-// expected-error@+4{{C++ requires a type specifier for all declarations}}
-// expected-error@+3{{expected unqualified-id}}
-// expected-error@+3{{expected expression}}
-// expected-error@+1{{expected ';' after top level declarator}}
-a (::(
+// expected-error@+2{{C++ requires a type specifier for all declarations}}
+// expected-error@+1{{expected unqualified-id}}
+a (::( ));
+
+::((c )); // expected-error{{expected unqualified-id}}
#endif
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index d2c97b8..43885bf 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
char *const_cast_test(const char *var)
{
@@ -41,10 +43,25 @@
typedef char* c;
typedef A* a;
void test2(char x, struct B * b) {
- (void)const_cast<::c>(&x); // expected-error{{found '<::' after a const_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- (void)dynamic_cast<::a>(b); // expected-error{{found '<::' after a dynamic_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- (void)reinterpret_cast<::c>(x); // expected-error{{found '<::' after a reinterpret_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- (void)static_cast<::c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ (void)const_cast<::c>(&x);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a const_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ (void)dynamic_cast<::a>(b);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a dynamic_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ (void)reinterpret_cast<::c>(x);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a reinterpret_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ (void)static_cast<::c>(&x);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
// Do not do digraph correction.
(void)static_cast<: :c>(&x); //\
@@ -64,8 +81,15 @@
(void)static_cast<:C c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
#define LCC <::
- test1::A LCC B> e; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- (void)static_cast LCC c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ test1::A LCC B> e;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ (void)static_cast LCC c>(&x);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
}
// This note comes from "::D[:F> A5;"
@@ -74,10 +98,25 @@
class F {};
void test3() {
- ::D<::F> A1; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- D<::F> A2; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- ::E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
- E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ ::D<::F> A1;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ D<::F> A2;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ ::E<::F>();
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
+
+ E<::F>();
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
::D< ::F> A3;
D< ::F> A4;
diff --git a/test/Parser/cxx-invalid-function-decl.cpp b/test/Parser/cxx-invalid-function-decl.cpp
new file mode 100644
index 0000000..2db2751
--- /dev/null
+++ b/test/Parser/cxx-invalid-function-decl.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Check that "::new" and "::delete" in member initializer list are diagnosed
+// correctly and don't lead to infinite loop on parsing.
+
+// Error: X() (initializer on non-constructor), "::new" is skipped.
+void f1() : X() ::new{}; // expected-error{{only constructors take base initializers}}
+
+// Errors: first "::delete" and initializer on non-constructor, others skipped.
+void f2() : ::delete, ::new, X() ::new ::delete{} // expected-error{{expected class member or base class name}}
+ // expected-error@-1{{only constructors take base initializers}}
+
+// Errors: the '::' token, "::delete" and initializer on non-constructor, others skipped.
+void f3() : ::, ::delete X(), ::new {}; // expected-error2{{expected class member or base class name}}
+ // expected-error@-1{{only constructors take base initializers}}
+
+template <class T>
+struct Base1 {
+ T x1;
+ Base1(T a1) : x1(a1) {}
+};
+
+template <class T>
+struct Base2 {
+ T x2;
+ Base2(T a2) : x2(a2) {}
+};
+
+struct S : public Base1<int>, public Base2<float> {
+ int x;
+
+ // 1-st initializer is correct (just missing ','), 2-nd incorrect, skip other.
+ S() : ::Base1<int>(0) ::new, ::Base2<float>(1.0) ::delete x(2) {} // expected-error{{expected class member or base class name}}
+ // expected-error@-1{{missing ',' between base or member initializers}}
+
+ // 1-st and 2-nd are correct, errors: '::' and "::new", others skipped.
+ S(int a) : Base1<int>(a), ::Base2<float>(1.0), ::, // expected-error{{expected class member or base class name}}
+ ::new, ! ::delete, ::Base2<() x(3) {} // expected-error{{expected class member or base class name}}
+
+ // All initializers are correct, nothing to skip, diagnose 2 missing commas.
+ S(const S &) : Base1<int>(0) ::Base2<float>(1.0) x(2) {} // expected-error2{{missing ',' between base or member initializers}}
+};
diff --git a/test/Parser/cxx-reference.cpp b/test/Parser/cxx-reference.cpp
index b62638b..58bd7ab 100644
--- a/test/Parser/cxx-reference.cpp
+++ b/test/Parser/cxx-reference.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
extern char *bork;
char *& bar = bork;
@@ -18,4 +20,7 @@
int & const volatile Z = val; /* expected-error {{'const' qualifier may not be applied}} \
expected-error {{'volatile' qualifier may not be applied}} */
-typedef int && RV; // expected-warning {{rvalue references are a C++11 extension}}
+typedef int && RV;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{rvalue references are a C++11 extension}}
+#endif
diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp
index c9cc6b8..9b8ca98 100644
--- a/test/Parser/cxx-template-argument.cpp
+++ b/test/Parser/cxx-template-argument.cpp
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify %s -fdelayed-template-parsing
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -fdelayed-template-parsing
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -fdelayed-template-parsing
template<typename T> struct A {};
@@ -22,7 +26,10 @@
void (*p)() = &t<int>;
(void)(&t<int>==p); // expected-error {{use '> ='}}
(void)(&t<int>>=p); // expected-error {{use '> >'}}
- (void)(&t<S<int>>>=p); // expected-error {{use '> >'}}
+ (void)(&t<S<int>>>=p);
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
(void)(&t<S<int>>==p); // expected-error {{use '> >'}} expected-error {{use '> ='}}
}
}
@@ -72,13 +79,17 @@
{ };
template<class T1, typename T2> struct foo5 :
- UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{unknown template name 'UnknownBase'}} \
- // expected-error {{use '> >'}}
+ UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{unknown template name 'UnknownBase'}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
{ };
template<class T1, typename T2> struct foo6 :
- UnknownBase<T1,ABC<T2,T1>>, // expected-error {{unknown template name 'UnknownBase'}} \
- // expected-error {{use '> >'}}
+ UnknownBase<T1,ABC<T2,T1>>, // expected-error {{unknown template name 'UnknownBase'}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
Known<T1> // expected-error {{too few template arguments for class template 'Known'}}
{ };
@@ -87,18 +98,24 @@
{ };
template<class T1, typename T2> struct foo8 :
- UnknownBase<X<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
- // expected-error {{use '> >'}}
+ UnknownBase<X<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
{ };
template<class T1, typename T2> struct foo9 :
- UnknownBase<Known<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
- // expected-error {{use '> >'}}
+ UnknownBase<Known<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
{ };
template<class T1, typename T2> struct foo10 :
- UnknownBase<Known<int,int>,X<int,X<int,int>>> // expected-error {{unknown template name 'UnknownBase'}} \
- // expected-error {{use '> >'}}
+ UnknownBase<Known<int,int>,X<int,X<int,int>>> // expected-error {{unknown template name 'UnknownBase'}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{use '> >'}}
+#endif
{ };
template<int N1, int N2> struct foo11 :
diff --git a/test/Parser/cxx-typeof.cpp b/test/Parser/cxx-typeof.cpp
index 1ec6e29..c9651b4 100644
--- a/test/Parser/cxx-typeof.cpp
+++ b/test/Parser/cxx-typeof.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 %s
static void test() {
int *pi;
@@ -9,5 +11,10 @@
// Part of rdar://problem/8347416; from the gcc test suite.
struct S {
int i;
- __typeof(S::i) foo(); // expected-error {{invalid use of non-static data member 'i'}}
+ __typeof(S::i) foo();
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{invalid use of non-static data member 'i'}}
+#else
+ // expected-no-diagnostics
+#endif
};
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index c2bf6fd..7deeb21 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -61,7 +61,7 @@
int z;
void init_capture() {
[n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
- [n{0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}} expected-warning{{will change meaning in a future version}}
+ [n{0}] { return; }; // expected-warning{{extension}}
[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
[n = {0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}}
[a([&b = z]{})](){}; // expected-warning 2{{extension}}
diff --git a/test/Parser/cxx1z-attributes.cpp b/test/Parser/cxx1z-attributes.cpp
index f57b47d..1267091 100644
--- a/test/Parser/cxx1z-attributes.cpp
+++ b/test/Parser/cxx1z-attributes.cpp
@@ -1,14 +1,14 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-
-namespace [[]] foo {}
-namespace [[]] {}
-namespace [[]] bad = foo; // expected-error {{attributes cannot be specified on namespace alias}}
-
-namespace [[]] A::B {} // expected-error {{attributes cannot be specified on a nested namespace definition}}
-
-enum test {
- bing [[]],
- bar [[]] = 1,
- baz [[]][[]],
- quux [[]][[]] = 4
-};
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+
+namespace [[]] foo {}
+namespace [[]] {}
+namespace [[]] bad = foo; // expected-error {{attributes cannot be specified on namespace alias}}
+
+namespace [[]] A::B {} // expected-error {{attributes cannot be specified on a nested namespace definition}}
+
+enum test {
+ bing [[]],
+ bar [[]] = 1,
+ baz [[]][[]],
+ quux [[]][[]] = 4
+};
diff --git a/test/Parser/cxx1z-coroutines.cpp b/test/Parser/cxx1z-coroutines.cpp
index 1ea2635..3e69840 100644
--- a/test/Parser/cxx1z-coroutines.cpp
+++ b/test/Parser/cxx1z-coroutines.cpp
@@ -9,7 +9,7 @@
1 + co_yield t; // expected-error {{expected expression}}
auto x = co_await t;
- auto y = co_yield t; // expected-error {{void}} FIXME
+ auto y = co_yield t;
for co_await (int x : t) {}
for co_await (int x = 0; x != 10; ++x) {} // expected-error {{'co_await' modifier can only be applied to range-based for loop}}
diff --git a/test/Parser/objc-class-property.m b/test/Parser/objc-class-property.m
new file mode 100644
index 0000000..202352c
--- /dev/null
+++ b/test/Parser/objc-class-property.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+@interface A : Root {
+ int x;
+ int z;
+}
+@property int x;
+@property int y;
+@property int z;
+@property(readonly) int ro, ro2;
+@property (class) int c;
+@property (class) int c2;
+@end
+
+@implementation A
+@dynamic x;
+@synthesize z;
+@dynamic c;
+@end
+
+int test() {
+ A *a = [[A alloc] init];
+ return a.x;
+}
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
index c9d7d5d..088e385 100644
--- a/test/Parser/objc-init.m
+++ b/test/Parser/objc-init.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -pedantic -Wno-objc-root-class %s
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class -std=c++11 %s
// rdar://5707001
@interface NSNumber;
@@ -36,8 +38,16 @@
};
struct SomeStruct z = {
- .x = [x METH2], // ok.
+ .x = [x METH2], // ok in C++98.
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'int' in initializer list}}
+ // expected-note@-3 {{insert an explicit cast to silence this issue}}
+#endif
.x [x METH2] // expected-error {{expected '=' or another designator}}
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'int' in initializer list}}
+ // expected-note@-3 {{insert an explicit cast to silence this issue}}
+#endif
};
}
diff --git a/test/Parser/objcxx-lambda-expressions-neg.mm b/test/Parser/objcxx-lambda-expressions-neg.mm
index 7cdb1a2..b2fe39d 100644
--- a/test/Parser/objcxx-lambda-expressions-neg.mm
+++ b/test/Parser/objcxx-lambda-expressions-neg.mm
@@ -1,5 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
int main() {
- []{}; // expected-error {{expected expression}}
+ []{};
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{expected expression}}
+#else
+ // expected-no-diagnostics
+#endif
+
}
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
index c6ed121..0f3e948 100644
--- a/test/Parser/objcxx0x-lambda-expressions.mm
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -21,7 +21,7 @@
[foo(bar)] () {};
[foo = bar] () {};
- [foo{bar}] () {}; // expected-error {{<initializer_list>}} expected-warning {{will change meaning}}
+ [foo{bar}] () {};
[foo = {bar}] () {}; // expected-error {{<initializer_list>}}
[foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}}
diff --git a/test/Parser/objcxx11-protocol-in-template.mm b/test/Parser/objcxx11-protocol-in-template.mm
index c5c3b6c..5c80ae9 100644
--- a/test/Parser/objcxx11-protocol-in-template.mm
+++ b/test/Parser/objcxx11-protocol-in-template.mm
@@ -8,3 +8,11 @@
vector<id<P>> v;
vector<vector<id<P>>> v2;
+
+@protocol PA;
+@protocol PB;
+
+@class NSArray<ObjectType>;
+typedef int some_t;
+
+id<PA> FA(NSArray<id<PB>> *h, some_t group);
diff --git a/test/Parser/objcxx14-protocol-in-template.mm b/test/Parser/objcxx14-protocol-in-template.mm
new file mode 100644
index 0000000..36da92e
--- /dev/null
+++ b/test/Parser/objcxx14-protocol-in-template.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+
+template<class T> class vector {};
+@protocol P @end
+
+// expected-no-diagnostics
+
+template <typename Functor> void F(Functor functor) {}
+
+// Test protocol in template within lambda capture initializer context.
+void z() {
+ id<P> x = 0;
+ (void)x;
+ F( [ x = vector<id<P>>{} ] {} );
+}
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index b5864db..dbc29cf 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -71,6 +71,9 @@
// CHECK-NEON: __ARM_NEON 1
// CHECK-NEON: __ARM_NEON_FP 0xE
+// RUN: %clang -target aarch64-none-eabi -march=armv8.1-a -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-V81A %s
+// CHECK-V81A: __ARM_FEATURE_QRDMX 1
+
// RUN: %clang -target aarch64 -march=arm64 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ARCH-NOT-ACCEPT %s
// RUN: %clang -target aarch64 -march=aarch64 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ARCH-NOT-ACCEPT %s
// CHECK-ARCH-NOT-ACCEPT: error: the clang compiler does not support
@@ -85,13 +88,17 @@
// CHECK-MTUNE-CYCLONE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+zcm" "-target-feature" "+zcz"
// RUN: %clang -target aarch64 -mcpu=cyclone -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CYCLONE %s
+// RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A35 %s
// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A53 %s
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A57 %s
// RUN: %clang -target aarch64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A72 %s
+// RUN: %clang -target aarch64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M1 %s
// CHECK-MCPU-CYCLONE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
+// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
+// CHECK-MCPU-M1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s
// CHECK-ARCH-ARM64: "-target-cpu" "cyclone" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
index 640cf9e..ae27aa0 100644
--- a/test/Preprocessor/arm-target-features.c
+++ b/test/Preprocessor/arm-target-features.c
@@ -407,4 +407,5 @@
// CHECK-V81A: __ARM_ARCH 8
// CHECK-V81A: __ARM_ARCH_8_1A__ 1
// CHECK-V81A: #define __ARM_ARCH_PROFILE 'A'
+// CHECK-V81A: __ARM_FEATURE_QRDMX 1
// CHECK-V81A: #define __ARM_FP 0xE
diff --git a/test/Preprocessor/cuda-preprocess.cu b/test/Preprocessor/cuda-preprocess.cu
new file mode 100644
index 0000000..369dfa2
--- /dev/null
+++ b/test/Preprocessor/cuda-preprocess.cu
@@ -0,0 +1,32 @@
+// Tests CUDA compilation with -E.
+
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+#ifndef __CUDA_ARCH__
+#define PREPROCESSED_AWAY
+clang_unittest_no_arch PREPROCESSED_AWAY
+#else
+clang_unittest_cuda_arch __CUDA_ARCH__
+#endif
+
+// CHECK-NOT: PREPROCESSED_AWAY
+
+// RUN: %clang -E -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 %s 2>&1 \
+// RUN: | FileCheck -check-prefix NOARCH %s
+// RUN: %clang -E -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 --cuda-host-only %s 2>&1 \
+// RUN: | FileCheck -check-prefix NOARCH %s
+// NOARCH: clang_unittest_no_arch
+
+// RUN: %clang -E -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 --cuda-device-only %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM20 %s
+// SM20: clang_unittest_cuda_arch 200
+
+// RUN: %clang -E -target x86_64-linux-gnu --cuda-gpu-arch=sm_30 --cuda-device-only %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM30 %s
+// SM30: clang_unittest_cuda_arch 300
+
+// RUN: %clang -E -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 --cuda-gpu-arch=sm_30 \
+// RUN: --cuda-device-only %s 2>&1 \
+// RUN: | FileCheck -check-prefix SM20 -check-prefix SM30 %s
diff --git a/test/Preprocessor/elfiamcu-predefines.c b/test/Preprocessor/elfiamcu-predefines.c
index af5e40e..7140c61 100644
--- a/test/Preprocessor/elfiamcu-predefines.c
+++ b/test/Preprocessor/elfiamcu-predefines.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -E -dM -triple i586-intel-elfiamcu | FileCheck %s
+// CHECK: #define __USER_LABEL_PREFIX__ {{$}}
// CHECK: #define __iamcu
// CHECK: #define __iamcu__
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 7ddb946..099e585 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -8549,20 +8549,20 @@
// WEBASSEMBLY32-NEXT:#define __INT_LEAST8_MAX__ 127{{$}}
// WEBASSEMBLY32-NEXT:#define __INT_LEAST8_TYPE__ signed char{{$}}
// WEBASSEMBLY32-NEXT:#define __INT_MAX__ 2147483647{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_DECIMAL_DIG__ 17{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_DIG__ 15{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_EPSILON__ 2.2204460492503131e-16L{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_DECIMAL_DIG__ 36{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_DIG__ 33{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L{{$}}
// WEBASSEMBLY32-NEXT:#define __LDBL_HAS_DENORM__ 1{{$}}
// WEBASSEMBLY32-NEXT:#define __LDBL_HAS_INFINITY__ 1{{$}}
// WEBASSEMBLY32-NEXT:#define __LDBL_HAS_QUIET_NAN__ 1{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MANT_DIG__ 53{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MAX_10_EXP__ 308{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MAX_EXP__ 1024{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MAX__ 1.7976931348623157e+308L{{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MIN_10_EXP__ (-307){{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MIN_EXP__ (-1021){{$}}
-// WEBASSEMBLY32-NEXT:#define __LDBL_MIN__ 2.2250738585072014e-308L{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MANT_DIG__ 113{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MAX_10_EXP__ 4932{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MAX_EXP__ 16384{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L{{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MIN_10_EXP__ (-4931){{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MIN_EXP__ (-16381){{$}}
+// WEBASSEMBLY32-NEXT:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L{{$}}
// WEBASSEMBLY32-NEXT:#define __LITTLE_ENDIAN__ 1{{$}}
// WEBASSEMBLY32-NEXT:#define __LONG_LONG_MAX__ 9223372036854775807LL{{$}}
// WEBASSEMBLY32-NEXT:#define __LONG_MAX__ 2147483647L{{$}}
@@ -8587,7 +8587,7 @@
// WEBASSEMBLY32-NEXT:#define __SIZEOF_FLOAT__ 4{{$}}
// WEBASSEMBLY32-NEXT:#define __SIZEOF_INT128__ 16{{$}}
// WEBASSEMBLY32-NEXT:#define __SIZEOF_INT__ 4{{$}}
-// WEBASSEMBLY32-NEXT:#define __SIZEOF_LONG_DOUBLE__ 8{{$}}
+// WEBASSEMBLY32-NEXT:#define __SIZEOF_LONG_DOUBLE__ 16{{$}}
// WEBASSEMBLY32-NEXT:#define __SIZEOF_LONG_LONG__ 8{{$}}
// WEBASSEMBLY32-NEXT:#define __SIZEOF_LONG__ 4{{$}}
// WEBASSEMBLY32-NEXT:#define __SIZEOF_POINTER__ 4{{$}}
@@ -8865,20 +8865,20 @@
// WEBASSEMBLY64-NEXT:#define __INT_LEAST8_MAX__ 127{{$}}
// WEBASSEMBLY64-NEXT:#define __INT_LEAST8_TYPE__ signed char{{$}}
// WEBASSEMBLY64-NEXT:#define __INT_MAX__ 2147483647{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_DECIMAL_DIG__ 17{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_DIG__ 15{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_EPSILON__ 2.2204460492503131e-16L{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_DECIMAL_DIG__ 36{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_DIG__ 33{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L{{$}}
// WEBASSEMBLY64-NEXT:#define __LDBL_HAS_DENORM__ 1{{$}}
// WEBASSEMBLY64-NEXT:#define __LDBL_HAS_INFINITY__ 1{{$}}
// WEBASSEMBLY64-NEXT:#define __LDBL_HAS_QUIET_NAN__ 1{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MANT_DIG__ 53{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MAX_10_EXP__ 308{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MAX_EXP__ 1024{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MAX__ 1.7976931348623157e+308L{{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MIN_10_EXP__ (-307){{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MIN_EXP__ (-1021){{$}}
-// WEBASSEMBLY64-NEXT:#define __LDBL_MIN__ 2.2250738585072014e-308L{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MANT_DIG__ 113{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MAX_10_EXP__ 4932{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MAX_EXP__ 16384{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L{{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MIN_10_EXP__ (-4931){{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MIN_EXP__ (-16381){{$}}
+// WEBASSEMBLY64-NEXT:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L{{$}}
// WEBASSEMBLY64-NEXT:#define __LITTLE_ENDIAN__ 1{{$}}
// WEBASSEMBLY64-NEXT:#define __LONG_LONG_MAX__ 9223372036854775807LL{{$}}
// WEBASSEMBLY64-NEXT:#define __LONG_MAX__ 9223372036854775807L{{$}}
@@ -8903,7 +8903,7 @@
// WEBASSEMBLY64-NEXT:#define __SIZEOF_FLOAT__ 4{{$}}
// WEBASSEMBLY64-NEXT:#define __SIZEOF_INT128__ 16{{$}}
// WEBASSEMBLY64-NEXT:#define __SIZEOF_INT__ 4{{$}}
-// WEBASSEMBLY64-NEXT:#define __SIZEOF_LONG_DOUBLE__ 8{{$}}
+// WEBASSEMBLY64-NEXT:#define __SIZEOF_LONG_DOUBLE__ 16{{$}}
// WEBASSEMBLY64-NEXT:#define __SIZEOF_LONG_LONG__ 8{{$}}
// WEBASSEMBLY64-NEXT:#define __SIZEOF_LONG__ 8{{$}}
// WEBASSEMBLY64-NEXT:#define __SIZEOF_POINTER__ 8{{$}}
diff --git a/test/Preprocessor/macro_paste_msextensions.c b/test/Preprocessor/macro_paste_msextensions.c
index aa5f41f..dcc5336 100644
--- a/test/Preprocessor/macro_paste_msextensions.c
+++ b/test/Preprocessor/macro_paste_msextensions.c
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -verify -fms-extensions -Wmicrosoft %s
// RUN: not %clang_cc1 -P -E -fms-extensions %s | FileCheck -strict-whitespace %s
// This horrible stuff should preprocess into (other than whitespace):
@@ -10,6 +11,7 @@
// CHECK: int foo;
#define comment /##/ dead tokens live here
+// expected-warning@+1 {{pasting two '/' tokens}}
comment This is stupidity
int bar;
@@ -18,6 +20,7 @@
#define nested(x) int x comment cute little dead tokens...
+// expected-warning@+1 {{pasting two '/' tokens}}
nested(baz) rise of the dead tokens
;
@@ -29,13 +32,13 @@
// rdar://8197149 - VC++ allows invalid token pastes: (##baz
#define foo(x) abc(x)
#define bar(y) foo(##baz(y))
-bar(q)
+bar(q) // expected-warning {{type specifier missing}} expected-error {{invalid preprocessing token}} expected-error {{parameter list without types}}
// CHECK: abc(baz(q))
#define str(x) #x
#define collapse_spaces(a, b, c, d) str(a ## - ## b ## - ## c ## d)
-collapse_spaces(1a, b2, 3c, d4)
+collapse_spaces(1a, b2, 3c, d4) // expected-error 4 {{invalid preprocessing token}} expected-error {{expected function body}}
// CHECK: "1a-b2-3cd4"
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 1254ac4..66a96e4 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -1749,10 +1749,13 @@
// CHECK_SPARC: #define __sparc 1
// CHECK_SPARC: #define __sparc__ 1
// CHECK_SPARC-NOT: #define __sparcv9 1
+// CHECK_SPARC-NOT: #define __sparcv9__ 1
// CHECK_SPARC: #define __sparcv8 1
// CHECK_SPARC-NOT: #define __sparcv9 1
+// CHECK_SPARC-NOT: #define __sparcv9__ 1
// CHECK_SPARC-V9-NOT: #define __sparcv8 1
+// CHECK_SPARC-V9: #define __sparc_v9__ 1
// CHECK_SPARC-V9: #define __sparcv9 1
// CHECK_SPARC-V9-NOT: #define __sparcv8 1
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 4130f7a..1f68a08 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -134,3 +134,15 @@
// RUN: %clang_cc1 %s -E -dM -o - -triple armv6 -target-cpu cortex-m0 \
// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_ARMv6
// CHECK-SYNC_CAS_ARMv6-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple mips -target-cpu mips2 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_MIPS \
+// RUN: --check-prefix=CHECK-SYNC_CAS_MIPS32
+// RUN: %clang_cc1 %s -E -dM -o - -triple mips64 -target-cpu mips3 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_MIPS \
+// RUN: --check-prefix=CHECK-SYNC_CAS_MIPS64
+// CHECK-SYNC_CAS_MIPS: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK-SYNC_CAS_MIPS: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK-SYNC_CAS_MIPS: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK-SYNC_CAS_MIPS32-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+// CHECK-SYNC_CAS_MIPS64: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
diff --git a/test/Preprocessor/stringize_space.c b/test/Preprocessor/stringize_space.c
index 2d79d47..ae70bf1 100644
--- a/test/Preprocessor/stringize_space.c
+++ b/test/Preprocessor/stringize_space.c
@@ -12,3 +12,9 @@
// CHECK: {{^}}"a c"{{$}}
+#define str(x) #x
+#define f(x) str(-x)
+f(
+ 1)
+
+// CHECK: {{^}}"-1"
diff --git a/test/Profile/Inputs/c-general.profdata.v3 b/test/Profile/Inputs/c-general.profdata.v3
new file mode 100644
index 0000000..06545f9
--- /dev/null
+++ b/test/Profile/Inputs/c-general.profdata.v3
Binary files differ
diff --git a/test/Profile/Inputs/max-function-count.proftext b/test/Profile/Inputs/max-function-count.proftext
new file mode 100644
index 0000000..c744f7a
--- /dev/null
+++ b/test/Profile/Inputs/max-function-count.proftext
@@ -0,0 +1,26 @@
+begin
+# Func Hash:
+10
+# Num Counters:
+2
+# Counter Values:
+1
+0
+
+main
+# Func Hash:
+0
+# Num Counters:
+1
+# Counter Values:
+1
+
+end
+# Func Hash:
+10
+# Num Counters:
+2
+# Counter Values:
+2
+2
+
diff --git a/test/Profile/c-attributes.c b/test/Profile/c-attributes.c
deleted file mode 100644
index 2dcc180..0000000
--- a/test/Profile/c-attributes.c
+++ /dev/null
@@ -1,48 +0,0 @@
-// Test that instrumentation based profiling sets function attributes correctly.
-
-// RUN: llvm-profdata merge %S/Inputs/c-attributes.proftext -o %t.profdata
-// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%t.profdata | FileCheck %s
-
-extern int atoi(const char *);
-
-// CHECK: hot_100_percent(i32{{.*}}%i) [[HOT:#[0-9]+]]
-void hot_100_percent(int i) {
- while (i > 0)
- i--;
-}
-
-// CHECK: hot_40_percent(i32{{.*}}%i) [[HOT]]
-void hot_40_percent(int i) {
- while (i > 0)
- i--;
-}
-
-// CHECK: normal_func(i32{{.*}}%i) [[NORMAL:#[0-9]+]]
-void normal_func(int i) {
- while (i > 0)
- i--;
-}
-
-// CHECK: cold_func(i32{{.*}}%i) [[COLD:#[0-9]+]]
-void cold_func(int i) {
- while (i > 0)
- i--;
-}
-
-// CHECK: attributes [[HOT]] = { inlinehint nounwind {{.*}} }
-// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} }
-// CHECK: attributes [[COLD]] = { cold nounwind {{.*}} }
-
-int main(int argc, const char *argv[]) {
- int max = atoi(argv[1]);
- int i;
- for (i = 0; i < max; i++)
- hot_100_percent(i);
- for (i = 0; i < max * 4 / 10; i++)
- hot_40_percent(i);
- for (i = 0; i < max * 2 / 10; i++)
- normal_func(i);
- for (i = 0; i < max / 200; i++)
- cold_func(i);
- return 0;
-}
diff --git a/test/Profile/c-captured.c b/test/Profile/c-captured.c
index 84fa6d3..e859628 100644
--- a/test/Profile/c-captured.c
+++ b/test/Profile/c-captured.c
@@ -3,9 +3,9 @@
// RUN: llvm-profdata merge %S/Inputs/c-captured.proftext -o %t.profdata
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE -check-prefix=PGOALL %s
-// PGOGEN: @[[DCC:__llvm_profile_counters_debug_captured]] = private global [3 x i64] zeroinitializer
-// PGOGEN: @[[CSC:"__llvm_profile_counters_c-captured.c:__captured_stmt"]] = private global [2 x i64] zeroinitializer
-// PGOGEN: @[[C1C:"__llvm_profile_counters_c-captured.c:__captured_stmt.1"]] = private global [3 x i64] zeroinitializer
+// PGOGEN: @[[DCC:__profc_debug_captured]] = private global [3 x i64] zeroinitializer
+// PGOGEN: @[[CSC:__profc_c_captured.c___captured_stmt]] = private global [2 x i64] zeroinitializer
+// PGOGEN: @[[C1C:__profc_c_captured.c___captured_stmt.1]] = private global [3 x i64] zeroinitializer
// PGOALL-LABEL: define void @debug_captured()
// PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 0
diff --git a/test/Profile/c-general.c b/test/Profile/c-general.c
index 4e123ae..03631d8 100644
--- a/test/Profile/c-general.c
+++ b/test/Profile/c-general.c
@@ -4,22 +4,22 @@
// RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s
-
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-general.profdata.v3 | FileCheck -check-prefix=PGOUSE %s
// Also check compatibility with older profiles.
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-general.profdata.v1 | FileCheck -check-prefix=PGOUSE %s
-// PGOGEN: @[[SLC:__llvm_profile_counters_simple_loops]] = private global [4 x i64] zeroinitializer
-// PGOGEN: @[[IFC:__llvm_profile_counters_conditionals]] = private global [11 x i64] zeroinitializer
-// PGOGEN: @[[EEC:__llvm_profile_counters_early_exits]] = private global [9 x i64] zeroinitializer
-// PGOGEN: @[[JMC:__llvm_profile_counters_jumps]] = private global [22 x i64] zeroinitializer
-// PGOGEN: @[[SWC:__llvm_profile_counters_switches]] = private global [19 x i64] zeroinitializer
-// PGOGEN: @[[BSC:__llvm_profile_counters_big_switch]] = private global [17 x i64] zeroinitializer
-// PGOGEN: @[[BOC:__llvm_profile_counters_boolean_operators]] = private global [8 x i64] zeroinitializer
-// PGOGEN: @[[BLC:__llvm_profile_counters_boolop_loops]] = private global [9 x i64] zeroinitializer
-// PGOGEN: @[[COC:__llvm_profile_counters_conditional_operator]] = private global [3 x i64] zeroinitializer
-// PGOGEN: @[[DFC:__llvm_profile_counters_do_fallthrough]] = private global [4 x i64] zeroinitializer
-// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = private global [1 x i64] zeroinitializer
-// PGOGEN: @[[STC:"__llvm_profile_counters_c-general.c:static_func"]] = private global [2 x i64] zeroinitializer
+// PGOGEN: @[[SLC:__profc_simple_loops]] = private global [4 x i64] zeroinitializer
+// PGOGEN: @[[IFC:__profc_conditionals]] = private global [11 x i64] zeroinitializer
+// PGOGEN: @[[EEC:__profc_early_exits]] = private global [9 x i64] zeroinitializer
+// PGOGEN: @[[JMC:__profc_jumps]] = private global [22 x i64] zeroinitializer
+// PGOGEN: @[[SWC:__profc_switches]] = private global [19 x i64] zeroinitializer
+// PGOGEN: @[[BSC:__profc_big_switch]] = private global [17 x i64] zeroinitializer
+// PGOGEN: @[[BOC:__profc_boolean_operators]] = private global [8 x i64] zeroinitializer
+// PGOGEN: @[[BLC:__profc_boolop_loops]] = private global [9 x i64] zeroinitializer
+// PGOGEN: @[[COC:__profc_conditional_operator]] = private global [3 x i64] zeroinitializer
+// PGOGEN: @[[DFC:__profc_do_fallthrough]] = private global [4 x i64] zeroinitializer
+// PGOGEN: @[[MAC:__profc_main]] = private global [1 x i64] zeroinitializer
+// PGOGEN: @[[STC:__profc_c_general.c_static_func]] = private global [2 x i64] zeroinitializer
// PGOGEN-LABEL: @simple_loops()
// PGOUSE-LABEL: @simple_loops()
diff --git a/test/Profile/c-linkage-available_externally.c b/test/Profile/c-linkage-available_externally.c
index c2ff2ab..8585bf8 100644
--- a/test/Profile/c-linkage-available_externally.c
+++ b/test/Profile/c-linkage-available_externally.c
@@ -2,10 +2,10 @@
// get thrown out.
// RUN: %clang_cc1 -O2 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage-available_externally.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_name_foo = linkonce_odr hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
+// CHECK: @__profn_foo = linkonce_odr hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_counters_foo = linkonce_odr hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-// CHECK: @__llvm_profile_data_foo = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__profc_foo = linkonce_odr hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+// CHECK: @__profd_foo = linkonce_odr hidden global { i32, i32, i64, i8*, i64*, i8*, i8*, [1 x i16] } { i32 3, i32 1, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_foo, i32 0, i32 0), i8* null, i8* null, [1 x i16] zeroinitializer }, section "__DATA,__llvm_prf_data", align 8
inline int foo(void) { return 1; }
int main(void) {
diff --git a/test/Profile/c-linkage.c b/test/Profile/c-linkage.c
index 9abbc29..e6fbda9 100644
--- a/test/Profile/c-linkage.c
+++ b/test/Profile/c-linkage.c
@@ -1,10 +1,10 @@
// Check that the profiling names we create have the linkage we expect
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_name_foo = private constant [3 x i8] c"foo"
-// CHECK: @__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak"
-// CHECK: @__llvm_profile_name_main = private constant [4 x i8] c"main"
-// CHECK: @"__llvm_profile_name_c-linkage.c:foo_internal" = private constant [24 x i8] c"c-linkage.c:foo_internal"
+// CHECK: @__profn_foo = private constant [3 x i8] c"foo"
+// CHECK: @__profn_foo_weak = weak hidden constant [8 x i8] c"foo_weak"
+// CHECK: @__profn_main = private constant [4 x i8] c"main"
+// CHECK: @__profn_c_linkage.c_foo_internal = private constant [24 x i8] c"c-linkage.c:foo_internal"
void foo(void) { }
diff --git a/test/Profile/c-unreachable-after-switch.c b/test/Profile/c-unreachable-after-switch.c
index 63add03..7d1855d 100644
--- a/test/Profile/c-unreachable-after-switch.c
+++ b/test/Profile/c-unreachable-after-switch.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -O3 -triple x86_64-apple-macosx10.10 -main-file-name c-unreachable-after-switch.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
-// CHECK: @[[C:__llvm_profile_counters_foo]] = private global [3 x i64] zeroinitializer
+// CHECK: @[[C:__profc_foo]] = private global [3 x i64] zeroinitializer
// CHECK-LABEL: @foo()
// CHECK: store {{.*}} @[[C]], i64 0, i64 0
diff --git a/test/Profile/cxx-class.cpp b/test/Profile/cxx-class.cpp
index 21cbbd6..a534140 100644
--- a/test/Profile/cxx-class.cpp
+++ b/test/Profile/cxx-class.cpp
@@ -18,7 +18,7 @@
public:
// CTRGEN-LABEL: define {{.*}} @_ZN6SimpleC2Ei(
// CTRUSE-LABEL: define {{.*}} @_ZN6SimpleC2Ei(
- // CTRGEN: store {{.*}} @[[SCC:__llvm_profile_counters__ZN6SimpleC2Ei]], i64 0, i64 0
+ // CTRGEN: store {{.*}} @[[SCC:__profc__ZN6SimpleC2Ei]], i64 0, i64 0
explicit Simple(int Member) : Member(Member) {
// CTRGEN: store {{.*}} @[[SCC]], i64 0, i64 1
// CTRUSE: br {{.*}} !prof ![[SC1:[0-9]+]]
@@ -31,7 +31,7 @@
// DTRGEN-LABEL: define {{.*}} @_ZN6SimpleD2Ev(
// DTRUSE-LABEL: define {{.*}} @_ZN6SimpleD2Ev(
- // DTRGEN: store {{.*}} @[[SDC:__llvm_profile_counters__ZN6SimpleD2Ev]], i64 0, i64 0
+ // DTRGEN: store {{.*}} @[[SDC:__profc__ZN6SimpleD2Ev]], i64 0, i64 0
~Simple() {
// DTRGEN: store {{.*}} @[[SDC]], i64 0, i64 1
// DTRUSE: br {{.*}} !prof ![[SD1:[0-9]+]]
@@ -44,7 +44,7 @@
// MTHGEN-LABEL: define {{.*}} @_ZN6Simple6methodEv(
// MTHUSE-LABEL: define {{.*}} @_ZN6Simple6methodEv(
- // MTHGEN: store {{.*}} @[[SMC:__llvm_profile_counters__ZN6Simple6methodEv]], i64 0, i64 0
+ // MTHGEN: store {{.*}} @[[SMC:__profc__ZN6Simple6methodEv]], i64 0, i64 0
void method() {
// MTHGEN: store {{.*}} @[[SMC]], i64 0, i64 1
// MTHUSE: br {{.*}} !prof ![[SM1:[0-9]+]]
@@ -58,7 +58,7 @@
// WRPGEN-LABEL: define {{.*}} @_Z14simple_wrapperv(
// WRPUSE-LABEL: define {{.*}} @_Z14simple_wrapperv(
-// WRPGEN: store {{.*}} @[[SWC:__llvm_profile_counters__Z14simple_wrapperv]], i64 0, i64 0
+// WRPGEN: store {{.*}} @[[SWC:__profc__Z14simple_wrapperv]], i64 0, i64 0
void simple_wrapper() {
// WRPGEN: store {{.*}} @[[SWC]], i64 0, i64 1
// WRPUSE: br {{.*}} !prof ![[SW1:[0-9]+]]
diff --git a/test/Profile/cxx-implicit.cpp b/test/Profile/cxx-implicit.cpp
index 79840ad..b25486a 100644
--- a/test/Profile/cxx-implicit.cpp
+++ b/test/Profile/cxx-implicit.cpp
@@ -4,7 +4,7 @@
// An implicit constructor is generated for Base. We should not emit counters
// for it.
-// CHECK-NOT: @__llvm_profile_counters__ZN4BaseC2Ev =
+// CHECK-NOT: @__profc__ZN4BaseC2Ev =
struct Base {
virtual void foo();
diff --git a/test/Profile/cxx-lambda.cpp b/test/Profile/cxx-lambda.cpp
index a111f06..26314c8 100644
--- a/test/Profile/cxx-lambda.cpp
+++ b/test/Profile/cxx-lambda.cpp
@@ -9,9 +9,9 @@
// RUN: FileCheck --input-file=%tuse -check-prefix=PGOUSE %s
// RUN: FileCheck --input-file=%tuse -check-prefix=LMBUSE %s
-// PGOGEN: @[[LWC:__llvm_profile_counters__Z7lambdasv]] = private global [4 x i64] zeroinitializer
-// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = private global [1 x i64] zeroinitializer
-// LMBGEN: @[[LFC:"__llvm_profile_counters_cxx-lambda.cpp:_ZZ7lambdasvENK3\$_0clEi"]] = private global [3 x i64] zeroinitializer
+// PGOGEN: @[[LWC:__profc__Z7lambdasv]] = private global [4 x i64] zeroinitializer
+// PGOGEN: @[[MAC:__profc_main]] = private global [1 x i64] zeroinitializer
+// LMBGEN: @[[LFC:"__profc_cxx_lambda.cpp__ZZ7lambdasvENK3\$_0clEi"]] = private global [3 x i64] zeroinitializer
// PGOGEN-LABEL: define {{.*}}void @_Z7lambdasv()
// PGOUSE-LABEL: define {{.*}}void @_Z7lambdasv()
diff --git a/test/Profile/cxx-linkage.cpp b/test/Profile/cxx-linkage.cpp
index 669e8ed..701a880 100644
--- a/test/Profile/cxx-linkage.cpp
+++ b/test/Profile/cxx-linkage.cpp
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -emit-llvm -main-file-name cxx-linkage.cpp %s -o - -fprofile-instr-generate | FileCheck %s
-// CHECK: @__llvm_profile_name__Z3foov = private constant [7 x i8] c"_Z3foov"
-// CHECK: @__llvm_profile_name__Z8foo_weakv = weak hidden constant [12 x i8] c"_Z8foo_weakv"
-// CHECK: @__llvm_profile_name_main = private constant [4 x i8] c"main"
-// CHECK: @__llvm_profile_name__Z10foo_inlinev = linkonce_odr hidden constant [15 x i8] c"_Z10foo_inlinev"
+// CHECK: @__profn__Z3foov = private constant [7 x i8] c"_Z3foov"
+// CHECK: @__profn__Z8foo_weakv = weak hidden constant [12 x i8] c"_Z8foo_weakv"
+// CHECK: @__profn_main = private constant [4 x i8] c"main"
+// CHECK: @__profn__Z10foo_inlinev = linkonce_odr hidden constant [15 x i8] c"_Z10foo_inlinev"
void foo(void) { }
diff --git a/test/Profile/cxx-rangefor.cpp b/test/Profile/cxx-rangefor.cpp
index 23be0f5..1007a70 100644
--- a/test/Profile/cxx-rangefor.cpp
+++ b/test/Profile/cxx-rangefor.cpp
@@ -7,7 +7,7 @@
// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-rangefor.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-use=%t.profdata > %tuse
// RUN: FileCheck --input-file=%tuse -check-prefix=CHECK -check-prefix=PGOUSE %s
-// PGOGEN: @[[RFC:__llvm_profile_counters__Z9range_forv]] = private global [5 x i64] zeroinitializer
+// PGOGEN: @[[RFC:__profc__Z9range_forv]] = private global [5 x i64] zeroinitializer
// CHECK-LABEL: define {{.*}}void @_Z9range_forv()
// PGOGEN: store {{.*}} @[[RFC]], i64 0, i64 0
diff --git a/test/Profile/cxx-structors.cpp b/test/Profile/cxx-structors.cpp
new file mode 100644
index 0000000..183df92
--- /dev/null
+++ b/test/Profile/cxx-structors.cpp
@@ -0,0 +1,32 @@
+// Tests for instrumentation of C++ constructors and destructors.
+//
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -x c++ %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
+
+struct Foo {
+ Foo() {}
+ Foo(int) {}
+ ~Foo() {}
+};
+
+struct Bar : public Foo {
+ Bar() {}
+ Bar(int x) : Foo(x) {}
+ ~Bar();
+};
+
+Foo foo;
+Foo foo2(1);
+Bar bar;
+
+// Profile data for complete constructors and destructors must absent.
+
+// CHECK-NOT: @__profn__ZN3FooC1Ev
+// CHECK-NOT: @__profn__ZN3FooC1Ei
+// CHECK-NOT: @__profn__ZN3FooD1Ev
+// CHECK-NOT: @__profn__ZN3BarC1Ev
+// CHECK-NOT: @__profn__ZN3BarD1Ev
+// CHECK-NOT: @__profc__ZN3FooD1Ev
+// CHECK-NOT: @__profd__ZN3FooD1Ev
+
+int main() {
+}
diff --git a/test/Profile/cxx-templates.cpp b/test/Profile/cxx-templates.cpp
index ca0e861..c24bae3 100644
--- a/test/Profile/cxx-templates.cpp
+++ b/test/Profile/cxx-templates.cpp
@@ -10,8 +10,8 @@
// RUN: FileCheck --input-file=%tuse -check-prefix=T0USE -check-prefix=ALL %s
// RUN: FileCheck --input-file=%tuse -check-prefix=T100USE -check-prefix=ALL %s
-// T0GEN: @[[T0C:__llvm_profile_counters__Z4loopILj0EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer
-// T100GEN: @[[T100C:__llvm_profile_counters__Z4loopILj100EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer
+// T0GEN: @[[T0C:__profc__Z4loopILj0EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer
+// T100GEN: @[[T100C:__profc__Z4loopILj100EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer
// T0GEN-LABEL: define linkonce_odr {{.*}}void @_Z4loopILj0EEvv()
// T0USE-LABEL: define linkonce_odr {{.*}}void @_Z4loopILj0EEvv()
diff --git a/test/Profile/cxx-throws.cpp b/test/Profile/cxx-throws.cpp
index 47d079b..6b33416 100644
--- a/test/Profile/cxx-throws.cpp
+++ b/test/Profile/cxx-throws.cpp
@@ -10,9 +10,9 @@
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -fcxx-exceptions -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -fcxx-exceptions -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s
-// PGOGEN: @[[THC:__llvm_profile_counters__Z6throwsv]] = private global [9 x i64] zeroinitializer
-// PGOGEN-EXC: @[[THC:__llvm_profile_counters__Z6throwsv]] = private global [9 x i64] zeroinitializer
-// PGOGEN: @[[UNC:__llvm_profile_counters__Z11unreachablei]] = private global [3 x i64] zeroinitializer
+// PGOGEN: @[[THC:__profc__Z6throwsv]] = private global [9 x i64] zeroinitializer
+// PGOGEN-EXC: @[[THC:__profc__Z6throwsv]] = private global [9 x i64] zeroinitializer
+// PGOGEN: @[[UNC:__profc__Z11unreachablei]] = private global [3 x i64] zeroinitializer
// PGOGEN-LABEL: @_Z6throwsv()
// PGOUSE-LABEL: @_Z6throwsv()
diff --git a/test/Profile/cxx-virtual-destructor-calls.cpp b/test/Profile/cxx-virtual-destructor-calls.cpp
index 35975c2..4affd26 100644
--- a/test/Profile/cxx-virtual-destructor-calls.cpp
+++ b/test/Profile/cxx-virtual-destructor-calls.cpp
@@ -13,18 +13,25 @@
virtual ~B();
};
-// Complete dtor
-// CHECK: @__llvm_profile_name__ZN1BD1Ev = private constant [9 x i8] c"_ZN1BD1Ev"
+// Base dtor
+// CHECK: @__profn__ZN1BD2Ev = private constant [9 x i8] c"_ZN1BD2Ev"
-// Deleting dtor
-// CHECK: @__llvm_profile_name__ZN1BD0Ev = private constant [9 x i8] c"_ZN1BD0Ev"
+// Complete dtor must not be instrumented
+// CHECK-NOT: @__profn__ZN1BD1Ev = private constant [9 x i8] c"_ZN1BD1Ev"
-// Complete dtor counters and profile data
-// CHECK: @__llvm_profile_counters__ZN1BD1Ev = private global [1 x i64] zeroinitializer
-// CHECK: @__llvm_profile_data__ZN1BD1Ev =
+// Deleting dtor must not be instrumented
+// CHECK-NOT: @__profn__ZN1BD0Ev = private constant [9 x i8] c"_ZN1BD0Ev"
-// Deleting dtor counters and profile data
-// CHECK: @__llvm_profile_counters__ZN1BD0Ev = private global [1 x i64] zeroinitializer
-// CHECK: @__llvm_profile_data__ZN1BD0Ev =
+// Base dtor counters and profile data
+// CHECK: @__profc__ZN1BD2Ev = private global [1 x i64] zeroinitializer
+// CHECK: @__profd__ZN1BD2Ev =
+
+// Complete dtor counters and profile data must absent
+// CHECK-NOT: @__profc__ZN1BD1Ev = private global [1 x i64] zeroinitializer
+// CHECK-NOT: @__profd__ZN1BD1Ev =
+
+// Deleting dtor counters and profile data must absent
+// CHECK-NOT: @__profc__ZN1BD0Ev = private global [1 x i64] zeroinitializer
+// CHECK-NOT: @__profd__ZN1BD0Ev =
B::~B() { }
diff --git a/test/Profile/func-entry.c b/test/Profile/func-entry.c
index 32c20a2..1ecae60 100644
--- a/test/Profile/func-entry.c
+++ b/test/Profile/func-entry.c
@@ -5,10 +5,10 @@
void foo(void);
-// CHECK: @foo() #0 !prof [[FOO:![0-9]+]]
+// CHECK: @foo() #{{[0-9]}} !prof [[FOO:![0-9]+]]
void foo() { return; }
-// CHECK: @main() #1 !prof [[MAIN:![0-9]+]]
+// CHECK: @main() #{{[0-9]}} !prof [[MAIN:![0-9]+]]
int main() {
int i;
for (i = 0; i < 10000; i++) foo();
diff --git a/test/Profile/max-function-count.c b/test/Profile/max-function-count.c
new file mode 100644
index 0000000..39490d7
--- /dev/null
+++ b/test/Profile/max-function-count.c
@@ -0,0 +1,24 @@
+// Test that maximum function counts are set correctly.
+
+// RUN: llvm-profdata merge %S/Inputs/max-function-count.proftext -o %t.profdata
+// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%t.profdata | FileCheck %s
+//
+int begin(int i) {
+ if (i)
+ return 0;
+ return 1;
+}
+
+int end(int i) {
+ if (i)
+ return 0;
+ return 1;
+}
+
+int main(int argc, const char *argv[]) {
+ begin(0);
+ end(1);
+ end(1);
+ return 0;
+}
+// CHECK: !{{[0-9]+}} = !{i32 1, !"MaxFunctionCount", i32 2}
diff --git a/test/Profile/objc-general.m b/test/Profile/objc-general.m
index eae1942..b6435af 100644
--- a/test/Profile/objc-general.m
+++ b/test/Profile/objc-general.m
@@ -31,9 +31,9 @@
@end;
#endif
-// PGOGEN: @[[FRC:"__llvm_profile_counters_objc-general.m:\+\[A foreach:\]"]] = private global [2 x i64] zeroinitializer
-// PGOGEN: @[[BLC:"__llvm_profile_counters_objc-general.m:__13\+\[A foreach:\]_block_invoke"]] = private global [2 x i64] zeroinitializer
-// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = private global [1 x i64] zeroinitializer
+// PGOGEN: @[[FRC:"__profc_objc_general.m_\+\[A foreach_\]"]] = private global [2 x i64] zeroinitializer
+// PGOGEN: @[[BLC:"__profc_objc_general.m___13\+\[A foreach_\]_block_invoke"]] = private global [2 x i64] zeroinitializer
+// PGOGEN: @[[MAC:__profc_main]] = private global [1 x i64] zeroinitializer
@interface A : NSObject
+ (void)foreach: (NSArray *)array;
diff --git a/test/Sema/arm_vfma.c b/test/Sema/arm_vfma.c
new file mode 100644
index 0000000..c50a414
--- /dev/null
+++ b/test/Sema/arm_vfma.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple thumbv7s-apple-ios7.0 -target-feature +neon -fsyntax-only -verify %s
+#include <arm_neon.h>
+
+// expected-no-diagnostics
+
+void func(float32x2_t v2f32, float32x4_t v4f32) {
+ vfma_f32(v2f32, v2f32, v2f32);
+ vfmaq_f32(v4f32, v4f32, v4f32);
+
+ vfms_f32(v2f32, v2f32, v2f32);
+ vfmsq_f32(v4f32, v4f32, v4f32);
+}
diff --git a/test/Sema/asm-label.c b/test/Sema/asm-label.c
new file mode 100644
index 0000000..87cda2f
--- /dev/null
+++ b/test/Sema/asm-label.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -verify %s
+
+void f();
+void f() __asm__("fish");
+void g();
+
+void f() {
+ g();
+}
+void g() __asm__("gold"); // expected-error{{cannot apply asm label to function after its first use}}
+
+void h() __asm__("hose"); // expected-note{{previous declaration is here}}
+void h() __asm__("hair"); // expected-error{{conflicting asm label}}
+
+int x;
+int x __asm__("xenon");
+int y;
+
+int test() { return y; }
+
+int y __asm__("yacht"); // expected-error{{cannot apply asm label to variable after its first use}}
+
+int z __asm__("zebra"); // expected-note{{previous declaration is here}}
+int z __asm__("zooms"); // expected-error{{conflicting asm label}}
+
+
+// No diagnostics on the following.
+void __real_readlink() __asm("readlink");
+void readlink() __asm("__protected_readlink");
+void readlink() { __real_readlink(); }
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 76e2015..d29b136 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 %s -Wno-private-extern -triple i386-pc-linux-gnu -verify -fsyntax-only
-
void f() {
int i;
@@ -154,10 +153,13 @@
// PR19837
struct foo {
int a;
- char b;
};
-register struct foo bar asm("sp"); // expected-error {{bad type for named register variable}}
-register float baz asm("sp"); // expected-error {{bad type for named register variable}}
+register struct foo bar asm("esp"); // expected-error {{bad type for named register variable}}
+register float baz asm("esp"); // expected-error {{bad type for named register variable}}
+
+register int r0 asm ("edi"); // expected-error {{register 'edi' unsuitable for global register variables on this target}}
+register long long r1 asm ("esp"); // expected-error {{size of register 'esp' does not match variable size}}
+register int r2 asm ("esp");
double f_output_constraint(void) {
double result;
@@ -212,7 +214,7 @@
unsigned int field3 : 3;
} test16_foo;
typedef __attribute__((vector_size(16))) int test16_bar;
-register int test16_baz asm("rbx");
+register int test16_baz asm("esp");
void test16()
{
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index 5f308be..9a37ec2 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -85,6 +85,9 @@
_Static_assert(!__atomic_always_lock_free(8, &i32), "");
_Static_assert(__atomic_always_lock_free(8, &i64), "");
+#define _AS1 __attribute__((address_space(1)))
+#define _AS2 __attribute__((address_space(2)))
+
void f(_Atomic(int) *i, const _Atomic(int) *ci,
_Atomic(int*) *p, _Atomic(float) *d,
int *I, const int *CI,
@@ -190,6 +193,9 @@
(void)__atomic_compare_exchange(CI, I, I, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const int *' invalid)}}
(void)__atomic_compare_exchange(I, CI, I, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}}
+ // Pointers to different address spaces are allowed.
+ _Bool cmpexch_10 = __c11_atomic_compare_exchange_strong((_Atomic int _AS1 *)0x308, (int _AS2 *)0x309, 1, memory_order_seq_cst, memory_order_seq_cst);
+
const volatile int flag_k = 0;
volatile int flag = 0;
(void)(int)__atomic_test_and_set(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}}
diff --git a/test/Sema/attr-coldhot.c b/test/Sema/attr-coldhot.c
index abadf88..972f5a5 100644
--- a/test/Sema/attr-coldhot.c
+++ b/test/Sema/attr-coldhot.c
@@ -6,5 +6,7 @@
int var1 __attribute__((__cold__)); // expected-warning{{'__cold__' attribute only applies to functions}}
int var2 __attribute__((__hot__)); // expected-warning{{'__hot__' attribute only applies to functions}}
-int qux() __attribute__((__hot__)) __attribute__((__cold__)); // expected-error{{'__hot__' and 'cold' attributes are not compatible}}
-int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__cold__' and 'hot' attributes are not compatible}}
+int qux() __attribute__((__hot__)) __attribute__((__cold__)); // expected-error{{'__hot__' and 'cold' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
+int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__cold__' and 'hot' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
diff --git a/test/Sema/attr-disable-tail-calls.c b/test/Sema/attr-disable-tail-calls.c
new file mode 100644
index 0000000..4574d5e
--- /dev/null
+++ b/test/Sema/attr-disable-tail-calls.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void __attribute__((disable_tail_calls,naked)) foo1(int a) { // expected-error {{'disable_tail_calls' and 'naked' attributes are not compatible}} expected-note {{conflicting attribute is here}}
+ __asm__("");
+}
+
+void __attribute__((naked,disable_tail_calls)) foo2(int a) { // expected-error {{'naked' and 'disable_tail_calls' attributes are not compatible}} expected-note {{conflicting attribute is here}}
+ __asm__("");
+}
+
+int g0 __attribute__((disable_tail_calls)); // expected-warning {{'disable_tail_calls' attribute only applies to functions and methods}}
+
+int foo3(int a) __attribute__((disable_tail_calls("abc"))); // expected-error {{'disable_tail_calls' attribute takes no arguments}}
diff --git a/test/Sema/attr-mode-vector-types.c b/test/Sema/attr-mode-vector-types.c
index 3893922..1567441 100644
--- a/test/Sema/attr-mode-vector-types.c
+++ b/test/Sema/attr-mode-vector-types.c
@@ -9,6 +9,14 @@
typedef float __attribute__((mode(DF))) __attribute__((vector_size(256))) vec_t6;
typedef float __attribute__((mode(XF))) __attribute__((vector_size(256))) vec_t7;
+typedef int v8qi __attribute__ ((mode(QI))) __attribute__ ((vector_size(8)));
+typedef int v8qi __attribute__ ((mode(V8QI)));
+// expected-warning@-1{{specifying vector types with the 'mode' attribute is deprecated; use the 'vector_size' attribute instead}}
+
+typedef float v4sf __attribute__((mode(V4SF)));
+// expected-warning@-1{{specifying vector types with the 'mode' attribute is deprecated; use the 'vector_size' attribute instead}}
+typedef float v4sf __attribute__((mode(SF))) __attribute__ ((vector_size(16)));
+
// Incorrect cases.
typedef float __attribute__((mode(QC))) __attribute__((vector_size(256))) vec_t8;
// expected-error@-1{{unsupported machine mode 'QC'}}
@@ -24,3 +32,5 @@
// expected-error@-2{{type of machine mode does not support base vector types}}
typedef _Complex float __attribute__((mode(XC))) __attribute__((vector_size(256))) vec_t12;
// expected-error@-1{{invalid vector element type '_Complex float'}}
+typedef int __attribute__((mode(V3QI))) v3qi;
+// expected-error@-1{{unknown machine mode 'V3QI'}}
diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c
index 49e41d2..179b181 100644
--- a/test/Sema/attr-mode.c
+++ b/test/Sema/attr-mode.c
@@ -24,6 +24,9 @@
int **__attribute((mode(QI)))* i32; // expected-error{{mode attribute}}
+__attribute__((mode(QI))) int invalid_func() { return 1; } // expected-error{{'mode' attribute only applies to variables, fields and typedefs}}
+enum invalid_enum { A1 __attribute__((mode(QI))) }; // expected-error{{'mode' attribute only applies to variables, fields and typedefs}}
+
typedef _Complex double c32 __attribute((mode(SC)));
int c32_test[sizeof(c32) == 8 ? 1 : -1];
typedef _Complex float c64 __attribute((mode(DC)));
@@ -73,3 +76,7 @@
#else
#error Unknown test architecture.
#endif
+
+struct S {
+ int n __attribute((mode(HI)));
+};
diff --git a/test/Sema/attr-notail.c b/test/Sema/attr-notail.c
index 7b8371f..4d05fcf 100644
--- a/test/Sema/attr-notail.c
+++ b/test/Sema/attr-notail.c
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int callee0() __attribute__((not_tail_called,always_inline)); // expected-error{{'not_tail_called' and 'always_inline' attributes are not compatible}}
-int callee1() __attribute__((always_inline,not_tail_called)); // expected-error{{'always_inline' and 'not_tail_called' attributes are not compatible}}
+int callee0() __attribute__((not_tail_called,always_inline)); // expected-error{{'not_tail_called' and 'always_inline' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
+int callee1() __attribute__((always_inline,not_tail_called)); // expected-error{{'always_inline' and 'not_tail_called' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
int foo(int a) {
return a ? callee0() : callee1();
diff --git a/test/Sema/attr-ownership.c b/test/Sema/attr-ownership.c
index f7969d4..fa21b03 100644
--- a/test/Sema/attr-ownership.c
+++ b/test/Sema/attr-ownership.c
@@ -9,7 +9,7 @@
void f7(void) __attribute__((ownership_takes(foo))); // expected-error {{'ownership_takes' attribute takes at least 2 arguments}}
void f8(int *i, int *j, int k) __attribute__((ownership_holds(foo, 1, 2, 4))); // expected-error {{'ownership_holds' attribute parameter 3 is out of bounds}}
-int f9 __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to non-K&R-style functions}}
+int f9 __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to non-K&R-style functions}}
void f10(int i) __attribute__((ownership_holds(foo, 1))); // expected-error {{'ownership_holds' attribute only applies to pointer arguments}}
void *f11(float i) __attribute__((ownership_returns(foo, 1))); // expected-error {{'ownership_returns' attribute only applies to integer arguments}}
@@ -19,8 +19,8 @@
void f14(int i, int j, int *k) __attribute__((ownership_holds(foo, 3))) __attribute__((ownership_takes(foo, 3))); // expected-error {{'ownership_holds' and 'ownership_takes' attributes are not compatible}}
void f15(int, int)
- __attribute__((ownership_returns(foo, 1))) // expected-note {{declared with index 1 here}}
- __attribute__((ownership_returns(foo, 2))); // expected-error {{'ownership_returns' attribute index does not match; here it is 2}}
-void f16(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_holds(foo, 1))); // OK, same index
-void f17(void*) __attribute__((ownership_takes(__, 1)));
-void f18() __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to non-K&R-style functions}}
+ __attribute__((ownership_returns(foo, 1))) // expected-note {{declared with index 1 here}}
+ __attribute__((ownership_returns(foo, 2))); // expected-error {{'ownership_returns' attribute index does not match; here it is 2}}
+void f16(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_holds(foo, 1))); // OK, same index
+void f17(void*) __attribute__((ownership_takes(__, 1)));
+void f18() __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to non-K&R-style functions}}
diff --git a/test/Sema/attr-x86-interrupt.c b/test/Sema/attr-x86-interrupt.c
new file mode 100644
index 0000000..0785fdf
--- /dev/null
+++ b/test/Sema/attr-x86-interrupt.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s
+
+struct a {
+ int b;
+};
+
+struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to non-K&R-style functions}}
+
+__attribute__((interrupt)) int foo1(void) { return 0; } // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'void' return type}}
+__attribute__((interrupt)) void foo2(void) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
+__attribute__((interrupt)) void foo3(void *a, unsigned b, int c) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
+__attribute__((interrupt)) void foo4(int a) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a pointer as the first parameter}}
+#ifdef _LP64
+// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#else
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo5(void *a, float b) {}
+#ifdef _LP64
+// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#else
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo6(float *a, int b) {}
+
+#ifdef _LP64
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo7(int *a, unsigned b) {}
+__attribute__((interrupt)) void foo8(int *a) {}
+
+void g(void (*fp)(int *));
+int main(int argc, char **argv) {
+ void *ptr = (void *)&foo7;
+ g(foo8);
+
+ (void)ptr;
+#ifndef __x86_64__
+ // expected-error@+2 {{interrupt service routine cannot be called directly}}
+#endif
+ foo7((int *)argv, argc);
+ foo8((int *)argv); // expected-error {{interrupt service routine cannot be called directly}}
+ return 0;
+}
+
diff --git a/test/Sema/auto-type.c b/test/Sema/auto-type.c
new file mode 100644
index 0000000..9fadb90
--- /dev/null
+++ b/test/Sema/auto-type.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -std=c11
+
+__auto_type a = 5; // expected-warning {{'__auto_type' is a GNU extension}}
+__extension__ __auto_type a1 = 5;
+#pragma clang diagnostic ignored "-Wgnu-auto-type"
+__auto_type b = 5.0;
+__auto_type c = &b;
+__auto_type d = (struct {int a;}) {5};
+_Static_assert(__builtin_types_compatible_p(__typeof(a), int), "");
+__auto_type e = e; // expected-error {{variable 'e' declared with '__auto_type' type cannot appear in its own initializer}}
+
+struct s { __auto_type a; }; // expected-error {{'__auto_type' not allowed in struct member}}
+
+__auto_type f = 1, g = 1.0; // expected-error {{'__auto_type' deduced as 'int' in declaration of 'f' and deduced as 'double' in declaration of 'g'}}
+
+__auto_type h() {} // expected-error {{'__auto_type' not allowed in function return type}}
+
+int i() {
+ struct bitfield { int field:2; };
+ __auto_type j = (struct bitfield){1}.field; // expected-error {{cannot pass bit-field as __auto_type initializer in C}}
+
+}
+
+int k(l)
+__auto_type l; // expected-error {{'__auto_type' not allowed in K&R-style function parameter}}
+{}
diff --git a/test/Sema/bitfield-layout.c b/test/Sema/bitfield-layout.c
index 2abd139..b96b386 100644
--- a/test/Sema/bitfield-layout.c
+++ b/test/Sema/bitfield-layout.c
@@ -1,13 +1,25 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=arm-linux-gnueabihf
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=aarch64-linux-gnu
// expected-no-diagnostics
+#include <stddef.h>
-#define CHECK_SIZE(kind, name, size) extern int name##1[sizeof(kind name) == size ? 1 : -1];
-#define CHECK_ALIGN(kind, name, size) extern int name##2[__alignof(kind name) == size ? 1 : -1];
+#define CHECK_SIZE(kind, name, size) \
+ extern int name##_1[sizeof(kind name) == size ? 1 : -1];
+#define CHECK_ALIGN(kind, name, size) \
+ extern int name##_2[__alignof(kind name) == size ? 1 : -1];
+#define CHECK_OFFSET(kind, name, member, offset) \
+ extern int name##_3[offsetof(kind name, member) == offset ? 1 : -1];
// Zero-width bit-fields
struct a {char x; int : 0; char y;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, a, 8)
+CHECK_ALIGN(struct, a, 4)
+#else
CHECK_SIZE(struct, a, 5)
CHECK_ALIGN(struct, a, 1)
+#endif
// Zero-width bit-fields with packed
struct __attribute__((packed)) a2 { short x : 9; char : 0; int y : 17; };
@@ -16,8 +28,13 @@
// Zero-width bit-fields at the end of packed struct
struct __attribute__((packed)) a3 { short x : 9; int : 0; };
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, a3, 4)
+CHECK_ALIGN(struct, a3, 4)
+#else
CHECK_SIZE(struct, a3, 4)
CHECK_ALIGN(struct, a3, 1)
+#endif
// For comparison, non-zero-width bit-fields at the end of packed struct
struct __attribute__((packed)) a4 { short x : 9; int : 1; };
@@ -25,17 +42,32 @@
CHECK_ALIGN(struct, a4, 1)
union b {char x; int : 0; char y;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(union, b, 4)
+CHECK_ALIGN(union, b, 4)
+#else
CHECK_SIZE(union, b, 1)
CHECK_ALIGN(union, b, 1)
+#endif
// Unnamed bit-field align
struct c {char x; int : 20;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, c, 4)
+CHECK_ALIGN(struct, c, 4)
+#else
CHECK_SIZE(struct, c, 4)
CHECK_ALIGN(struct, c, 1)
+#endif
union d {char x; int : 20;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(union, d, 4)
+CHECK_ALIGN(union, d, 4)
+#else
CHECK_SIZE(union, d, 3)
CHECK_ALIGN(union, d, 1)
+#endif
// Bit-field packing
struct __attribute__((packed)) e {int x : 4, y : 30, z : 30;};
@@ -56,3 +88,153 @@
CHECK_SIZE(struct, s0, 0x32100008)
CHECK_ALIGN(struct, s0, 4)
+// Bit-field with explicit align bigger than normal.
+struct g0 {
+ char a;
+ __attribute__((aligned(16))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g0, 32);
+CHECK_ALIGN(struct, g0, 16);
+CHECK_OFFSET(struct, g0, c, 17);
+
+// Bit-field with explicit align smaller than normal.
+struct g1 {
+ char a;
+ __attribute__((aligned(2))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g1, 4);
+CHECK_ALIGN(struct, g1, 4);
+CHECK_OFFSET(struct, g1, c, 3);
+
+// Same as above but without explicit align.
+struct g2 {
+ char a;
+ int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g2, 4);
+CHECK_ALIGN(struct, g2, 4);
+CHECK_OFFSET(struct, g2, c, 2);
+
+// Explicit attribute align on bit-field has precedence over packed attribute
+// applied too the struct.
+struct __attribute__((packed)) g3 {
+ char a;
+ __attribute__((aligned(16))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g3, 32);
+CHECK_ALIGN(struct, g3, 16);
+CHECK_OFFSET(struct, g3, c, 17);
+
+struct __attribute__((packed)) g4 {
+ char a;
+ __attribute__((aligned(2))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g4, 4);
+CHECK_ALIGN(struct, g4, 2);
+CHECK_OFFSET(struct, g4, c, 3);
+
+struct g5 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 24;
+};
+CHECK_SIZE(struct, g5, 4);
+CHECK_ALIGN(struct, g5, 4);
+
+struct __attribute__((packed)) g6 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 24;
+};
+CHECK_SIZE(struct, g6, 4);
+CHECK_ALIGN(struct, g6, 1);
+
+struct g7 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 25;
+};
+CHECK_SIZE(struct, g7, 8);
+CHECK_ALIGN(struct, g7, 4);
+
+struct __attribute__((packed)) g8 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 25;
+};
+CHECK_SIZE(struct, g8, 5);
+CHECK_ALIGN(struct, g8, 1);
+
+struct g9 {
+ __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2;
+ int i;
+};
+CHECK_SIZE(struct, g9, 12);
+CHECK_ALIGN(struct, g9, 4);
+
+struct __attribute__((packed)) g10 {
+ __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2;
+ int i;
+};
+CHECK_SIZE(struct, g10, 9);
+CHECK_ALIGN(struct, g10, 1);
+
+struct g11 {
+ char a;
+ __attribute__((aligned(1))) long long b : 62;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g11, 24);
+CHECK_ALIGN(struct, g11, 8);
+CHECK_OFFSET(struct, g11, c, 16);
+#else
+CHECK_SIZE(struct, g11, 16);
+CHECK_ALIGN(struct, g11, 4);
+CHECK_OFFSET(struct, g11, c, 12);
+#endif
+
+struct __attribute__((packed)) g12 {
+ char a;
+ __attribute__((aligned(1))) long long b : 62;
+ char c;
+};
+CHECK_SIZE(struct, g12, 10);
+CHECK_ALIGN(struct, g12, 1);
+CHECK_OFFSET(struct, g12, c, 9);
+
+struct g13 {
+ char a;
+ __attribute__((aligned(1))) long long : 0;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g13, 16);
+CHECK_ALIGN(struct, g13, 8);
+CHECK_OFFSET(struct, g13, c, 8);
+#else
+CHECK_SIZE(struct, g13, 5);
+CHECK_ALIGN(struct, g13, 1);
+CHECK_OFFSET(struct, g13, c, 4);
+#endif
+
+struct __attribute__((packed)) g14 {
+ char a;
+ __attribute__((aligned(1))) long long : 0;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g14, 16);
+CHECK_ALIGN(struct, g14, 8);
+CHECK_OFFSET(struct, g14, c, 8);
+#else
+CHECK_SIZE(struct, g14, 5);
+CHECK_ALIGN(struct, g14, 1);
+CHECK_OFFSET(struct, g14, c, 4);
+#endif
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
index ba8460d..810dc79 100644
--- a/test/Sema/bitfield.c
+++ b/test/Sema/bitfield.c
@@ -63,7 +63,8 @@
typedef signed Signed;
struct Test5 { unsigned n : 2; } t5;
-typedef __typeof__(t5.n) Unsigned; // Bitfield is unsigned
+// Bitfield is unsigned
+struct Test5 sometest5 = {-1}; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -1 to 3}}
typedef __typeof__(+t5.n) Signed; // ... but promotes to signed.
typedef __typeof__(t5.n + 0) Signed; // Arithmetic promotes.
diff --git a/test/Sema/callingconv-iamcu.c b/test/Sema/callingconv-iamcu.c
new file mode 100644
index 0000000..b66320e
--- /dev/null
+++ b/test/Sema/callingconv-iamcu.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 %s -fsyntax-only -triple i686-intel-elfiamcu -verify
+
+void __attribute__((fastcall)) foo(float *a) { // expected-warning {{calling convention 'fastcall' ignored for this target}}
+}
+
+void __attribute__((stdcall)) bar(float *a) { // expected-warning {{calling convention 'stdcall' ignored for this target}}
+}
+
+void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{'fastcall' attribute takes no arguments}}
+}
+
+void __attribute__((fastcall)) test2(int a, ...) { // expected-warning {{calling convention 'fastcall' ignored for this target}}
+}
+void __attribute__((stdcall)) test3(int a, ...) { // expected-warning {{calling convention 'stdcall' ignored for this target}}
+}
+void __attribute__((thiscall)) test4(int a, ...) { // expected-warning {{calling convention 'thiscall' ignored for this target}}
+}
+
+void __attribute__((cdecl)) ctest0() {}
+
+void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{'cdecl' attribute takes no arguments}}
+
+void (__attribute__((fastcall)) *pfoo)(float*) = foo; // expected-warning {{calling convention 'fastcall' ignored for this target}}
+
+void (__attribute__((stdcall)) *pbar)(float*) = bar; // expected-warning {{calling convention 'stdcall' ignored for this target}}
+
+void (*pctest0)() = ctest0;
+
+void ctest2() {}
+void (__attribute__((cdecl)) *pctest2)() = ctest2;
+
+typedef void (__attribute__((fastcall)) *Handler) (float *); // expected-warning {{calling convention 'fastcall' ignored for this target}}
+Handler H = foo;
+
+int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{'pcs' attribute takes one argument}}
+int __attribute__((pcs())) pcs2(void); // expected-error {{'pcs' attribute takes one argument}}
+int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{'pcs' attribute requires a string}} \
+ // expected-error {{invalid PCS type}}
+int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires a string}}
+/* These are ignored because the target is i386 and not ARM */
+int __attribute__((pcs("aapcs"))) pcs5(void); // expected-warning {{calling convention 'pcs' ignored for this target}}
+int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // expected-warning {{calling convention 'pcs' ignored for this target}}
+int __attribute__((pcs("foo"))) pcs7(void); // expected-error {{invalid PCS type}}
+
+void ctest3();
+void __attribute__((cdecl)) ctest3() {}
+
+typedef __attribute__((stdcall)) void (*PROC)(); // expected-warning {{calling convention 'stdcall' ignored for this target}}
+PROC __attribute__((cdecl)) ctest4(const char *x) {}
+
+void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {} // expected-warning {{calling convention 'intel_ocl_bicc' ignored for this target}}
+
+struct type_test {} __attribute__((stdcall)); // expected-warning {{calling convention 'stdcall' ignored for this target}} expected-warning {{'stdcall' attribute only applies to functions and methods}}
diff --git a/test/Sema/darwin-tls.c b/test/Sema/darwin-tls.c
new file mode 100644
index 0000000..0fcf096
--- /dev/null
+++ b/test/Sema/darwin-tls.c
@@ -0,0 +1,17 @@
+// RUN: not %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx10.6 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx10.7 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple arm64-apple-ios7.1 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios8.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple thumbv7s-apple-ios8.3 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv7s-apple-ios9.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: %clang_cc1 -fsyntax-only -triple armv7-apple-ios9.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple thumbv7k-apple-watchos1.0 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv7k-apple-watchos2.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+
+
+__thread int a;
+
+// NO-TLS: thread-local storage is not supported for the current target
+// TLS-NOT: thread-local storage is not supported for the current target
+
+wibble;
diff --git a/test/Sema/decl-in-prototype.c b/test/Sema/decl-in-prototype.c
index 4f581aa..3b8a3b8 100644
--- a/test/Sema/decl-in-prototype.c
+++ b/test/Sema/decl-in-prototype.c
@@ -35,3 +35,6 @@
void pr19018_1 (enum e19018 { qq } x); // expected-warning{{declaration of 'enum e19018' will not be visible outside of this function}}
enum e19018 qq; //expected-error{{tentative definition has type 'enum e19018' that is never completed}} \
//expected-note{{forward declaration of 'enum e19018'}}
+
+// Only warn once, even if we create two declarations.
+void f(struct q *, struct __attribute__((aligned(4))) q *); // expected-warning {{will not be visible outside}}
diff --git a/test/Sema/enable_if.c b/test/Sema/enable_if.c
index 0ee642e..0cd9c48 100644
--- a/test/Sema/enable_if.c
+++ b/test/Sema/enable_if.c
@@ -136,4 +136,10 @@
void *p3 = (void*)&f3; // expected-error{{address of overloaded function 'f3' does not match required type 'void'}} expected-note@131{{candidate function made ineligible by enable_if}} expected-note@132{{candidate function made ineligible by enable_if}}
void *p4 = (void*)f3; // expected-error{{address of overloaded function 'f3' does not match required type 'void'}} expected-note@131{{candidate function made ineligible by enable_if}} expected-note@132{{candidate function made ineligible by enable_if}}
}
+
+void f4(int m) __attribute__((enable_if(0, "")));
+void test8() {
+ void (*p1)(int) = &f4; // expected-error{{cannot take address of function 'f4' becuase it has one or more non-tautological enable_if conditions}}
+ void (*p2)(int) = f4; // expected-error{{cannot take address of function 'f4' becuase it has one or more non-tautological enable_if conditions}}
+}
#endif
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 17b1aa2..5da4f94 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -97,6 +97,7 @@
R = __alignof(P->x); // expected-error {{invalid application of 'alignof' to bit-field}}
R = __alignof(P->y); // ok.
R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bit-field}}
+ __extension__ ({ R = (__typeof__(P->x)) 2; }); // expected-error {{invalid application of 'typeof' to bit-field}}
return R;
}
diff --git a/test/Sema/implicit-builtin-freestanding.c b/test/Sema/implicit-builtin-freestanding.c
index 385cf1f..f77bccc 100644
--- a/test/Sema/implicit-builtin-freestanding.c
+++ b/test/Sema/implicit-builtin-freestanding.c
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fno-builtin %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fno-builtin-malloc %s
// expected-no-diagnostics
int malloc(int a) { return a; }
diff --git a/test/Sema/inline-asm-validate-amdgpu.cl b/test/Sema/inline-asm-validate-amdgpu.cl
new file mode 100644
index 0000000..d60b09e
--- /dev/null
+++ b/test/Sema/inline-asm-validate-amdgpu.cl
@@ -0,0 +1,14 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -x cl -triple amdgcn -fsyntax-only %s
+// expected-no-diagnostics
+
+kernel void test () {
+
+ int sgpr = 0, vgpr = 0, imm = 0;
+
+ // sgpr constraints
+ __asm__ ("s_mov_b32 %0, %1" : "=s" (sgpr) : "s" (imm) : );
+
+ // vgpr constraints
+ __asm__ ("v_mov_b32 %0, %1" : "=v" (vgpr) : "v" (imm) : );
+}
diff --git a/test/Sema/integer-overflow.c b/test/Sema/integer-overflow.c
index 44fbcd4..db5c1f4 100644
--- a/test/Sema/integer-overflow.c
+++ b/test/Sema/integer-overflow.c
@@ -145,3 +145,11 @@
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
}
+
+struct s {
+ unsigned x;
+ unsigned y;
+} s = {
+ .y = 5,
+ .x = 4 * 1024 * 1024 * 1024 // expected-warning {{overflow in expression; result is 0 with type 'int'}}
+};
diff --git a/test/Sema/internal_linkage.c b/test/Sema/internal_linkage.c
new file mode 100644
index 0000000..f4deccc
--- /dev/null
+++ b/test/Sema/internal_linkage.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int var __attribute__((internal_linkage));
+int var2 __attribute__((internal_linkage,common)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}} \
+ // expected-note{{conflicting attribute is here}}
+int var3 __attribute__((common,internal_linkage)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}} \
+ // expected-note{{conflicting attribute is here}}
+
+int var4 __attribute__((common)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}} \
+// expected-note{{previous definition is here}}
+int var4 __attribute__((internal_linkage)); // expected-note{{conflicting attribute is here}} \
+// expected-error{{'internal_linkage' attribute does not appear on the first declaration of 'var4'}}
+
+int var5 __attribute__((internal_linkage)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}}
+int var5 __attribute__((common)); // expected-note{{conflicting attribute is here}}
+
+__attribute__((internal_linkage)) int f() {}
+struct __attribute__((internal_linkage)) S { // expected-warning{{'internal_linkage' attribute only applies to variables and functions}}
+};
+
+__attribute__((internal_linkage("foo"))) int g() {} // expected-error{{'internal_linkage' attribute takes no arguments}}
diff --git a/test/Sema/mips-interrupt-attr.c b/test/Sema/mips-interrupt-attr.c
new file mode 100644
index 0000000..17344b6
--- /dev/null
+++ b/test/Sema/mips-interrupt-attr.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -triple mips-img-elf -verify -fsyntax-only
+struct a { int b; };
+
+struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions and methods}}
+
+__attribute__((interrupt("EIC"))) void foo1() {} // expected-warning {{'interrupt' attribute argument not supported: 'EIC'}}
+
+__attribute__((interrupt("eic", 1))) void foo2() {} // expected-error {{'interrupt' attribute takes no more than 1 argument}}
+
+__attribute__((interrupt("eic"))) void foo3() {}
+__attribute__((interrupt("vector=sw0"))) void foo4() {}
+__attribute__((interrupt("vector=hw0"))) void foo5() {}
+__attribute__((interrupt("vector=hw1"))) void foo6() {}
+__attribute__((interrupt("vector=hw2"))) void foo7() {}
+__attribute__((interrupt("vector=hw3"))) void foo8() {}
+__attribute__((interrupt("vector=hw4"))) void foo9() {}
+__attribute__((interrupt("vector=hw5"))) void fooa() {}
+__attribute__((interrupt(""))) void food() {}
+
+__attribute__((interrupt)) int foob() {return 0;} // expected-warning {{MIPS 'interrupt' attribute only applies to functions that have a 'void' return type}}
+__attribute__((interrupt())) void fooc(int a) {} // expected-warning {{MIPS 'interrupt' attribute only applies to functions that have no parameters}}
+__attribute__((interrupt,mips16)) void fooe() {} // expected-error {{'interrupt' and 'mips16' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+__attribute__((mips16,interrupt)) void foof() {} // expected-error {{'mips16' and 'interrupt' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+__attribute__((interrupt)) __attribute__ ((mips16)) void foo10() {} // expected-error {{'interrupt' and 'mips16' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+__attribute__((mips16)) __attribute ((interrupt)) void foo11() {} // expected-error {{'mips16' and 'interrupt' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
index 4b3df85..9503e7c 100644
--- a/test/Sema/nonnull.c
+++ b/test/Sema/nonnull.c
@@ -89,7 +89,7 @@
__attribute__((__nonnull__))
int evil_nonnull_func(int* pointer, void * pv)
{
- if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is false on first encounter}}
+ if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is 'false' on first encounter}}
return 0;
} else {
return *pointer;
@@ -101,13 +101,13 @@
else
return *pointer;
- if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is false on first encounter}}
+ if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is 'false' on first encounter}}
}
void set_param_to_null(int**);
int another_evil_nonnull_func(int* pointer, char ch, void * pv) __attribute__((nonnull(1, 3)));
int another_evil_nonnull_func(int* pointer, char ch, void * pv) {
- if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is false on first encounter}}
+ if (pointer == NULL) { // expected-warning {{comparison of nonnull parameter 'pointer' equal to a null pointer is 'false' on first encounter}}
return 0;
} else {
return *pointer;
@@ -119,7 +119,7 @@
else
return *pointer;
- if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is false on first encounter}}
+ if (pv == NULL) {} // expected-warning {{comparison of nonnull parameter 'pv' equal to a null pointer is 'false' on first encounter}}
}
extern void *returns_null(void**);
@@ -153,3 +153,17 @@
if (p) // No warning
;
}
+
+__attribute__((returns_nonnull)) void *returns_nonnull_whee();
+
+void returns_nonnull_warning_tests() {
+ if (returns_nonnull_whee() == NULL) {} // expected-warning {{comparison of nonnull function call 'returns_nonnull_whee()' equal to a null pointer is 'false' on first encounter}}
+
+ if (returns_nonnull_whee() != NULL) {} // expected-warning {{comparison of nonnull function call 'returns_nonnull_whee()' not equal to a null pointer is 'true' on first encounter}}
+
+ if (returns_nonnull_whee()) {} // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
+ if (!returns_nonnull_whee()) {} // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
+
+ int and_again = !returns_nonnull_whee(); // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
+ and_again = !returns_nonnull_whee(); // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
+}
diff --git a/test/Sema/nullability.c b/test/Sema/nullability.c
index 8a621d3..bbe5cb41 100644
--- a/test/Sema/nullability.c
+++ b/test/Sema/nullability.c
@@ -112,4 +112,7 @@
void nullable_to_nonnull(_Nullable int *ptr) {
int *a = ptr; // okay
_Nonnull int *b = ptr; // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
+ b = ptr; // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
+
+ accepts_nonnull_1(ptr); // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
}
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index 739561d..8c6c499 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -55,6 +55,26 @@
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"("
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:19-[[@LINE-3]]:19}:")"
+ (void)(i ^ i | i); // expected-warning {{'^' within '|'}} \
+ // expected-note {{place parentheses around the '^' expression to silence this warning}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:10}:"("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:15}:")"
+
+ (void)(i | i ^ i); // expected-warning {{'^' within '|'}} \
+ // expected-note {{place parentheses around the '^' expression to silence this warning}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:19-[[@LINE-3]]:19}:")"
+
+ (void)(i & i ^ i); // expected-warning {{'&' within '^'}} \
+ // expected-note {{place parentheses around the '&' expression to silence this warning}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:10}:"("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:15}:")"
+
+ (void)(i ^ i & i); // expected-warning {{'&' within '^'}} \
+ // expected-note {{place parentheses around the '&' expression to silence this warning}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:19-[[@LINE-3]]:19}:")"
+
(void)(i ||
i && i); // expected-warning {{'&&' within '||'}} \
// expected-note {{place parentheses around the '&&' expression to silence this warning}}
diff --git a/test/Sema/pass-object-size.c b/test/Sema/pass-object-size.c
new file mode 100644
index 0000000..6f375c0
--- /dev/null
+++ b/test/Sema/pass-object-size.c
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -Wincompatible-pointer-types
+//
+// Tests for the pass_object_size attribute
+// Non-failure cases are covered in test/CodeGen/pass-object-size.c
+
+void a(void *p __attribute__((pass_object_size))); //expected-error{{'pass_object_size' attribute takes one argument}}
+void b(void *p __attribute__((pass_object_size(1.0)))); //expected-error{{'pass_object_size' attribute requires parameter 1 to be an integer constant}}
+
+void c(void *p __attribute__((pass_object_size(4)))); //expected-error{{'pass_object_size' attribute requires integer constant between 0 and 3 inclusive}}
+void d(void *p __attribute__((pass_object_size(-1)))); //expected-error{{'pass_object_size' attribute requires integer constant between 0 and 3 inclusive}}
+
+void e(void *p __attribute__((pass_object_size(1ULL<<32)))); //expected-error{{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}}
+
+void f(char p __attribute__((pass_object_size(0)))); //expected-error{{'pass_object_size' attribute only applies to constant pointer arguments}}
+void g(const char p __attribute__((pass_object_size(0)))); //expected-error{{'pass_object_size' attribute only applies to constant pointer arguments}}
+void h(char *p __attribute__((pass_object_size(0)))) {} //expected-error{{pass_object_size attribute only applies to constant pointer arguments}}
+void i(char *p __attribute__((pass_object_size(0)))); // OK -- const is only necessary on definitions, not decls.
+void j(char *p __attribute__((pass_object_size(0), pass_object_size(1)))); //expected-error{{'pass_object_size' attribute can only be applied once per parameter}}
+
+#define PS(N) __attribute__((pass_object_size(N)))
+#define overloaded __attribute__((overloadable))
+void Overloaded(void *p PS(0)) overloaded; //expected-note{{previous declaration is here}}
+void Overloaded(void *p PS(1)) overloaded; //expected-error{{conflicting pass_object_size attributes on parameters}}
+void Overloaded2(void *p PS(1), void *p2 PS(0)) overloaded; //expected-note{{previous declaration is here}}
+void Overloaded2(void *p PS(0), void *p2 PS(1)) overloaded; //expected-error{{conflicting pass_object_size attributes on parameters}}
+
+void Overloaded3(void *p PS(0), void *p2) overloaded; //expected-note{{previous declaration is here}}
+void Overloaded3(void *p, void *p2 PS(0)) overloaded; //expected-error{{conflicting pass_object_size attributes on parameters}}
+
+void TakeFn(void (*)(void *));
+void TakeFnOvl(void (*)(void *)) overloaded;
+void TakeFnOvl(void (*)(int *)) overloaded;
+
+void NotOverloaded(void *p PS(0));
+void IsOverloaded(void *p PS(0)) overloaded;
+void IsOverloaded(char *p) overloaded; // char* inestead of void* is intentional
+void FunctionPtrs() {
+ void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+ void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+
+ void (*p3)(void *) = IsOverloaded; //expected-error{{initializing 'void (*)(void *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@-6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@-5{{type mismatch}}
+ void (*p4)(void *) = &IsOverloaded; //expected-error{{initializing 'void (*)(void *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@-7{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@-6{{type mismatch}}
+
+ void (*p5)(char *) = IsOverloaded;
+ void (*p6)(char *) = &IsOverloaded;
+
+ TakeFn(NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+ TakeFn(&NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+
+ TakeFnOvl(NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+ TakeFnOvl(&NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+
+ int P;
+ (&NotOverloaded)(&P); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+ (&IsOverloaded)(&P); //expected-error{{no matching function}} expected-note@35{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@36{{candidate function not viable: no known conversion from 'int *' to 'char *' for 1st argument}}
+}
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
index 417c303..abdcd8e 100644
--- a/test/Sema/struct-packed-align.c
+++ b/test/Sema/struct-packed-align.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 %s -fsyntax-only -triple=x86_64-windows-coff -verify
// Packed structs.
struct s {
@@ -138,3 +138,24 @@
extern int n1[sizeof(struct nS) == 9 ? 1 : -1];
extern int n2[__alignof(struct nS) == 1 ? 1 : -1];
#endif
+
+// Packed attribute shouldn't be ignored for bit-field of char types.
+// Note from GCC reference manual: The 4.1, 4.2 and 4.3 series of GCC ignore
+// the packed attribute on bit-fields of type char. This has been fixed in
+// GCC 4.4 but the change can lead to differences in the structure layout.
+// See the documentation of -Wpacked-bitfield-compat for more information.
+struct packed_chars {
+ char a:4;
+ char b:8 __attribute__ ((packed));
+ // expected-warning@-1 {{'packed' attribute was ignored on bit-fields with single-byte alignment in older versions of GCC and Clang}}
+ char c:4;
+};
+
+#if defined(_WIN32) && !defined(__declspec) // _MSC_VER is unavailable in cc1.
+// On Windows clang uses MSVC compatible layout in this case.
+extern int o1[sizeof(struct packed_chars) == 3 ? 1 : -1];
+extern int o2[__alignof(struct packed_chars) == 1 ? 1 : -1];
+#else
+extern int o1[sizeof(struct packed_chars) == 2 ? 1 : -1];
+extern int o2[__alignof(struct packed_chars) == 1 ? 1 : -1];
+#endif
diff --git a/test/Sema/warn-absolute-value.c b/test/Sema/warn-absolute-value.c
index 70601db..109d515 100644
--- a/test/Sema/warn-absolute-value.c
+++ b/test/Sema/warn-absolute-value.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s -Wabsolute-value
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only %s -Wabsolute-value -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s -Wabsolute-value -Wno-int-conversion
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only %s -Wabsolute-value -Wno-int-conversion -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
int abs(int);
long int labs(long int);
@@ -780,3 +780,19 @@
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
}
+long long test_array() {
+ return llabs((long long[]){1});
+ // expected-warning@-1 {{absolute value of array type}}
+}
+long long test_function_pointer() {
+ return llabs(&test_function_pointer);
+ // expected-warning@-1 {{absolute value of pointer type}}
+}
+long long test_void_pointer(void *x) {
+ return llabs(x);
+ // expected-warning@-1 {{absolute value of pointer type}}
+}
+long long test_function() {
+ return llabs(test_function);
+ // expected-warning@-1 {{absolute value of function type}}
+}
diff --git a/test/Sema/warn-documentation-crlf.c b/test/Sema/warn-documentation-crlf.c
index 99c0714..474901b 100644
--- a/test/Sema/warn-documentation-crlf.c
+++ b/test/Sema/warn-documentation-crlf.c
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdocumentation %s
-// The run line does not have '-verify' because we were crashing while printing
-// the diagnostic.
-
-// This file has DOS-style line endings (CR LF). Please don't change it to
-// Unix-style LF!
-
-// PR14591. Check that we don't crash on this.
-/**
- * @param abc
- */
-void nocrash1(int qwerty);
-
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation %s
+// The run line does not have '-verify' because we were crashing while printing
+// the diagnostic.
+
+// This file has DOS-style line endings (CR LF). Please don't change it to
+// Unix-style LF!
+
+// PR14591. Check that we don't crash on this.
+/**
+ * @param abc
+ */
+void nocrash1(int qwerty);
+
diff --git a/test/SemaCUDA/Inputs/cuda.h b/test/SemaCUDA/Inputs/cuda.h
index a9a4595..18cafdf 100644
--- a/test/SemaCUDA/Inputs/cuda.h
+++ b/test/SemaCUDA/Inputs/cuda.h
@@ -2,6 +2,9 @@
#include <stddef.h>
+// Make this file work with nvcc, for testing compatibility.
+
+#ifndef __NVCC__
#define __constant__ __attribute__((constant))
#define __device__ __attribute__((device))
#define __global__ __attribute__((global))
@@ -18,3 +21,4 @@
int cudaConfigureCall(dim3 gridSize, dim3 blockSize, size_t sharedSize = 0,
cudaStream_t stream = 0);
+#endif // !__NVCC__
diff --git a/test/SemaCUDA/asm-constraints-mixed.cu b/test/SemaCUDA/asm-constraints-mixed.cu
index ebf4424..a3b1e1a 100644
--- a/test/SemaCUDA/asm-constraints-mixed.cu
+++ b/test/SemaCUDA/asm-constraints-mixed.cu
@@ -5,14 +5,14 @@
__attribute__((device)) register long global_dev_reg asm("r0");
__attribute__((device)) register long
- global_dev_hreg asm("rax"); // device-side error
+ global_dev_hreg asm("rsp"); // device-side error
-register long global_host_reg asm("rax");
+register long global_host_reg asm("rsp");
register long global_host_dreg asm("r0"); // host-side error
__attribute__((device)) void df() {
register long local_dev_reg asm("r0");
- register long local_host_reg asm("rax"); // device-side error
+ register long local_host_reg asm("rsp"); // device-side error
short h;
// asm with PTX constraints. Some of them are PTX-specific.
__asm__("dont care" : "=h"(h) : "f"(0.0), "d"(0.0), "h"(0), "r"(0), "l"(0));
@@ -20,7 +20,7 @@
void hf() {
register long local_dev_reg asm("r0"); // host-side error
- register long local_host_reg asm("rax");
+ register long local_host_reg asm("rsp");
int a;
// Asm with x86 constraints and registers that are not supported by PTX.
__asm__("dont care" : "=a"(a) : "a"(0), "b"(0), "c"(0) : "flags");
@@ -30,8 +30,8 @@
// We should only see errors relevant to current compilation mode.
#if defined(__CUDA_ARCH__)
// Device-side compilation:
-// expected-error@8 {{unknown register name 'rax' in asm}}
-// expected-error@15 {{unknown register name 'rax' in asm}}
+// expected-error@8 {{unknown register name 'rsp' in asm}}
+// expected-error@15 {{unknown register name 'rsp' in asm}}
#else
// Host-side compilation:
// expected-error@11 {{unknown register name 'r0' in asm}}
diff --git a/test/SemaCUDA/attributes.cu b/test/SemaCUDA/attributes-on-non-cuda.cu
similarity index 92%
rename from test/SemaCUDA/attributes.cu
rename to test/SemaCUDA/attributes-on-non-cuda.cu
index ce4dc92..e9e32ce 100644
--- a/test/SemaCUDA/attributes.cu
+++ b/test/SemaCUDA/attributes-on-non-cuda.cu
@@ -1,4 +1,5 @@
-// Tests handling of CUDA attributes.
+// Tests that CUDA attributes are warnings when compiling C files, but not when
+// compiling CUDA files.
//
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s
diff --git a/test/SemaCUDA/bad-attributes.cu b/test/SemaCUDA/bad-attributes.cu
new file mode 100644
index 0000000..7e01e14
--- /dev/null
+++ b/test/SemaCUDA/bad-attributes.cu
@@ -0,0 +1,49 @@
+// Tests handling of CUDA attributes that are bad either because they're
+// applied to the wrong sort of thing, or because they're given in illegal
+// combinations.
+//
+// You should be able to run this file through nvcc for compatibility testing.
+//
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcuda-is-device -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+// Try applying attributes to functions and variables. Some should generate
+// warnings; others not.
+__device__ int a1;
+__device__ void a2();
+__host__ int b1; // expected-warning {{attribute only applies to functions}}
+__host__ void b2();
+__constant__ int c1;
+__constant__ void c2(); // expected-warning {{attribute only applies to variables}}
+__shared__ int d1;
+__shared__ void d2(); // expected-warning {{attribute only applies to variables}}
+__global__ int e1; // expected-warning {{attribute only applies to functions}}
+__global__ void e2();
+
+// Try all pairs of attributes which can be present on a function or a
+// variable. Check both orderings of the attributes, as that can matter in
+// clang.
+__device__ __host__ void z1();
+__device__ __constant__ int z2;
+__device__ __shared__ int z3;
+__device__ __global__ void z4(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__host__ __device__ void z5();
+__host__ __global__ void z6(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__constant__ __device__ int z7;
+__constant__ __shared__ int z8; // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__shared__ __device__ int z9;
+__shared__ __constant__ int z10; // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__global__ __device__ void z11(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+__global__ __host__ void z12(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
diff --git a/test/SemaCUDA/cxx11-kernel-call.cu b/test/SemaCUDA/cxx11-kernel-call.cu
new file mode 100644
index 0000000..0d80125
--- /dev/null
+++ b/test/SemaCUDA/cxx11-kernel-call.cu
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+__global__ void k1() {}
+
+template<int ...Dimensions> void k1Wrapper() {
+ void (*f)() = [] { k1<<<Dimensions, Dimensions>>>(); }; // expected-error {{initializer contains unexpanded parameter pack 'Dimensions'}}
+ void (*g[])() = { [] { k1<<<Dimensions, Dimensions>>>(); } ... }; // ok
+}
diff --git a/test/SemaCUDA/function-target-hd.cu b/test/SemaCUDA/function-target-hd.cu
index 25fcc6e..685f4f9 100644
--- a/test/SemaCUDA/function-target-hd.cu
+++ b/test/SemaCUDA/function-target-hd.cu
@@ -8,9 +8,9 @@
// host device functions are not allowed to call device functions.
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -triple nvptx-unknown-cuda -verify %s
// RUN: %clang_cc1 -fsyntax-only -fcuda-allow-host-calls-from-host-device -verify %s -DTEST_WARN_HD
-// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -fcuda-allow-host-calls-from-host-device -verify %s -DTEST_WARN_HD
+// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -triple nvptx-unknown-cuda -fcuda-allow-host-calls-from-host-device -verify %s -DTEST_WARN_HD
#include "Inputs/cuda.h"
diff --git a/test/SemaCUDA/kernel-call.cu b/test/SemaCUDA/kernel-call.cu
index 9a3d86c..47d7762 100644
--- a/test/SemaCUDA/kernel-call.cu
+++ b/test/SemaCUDA/kernel-call.cu
@@ -23,4 +23,6 @@
int (*fp)(int) = h2;
fp<<<1, 1>>>(42); // expected-error {{must have void return type}}
+
+ g1<<<undeclared, 1>>>(42); // expected-error {{use of undeclared identifier 'undeclared'}}
}
diff --git a/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp b/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
index 85123b5..3b80d09 100644
--- a/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
+++ b/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++98 -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions -Wno-error=microsoft-cast
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++98 -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
//MSVC allows forward enum declaration
diff --git a/test/SemaCXX/PR16677.cpp b/test/SemaCXX/PR16677.cpp
new file mode 100644
index 0000000..7140ac7
--- /dev/null
+++ b/test/SemaCXX/PR16677.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+class Class_With_Destructor {
+ ~Class_With_Destructor() { }
+};
+
+template <class T>
+class Base { };
+
+template<class T, // Should be angle bracket instead of comma
+class Derived : public Base<T> { // expected-error{{'Derived' cannot be defined in a type specifier}}
+ Class_With_Destructor member;
+}; // expected-error{{a non-type template parameter cannot have type 'class Derived'}}
+ // expected-error@-1{{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-2{{declaration does not declare anything}}
+
diff --git a/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp b/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
new file mode 100644
index 0000000..ec67208
--- /dev/null
+++ b/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s -DCPP98
+
+namespace std {
+ template <class _E>
+ class initializer_list
+ {};
+}
+
+template<class E> int f(std::initializer_list<E> il);
+
+
+int F = f({1, 2, 3});
+#ifdef CPP98
+//expected-error@-2{{expected expression}}
+#else
+//expected-error@-4{{cannot compile}}
+#endif
+
+
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index b521196..ffd36be 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -8,6 +8,10 @@
typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
#endif
+union IncompleteUnion;
+
+static_assert(!__is_abstract(IncompleteUnion), "unions are never abstract");
+
class C {
virtual void f() = 0; // expected-note {{unimplemented pure virtual method 'f'}}
};
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 09f280b..cca847b 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int f(double); // expected-note{{candidate function}}
int f(int); // expected-note{{candidate function}}
@@ -79,7 +81,10 @@
void q3(); // expected-note{{possible target for call}}
template<typename T1, typename T2>
void q4(); // expected-note{{possible target for call}}
- template<typename T1 = int> // expected-warning{{default template arguments for a function template are a C++11 extension}}
+ template<typename T1 = int>
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{default template arguments for a function template are a C++11 extension}}
+#endif
void q5(); // expected-note{{possible target for call}}
void h() {
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 3520245..0b65426 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -62,11 +62,11 @@
struct Redecl {
int x; // expected-note{{previous declaration is here}}
- class y { };
+ class y { }; // expected-note{{previous declaration is here}}
union {
int x; // expected-error{{member of anonymous union redeclares 'x'}}
- float y;
+ float y; // expected-error{{member of anonymous union redeclares 'y'}}
double z; // expected-note{{previous declaration is here}}
double zz; // expected-note{{previous definition is here}}
};
diff --git a/test/SemaCXX/attr-cxx0x-fixit.cpp b/test/SemaCXX/attr-cxx0x-fixit.cpp
index 6a6cdc1..69eb223 100644
--- a/test/SemaCXX/attr-cxx0x-fixit.cpp
+++ b/test/SemaCXX/attr-cxx0x-fixit.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s
-
-[[noreturn()]] void f(); // expected-error {{attribute 'noreturn' cannot have an argument list}} \
-// CHECK: fix-it:"{{.*}}":{4:11-4:13}:""
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s
+
+[[noreturn()]] void f(); // expected-error {{attribute 'noreturn' cannot have an argument list}} \
+// CHECK: fix-it:"{{.*}}":{4:11-4:13}:""
diff --git a/test/SemaCXX/attr-disable-tail-calls.cpp b/test/SemaCXX/attr-disable-tail-calls.cpp
new file mode 100644
index 0000000..d442aa6
--- /dev/null
+++ b/test/SemaCXX/attr-disable-tail-calls.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+class B {
+public:
+ [[clang::disable_tail_calls]] virtual int foo1() { return 1; }
+ [[clang::disable_tail_calls]] int foo2() { return 2; }
+};
diff --git a/test/SemaCXX/attr-no-sanitize-address.cpp b/test/SemaCXX/attr-no-sanitize-address.cpp
index 0aafe06..9499742 100644
--- a/test/SemaCXX/attr-no-sanitize-address.cpp
+++ b/test/SemaCXX/attr-no-sanitize-address.cpp
@@ -5,14 +5,14 @@
#if !__has_attribute(no_sanitize_address)
#error "Should support no_sanitize_address"
#endif
-
-void noanal_fun() NO_SANITIZE_ADDRESS;
-
-void noanal_fun_alt() __attribute__((__no_sanitize_address__));
-
-void noanal_fun_args() __attribute__((no_sanitize_address(1))); // \
- // expected-error {{'no_sanitize_address' attribute takes no arguments}}
-
+
+void noanal_fun() NO_SANITIZE_ADDRESS;
+
+void noanal_fun_alt() __attribute__((__no_sanitize_address__));
+
+void noanal_fun_args() __attribute__((no_sanitize_address(1))); // \
+ // expected-error {{'no_sanitize_address' attribute takes no arguments}}
+
int noanal_testfn(int y) NO_SANITIZE_ADDRESS;
int noanal_testfn(int y) {
diff --git a/test/SemaCXX/attr-no-sanitize-memory.cpp b/test/SemaCXX/attr-no-sanitize-memory.cpp
index 8a8d847..41809a0 100644
--- a/test/SemaCXX/attr-no-sanitize-memory.cpp
+++ b/test/SemaCXX/attr-no-sanitize-memory.cpp
@@ -5,14 +5,14 @@
#if !__has_attribute(no_sanitize_memory)
#error "Should support no_sanitize_memory"
#endif
-
-void noanal_fun() NO_SANITIZE_MEMORY;
-
-void noanal_fun_alt() __attribute__((__no_sanitize_memory__));
-
-void noanal_fun_args() __attribute__((no_sanitize_memory(1))); // \
- // expected-error {{'no_sanitize_memory' attribute takes no arguments}}
-
+
+void noanal_fun() NO_SANITIZE_MEMORY;
+
+void noanal_fun_alt() __attribute__((__no_sanitize_memory__));
+
+void noanal_fun_args() __attribute__((no_sanitize_memory(1))); // \
+ // expected-error {{'no_sanitize_memory' attribute takes no arguments}}
+
int noanal_testfn(int y) NO_SANITIZE_MEMORY;
int noanal_testfn(int y) {
diff --git a/test/SemaCXX/attr-no-sanitize-thread.cpp b/test/SemaCXX/attr-no-sanitize-thread.cpp
index 92a3fa9..d97e050 100644
--- a/test/SemaCXX/attr-no-sanitize-thread.cpp
+++ b/test/SemaCXX/attr-no-sanitize-thread.cpp
@@ -5,14 +5,14 @@
#if !__has_attribute(no_sanitize_thread)
#error "Should support no_sanitize_thread"
#endif
-
-void noanal_fun() NO_SANITIZE_THREAD;
-
-void noanal_fun_alt() __attribute__((__no_sanitize_thread__));
-
-void noanal_fun_args() __attribute__((no_sanitize_thread(1))); // \
- // expected-error {{'no_sanitize_thread' attribute takes no arguments}}
-
+
+void noanal_fun() NO_SANITIZE_THREAD;
+
+void noanal_fun_alt() __attribute__((__no_sanitize_thread__));
+
+void noanal_fun_args() __attribute__((no_sanitize_thread(1))); // \
+ // expected-error {{'no_sanitize_thread' attribute takes no arguments}}
+
int noanal_testfn(int y) NO_SANITIZE_THREAD;
int noanal_testfn(int y) {
diff --git a/test/SemaCXX/attr-x86-interrupt.cpp b/test/SemaCXX/attr-x86-interrupt.cpp
new file mode 100644
index 0000000..95abc7c
--- /dev/null
+++ b/test/SemaCXX/attr-x86-interrupt.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnux32 -fsyntax-only -verify %s
+
+struct a {
+ int b;
+ static void foo(int *a) __attribute__((interrupt)) {}
+ void *operator new(__SIZE_TYPE__) throw() __attribute__((interrupt)) { return 0; } // expected-warning {{'interrupt' attribute only applies to non-K&R-style functions}}
+};
+
+struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to non-K&R-style functions}}
+
+__attribute__((interrupt)) int foo1(void) { return 0; } // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'void' return type}}
+__attribute__((interrupt)) void foo2(void) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
+__attribute__((interrupt)) void foo3(void *a, unsigned b, int c) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter}}
+__attribute__((interrupt)) void foo4(int a) {} // expected-error-re {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a pointer as the first parameter}}
+#ifdef _LP64
+// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#else
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo5(void *a, float b) {}
+#ifdef _LP64
+// expected-error-re@+6 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#else
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned int' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo6(float *a, int b) {}
+
+#ifdef _LP64
+// expected-error-re@+4 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long' type as the second parameter}}
+#elif defined(__x86_64__)
+// expected-error-re@+2 {{{{(x86|x86-64)}} 'interrupt' attribute only applies to functions that have a 'unsigned long long' type as the second parameter}}
+#endif
+__attribute__((interrupt)) void foo7(int *a, unsigned b) {}
+__attribute__((interrupt)) void foo8(int *a) {}
+template<typename T>
+__attribute__((interrupt)) void foo9(T *a) {}
+
+template <typename T>
+void bar(T *a) {
+ foo9(a); // expected-error {{interrupt service routine cannot be called directly}}
+}
+
+template <typename Fn>
+void bar1(Fn F) {
+ F(0);
+}
+__attribute__((interrupt)) void foo(int *) {}
+
+void g(void (*fp)(int *));
+int main(int argc, char **argv) {
+ void *ptr = (void *)&foo7;
+ g(foo8);
+ (void)ptr;
+ a::foo(ptr); // expected-error {{interrupt service routine cannot be called directly}}
+ bar1(foo);
+#ifndef __x86_64__
+ // expected-error@+2 {{interrupt service routine cannot be called directly}}
+#endif
+ foo7((int *)argv, argc);
+ foo8((int *)argv); // expected-error {{interrupt service routine cannot be called directly}}
+ bar(argv); // expected-note {{in instantiation of function template specialization 'bar<char *>' requested here}}
+ return 0;
+}
+
diff --git a/test/SemaCXX/auto-cxx0x.cpp b/test/SemaCXX/auto-cxx0x.cpp
index a8f9e84..f3daf1a 100644
--- a/test/SemaCXX/auto-cxx0x.cpp
+++ b/test/SemaCXX/auto-cxx0x.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
void f() {
auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
}
+
+typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}}
diff --git a/test/SemaCXX/auto-type-from-cxx.cpp b/test/SemaCXX/auto-type-from-cxx.cpp
new file mode 100644
index 0000000..961402f
--- /dev/null
+++ b/test/SemaCXX/auto-type-from-cxx.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+
+struct A {
+ operator __auto_type() {} // expected-error {{'__auto_type' not allowed in conversion function type}}
+};
+
+__auto_type a() -> int; // expected-error {{'__auto_type' not allowed in function return type}}
+template <typename T>
+__auto_type b() { return T::x; } // expected-error {{'__auto_type' not allowed in function return type}}
+auto c() -> __auto_type { __builtin_unreachable(); } // expected-error {{'__auto_type' not allowed in function return type}}
+int d() {
+ decltype(__auto_type) e = 1; // expected-error {{expected expression}}
+ auto _ = [](__auto_type f) {}; // expected-error {{'__auto_type' not allowed in lambda parameter}}
+ __auto_type g = 2;
+ struct BitField { int field:2; };
+ __auto_type h = BitField{1}.field; // (should work from C++)
+ new __auto_type; // expected-error {{'__auto_type' not allowed in type allocated by 'new'}}
+}
+
diff --git a/test/SemaCXX/calling-conv-compat.cpp b/test/SemaCXX/calling-conv-compat.cpp
index cebac9f..20d93b4 100644
--- a/test/SemaCXX/calling-conv-compat.cpp
+++ b/test/SemaCXX/calling-conv-compat.cpp
@@ -370,6 +370,19 @@
X<fun_stdcall >::p tmpl7 = &A::method_stdcall;
X<fun_fastcall>::p tmpl8 = &A::method_fastcall;
+// Make sure we adjust thiscall to cdecl when extracting the function type from
+// a member pointer.
+template <typename> struct Y;
+
+template <typename Fn, typename C>
+struct Y<Fn C::*> {
+ typedef Fn *p;
+};
+
+void __cdecl f_cdecl();
+Y<decltype(&A::method_thiscall)>::p tmpl9 = &f_cdecl;
+
+
} // end namespace MemberPointers
// Test that lambdas that capture nothing convert to cdecl function pointers.
diff --git a/test/SemaCXX/cdtor-fn-try-block.cpp b/test/SemaCXX/cdtor-fn-try-block.cpp
index 9e903ec..d4d8d82 100644
--- a/test/SemaCXX/cdtor-fn-try-block.cpp
+++ b/test/SemaCXX/cdtor-fn-try-block.cpp
@@ -1,97 +1,97 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s -std=c++14
-
-int FileScope;
-
-struct A {
- int I;
- void f();
- A() try {
- } catch (...) {
- I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
- f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
-
- FileScope = 12; // ok
- A a;
- a.I = 12; // ok
- }
-};
-
-struct B {
- int I;
- void f();
-};
-
-struct C : B {
- C() try {
- } catch (...) {
- I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
- f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
- }
-};
-
-struct D {
- static int I;
- static void f();
-
- D() try {
- } catch (...) {
- I = 12; // ok
- f(); // ok
- }
-};
-int D::I;
-
-struct E {
- int I;
- void f();
- static int J;
- static void g();
-
- ~E() try {
- } catch (...) {
- I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}}
- f(); // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}}
-
- J = 12; // ok
- g(); // ok
- }
-};
-int E::J;
-
-struct F {
- static int I;
- static void f();
-};
-int F::I;
-
-struct G : F {
- G() try {
- } catch (...) {
- I = 12; // ok
- f(); // ok
- }
-};
-
-struct H {
- struct A {};
- enum {
- E
- };
-
- H() try {
- } catch (...) {
- H::A a; // ok
- int I = E; // ok
- }
-};
-
-struct I {
- int J;
-
- I() {
- try { // not a function-try-block
- } catch (...) {
- J = 12; // ok
- }
- }
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s -std=c++14
+
+int FileScope;
+
+struct A {
+ int I;
+ void f();
+ A() try {
+ } catch (...) {
+ I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
+ f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
+
+ FileScope = 12; // ok
+ A a;
+ a.I = 12; // ok
+ }
+};
+
+struct B {
+ int I;
+ void f();
+};
+
+struct C : B {
+ C() try {
+ } catch (...) {
+ I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
+ f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}}
+ }
+};
+
+struct D {
+ static int I;
+ static void f();
+
+ D() try {
+ } catch (...) {
+ I = 12; // ok
+ f(); // ok
+ }
+};
+int D::I;
+
+struct E {
+ int I;
+ void f();
+ static int J;
+ static void g();
+
+ ~E() try {
+ } catch (...) {
+ I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}}
+ f(); // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}}
+
+ J = 12; // ok
+ g(); // ok
+ }
+};
+int E::J;
+
+struct F {
+ static int I;
+ static void f();
+};
+int F::I;
+
+struct G : F {
+ G() try {
+ } catch (...) {
+ I = 12; // ok
+ f(); // ok
+ }
+};
+
+struct H {
+ struct A {};
+ enum {
+ E
+ };
+
+ H() try {
+ } catch (...) {
+ H::A a; // ok
+ int I = E; // ok
+ }
+};
+
+struct I {
+ int J;
+
+ I() {
+ try { // not a function-try-block
+ } catch (...) {
+ J = 12; // ok
+ }
+ }
};
\ No newline at end of file
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index 73f3dce..b757fcb 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -17,9 +17,9 @@
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
while (struct NewS *x=0) ;
- while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
- while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
- switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}}
+ while (struct S {} *x=0) ; // expected-error {{'S' cannot be defined in a condition}}
+ while (struct {} *x=0) ; // expected-error-re {{'(anonymous struct at {{.*}})' cannot be defined in a condition}}
+ switch (enum {E} x=0) ; // expected-error-re {{'(anonymous enum at {{.*}})' cannot be defined in a condition}}
if (int x=0) { // expected-note 2 {{previous definition is here}}
int x; // expected-error {{redefinition of 'x'}}
@@ -59,7 +59,7 @@
template <class>
void test5() {
- if (struct S {}* p = 0) // expected-error {{types may not be defined in conditions}}
+ if (struct S {}* p = 0) // expected-error {{'S' cannot be defined in a condition}}
;
}
void test5_inst() {
diff --git a/test/SemaCXX/const-cast.cpp b/test/SemaCXX/const-cast.cpp
index 330e186..87df61c 100644
--- a/test/SemaCXX/const-cast.cpp
+++ b/test/SemaCXX/const-cast.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A {};
@@ -38,8 +40,10 @@
f *fpp = const_cast<f*>(&fp);
int const A::* const A::*icapcap = 0;
int A::* A::* iapap = const_cast<int A::* A::*>(icapcap);
- (void)const_cast<A&&>(A()); // expected-warning {{C++11}}
-
+ (void)const_cast<A&&>(A());
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{rvalue references are a C++11 extension}}
+#endif
return var4;
}
@@ -61,7 +65,10 @@
f fp2 = const_cast<f>(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}}
void (A::*mfn)() = 0;
(void)const_cast<void (A::*)()>(mfn); // expected-error-re {{const_cast to 'void (A::*)(){{( __attribute__\(\(thiscall\)\))?}}', which is not a reference, pointer-to-object, or pointer-to-data-member}}
- (void)const_cast<int&&>(0); // expected-error {{const_cast from rvalue to reference type 'int &&'}} expected-warning {{C++11}}
+ (void)const_cast<int&&>(0); // expected-error {{const_cast from rvalue to reference type 'int &&'}}
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{rvalue references are a C++11 extension}}
+#endif
return **var3;
}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 794932d..7b9d015 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -327,7 +327,7 @@
};
extern char externalvar[];
-constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}}
+constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}}
constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}}
static_assert(0 != "foo", "");
@@ -1874,10 +1874,9 @@
0;
}
- // FIXME: We should diagnose the cast to long here, not the division by zero.
constexpr int n = // expected-error {{must be initialized by a constant expression}}
- (int *)(long)&n == &n ?
- 1 / 0 : // expected-warning {{division by zero}} expected-note {{division by zero}}
+ (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
+ 1 / 0 : // expected-warning {{division by zero}}
0;
}
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index a344453..e9ecbe8 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -462,7 +462,7 @@
if ((c % 7) == 0) break;
} while (c != 21);
- return a == 10 && b == 12 & c == 14;
+ return a == 10 && b == 12 && c == 14;
}
static_assert(breaks_work(), "");
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
index e01acdd..f82a692 100644
--- a/test/SemaCXX/constant-expression.cpp
+++ b/test/SemaCXX/constant-expression.cpp
@@ -141,3 +141,5 @@
unsigned w = ({int a = b.val[sizeof(0)]; 0; }); // expected-warning {{use of GNU statement expression extension}}
}
}
+
+char PR17381_ice = 1000000 * 1000000; // expected-warning {{overflow}} expected-warning {{changes value}}
diff --git a/test/SemaCXX/constexpr-printing.cpp b/test/SemaCXX/constexpr-printing.cpp
index e545f45..7f6a9c6 100644
--- a/test/SemaCXX/constexpr-printing.cpp
+++ b/test/SemaCXX/constexpr-printing.cpp
@@ -90,10 +90,12 @@
constexpr char32_t c32_err = get(U"\U00110000"); // expected-error {{invalid universal character}}
+#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
+
typedef decltype(sizeof(int)) LabelDiffTy;
constexpr LabelDiffTy mulBy3(LabelDiffTy x) { return x * 3; } // expected-note {{subexpression}}
void LabelDiffTest() {
- static_assert(mulBy3((LabelDiffTy)&&a-(LabelDiffTy)&&b) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
+ static_assert(mulBy3(fold((LabelDiffTy)&&a-(LabelDiffTy)&&b)) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
a:b:return;
}
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index e3ab610..c5de33c 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify -std=c++11 %s
+
class A {
int m;
public:
@@ -98,9 +101,11 @@
// expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
};
-struct M { // expected-note 2 {{candidate constructor (the implicit copy constructor)}} \
- // expected-note {{declared here}} \
- // expected-note {{declared here}}
+struct M { // expected-note 2 {{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+// expected-note@-4 2 {{'M' declared here}}
M(int i, int j); // expected-note 2 {{candidate constructor}}
};
@@ -233,7 +238,13 @@
// <rdar://problem/8308215>: don't crash.
// Lots of questionable recovery here; errors can change.
namespace test3 {
- class A : public std::exception {}; // expected-error {{undeclared identifier}} expected-error {{expected class name}} expected-note 2 {{candidate}}
+ class A : public std::exception {}; // expected-error {{undeclared identifier}} expected-error {{expected class name}}
+ // expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-3 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+ // expected-note@-5 {{candidate constructor (the implicit default constructor) not viable}}
+
class B : public A {
public:
B(const String& s, int e=0) // expected-error {{unknown type name}}
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index b8f0e07..4c4089c 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -77,30 +77,8 @@
// CHECK: note: expanded from macro 'FINIT'
#define FINIT int a3 = NULL;
FINIT // expected-warning {{implicit conversion of NULL constant to 'int'}}
-
- // we don't catch the case of #define FOO NULL ... int i = FOO; but that seems a bit narrow anyway
- // and avoiding that helps us skip these cases:
-#define NULL_COND(cond) ((cond) ? &a : NULL)
- bool bl2 = NULL_COND(true); // don't warn on NULL conversion through the conditional operator across a macro boundary
- if (NULL_COND(true))
- ;
- while (NULL_COND(true))
- ;
- for (; NULL_COND(true); )
- ;
- do ;
- while(NULL_COND(true));
-
-#define NULL_WRAPPER NULL_COND(false)
- if (NULL_WRAPPER)
- ;
- while (NULL_WRAPPER)
- ;
- for (; NULL_WRAPPER;)
- ;
- do
- ;
- while (NULL_WRAPPER);
+ // we don't catch the case of #define FOO NULL ... int i = FOO; but that
+ // seems a bit narrow anyway and avoiding that helps us skip other cases.
int *ip = NULL;
int (*fp)() = NULL;
@@ -116,9 +94,9 @@
// FIXME: We should warn for non-dependent args (only when the param type is also non-dependent) only once
// not once for the template + once for every instantiation
template<typename T>
- void tmpl(char c = NULL, // expected-warning 4 {{implicit conversion of NULL constant to 'char'}}
+ void tmpl(char c = NULL, // expected-warning 3 {{implicit conversion of NULL constant to 'char'}}
T a = NULL, // expected-warning {{implicit conversion of NULL constant to 'char'}} \
- expected-warning 2 {{implicit conversion of NULL constant to 'int'}}
+ expected-warning {{implicit conversion of NULL constant to 'int'}}
T b = 1024) { // expected-warning {{implicit conversion from 'int' to 'char' changes value from 1024 to 0}}
}
@@ -129,8 +107,7 @@
void func() {
tmpl<char>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<char>' required here}}
tmpl<int>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<int>' required here}}
- // FIXME: We should warn only once for each template instantiation - not once for each call
- tmpl<int>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<int>' required here}}
+ tmpl<int>();
tmpl2<int*>();
}
}
@@ -157,3 +134,97 @@
return nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
}
}
+
+namespace test8 {
+ #define NULL_COND(cond) ((cond) ? &num : NULL)
+ #define NULL_WRAPPER NULL_COND(false)
+
+ // don't warn on NULL conversion through the conditional operator across a
+ // macro boundary
+ void macro() {
+ int num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ // Identical to the previous function except with a template argument.
+ // This ensures that template instantiation does not introduce any new
+ // warnings.
+ template <typename X>
+ void template_and_macro() {
+ int num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ // Identical to the previous function except the template argument affects
+ // the conditional statement.
+ template <typename X>
+ void template_and_macro2() {
+ X num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ void run() {
+ template_and_macro<int>();
+ template_and_macro<double>();
+ template_and_macro2<int>();
+ template_and_macro2<double>();
+ }
+}
+
+// Don't warn on a nullptr to bool conversion when the nullptr is the return
+// type of a function.
+namespace test9 {
+ typedef decltype(nullptr) nullptr_t;
+ nullptr_t EXIT();
+
+ bool test() {
+ return EXIT();
+ }
+}
+
+// Test NULL macro inside a macro has same warnings nullptr inside a macro.
+namespace test10 {
+#define test1(cond) \
+ ((cond) ? nullptr : NULL)
+#define test2(cond) \
+ ((cond) ? NULL : nullptr)
+
+#define assert(cond) \
+ ((cond) ? foo() : bar())
+ void foo();
+ void bar();
+
+ void run(int x) {
+ if (test1(x)) {}
+ if (test2(x)) {}
+ assert(test1(x));
+ assert(test2(x));
+ }
+}
diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp
index b52f11c..117b508 100644
--- a/test/SemaCXX/convert-to-bool.cpp
+++ b/test/SemaCXX/convert-to-bool.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
struct ConvToBool {
operator bool() const;
};
@@ -8,7 +11,10 @@
};
struct ExplicitConvToBool {
- explicit operator bool(); // expected-warning{{explicit conversion functions are a C++11 extension}}
+ explicit operator bool();
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{explicit conversion functions are a C++11 extension}}
+#endif
};
void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
@@ -39,7 +45,10 @@
void accepts_bool(bool) { } // expected-note{{candidate function}}
struct ExplicitConvToRef {
- explicit operator int&(); // expected-warning{{explicit conversion functions are a C++11 extension}}
+ explicit operator int&();
+#if (__cplusplus <= 199711L) // C++03 or earlier modes
+ // expected-warning@-2{{explicit conversion functions are a C++11 extension}}
+#endif
};
void test_explicit_bool(ExplicitConvToBool ecb) {
@@ -56,7 +65,10 @@
struct A { };
struct B { };
struct C {
- explicit operator A&(); // expected-warning{{explicit conversion functions are a C++11 extension}}
+ explicit operator A&();
+#if __cplusplus <= 199711L // C++03 or earlier modes
+// expected-warning@-2{{explicit conversion functions are a C++11 extension}}
+#endif
operator B&(); // expected-note{{candidate}}
};
diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp
index 1688e51..75002fa 100644
--- a/test/SemaCXX/converting-constructor.cpp
+++ b/test/SemaCXX/converting-constructor.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
class Z { };
class Y {
@@ -28,6 +31,10 @@
};
class FromShortExplicitly { // expected-note{{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
public:
explicit FromShortExplicitly(short s);
};
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
index ea2db0c..d219ee5 100644
--- a/test/SemaCXX/copy-initialization.cpp
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
class X {
public:
explicit X(const X&); // expected-note {{candidate constructor}}
@@ -58,7 +61,10 @@
namespace Ex2 {
struct S {
- S(S&&); // expected-warning {{C++11}}
+ S(S&&);
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{rvalue references are a C++11 extension}}
+#endif
S(int);
};
const S a(0);
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp
index 3e18187..e82cb62 100644
--- a/test/SemaCXX/coroutines.cpp
+++ b/test/SemaCXX/coroutines.cpp
@@ -6,6 +6,18 @@
void await_resume();
} a;
+struct suspend_always {
+ bool await_ready() { return false; }
+ void await_suspend() {}
+ void await_resume() {}
+};
+
+struct suspend_never {
+ bool await_ready() { return true; }
+ void await_suspend() {}
+ void await_resume() {}
+};
+
void no_coroutine_traits() {
co_await a; // expected-error {{need to include <coroutine>}}
}
@@ -14,6 +26,12 @@
template<typename ...T> struct coroutine_traits; // expected-note {{declared here}}
};
+template<typename Promise> struct coro {};
+template<typename Promise, typename... Ps>
+struct std::coroutine_traits<coro<Promise>, Ps...> {
+ using promise_type = Promise;
+};
+
void no_specialization() {
co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}}
}
@@ -21,18 +39,67 @@
template<typename ...T> struct std::coroutine_traits<int, T...> {};
int no_promise_type() {
- co_await a; // expected-error {{this function cannot be a coroutine: 'coroutine_traits<int>' has no member named 'promise_type'}}
+ co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}}
}
-struct promise; // expected-note {{forward declaration}}
+template<> struct std::coroutine_traits<double, double> { typedef int promise_type; };
+double bad_promise_type(double) {
+ co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
+}
+
+template<> struct std::coroutine_traits<double, int> {
+ struct promise_type {};
+};
+double bad_promise_type_2(int) {
+ co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}}
+}
+
+struct promise; // expected-note 2{{forward declaration}}
template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };
// FIXME: This diagnostic is terrible.
void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
+ // FIXME: This diagnostic doesn't make any sense.
+ // expected-error@-2 {{incomplete definition of type 'promise'}}
co_await a;
}
-struct promise {};
+struct yielded_thing { const char *p; short a, b; };
+
+struct not_awaitable {};
+
+struct promise {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ awaitable yield_value(int); // expected-note 2{{candidate}}
+ awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
+ not_awaitable yield_value(void()); // expected-note 2{{candidate}}
+ void return_void();
+ void return_value(int); // expected-note 2{{here}}
+};
+
+void yield() {
+ co_yield 0;
+ co_yield {"foo", 1, 2};
+ co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} expected-warning {{braces around scalar}}
+ co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}}
+ co_yield {"foo"};
+ co_yield "foo"; // expected-error {{no matching}}
+ co_yield 1.0;
+ co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+}
+
+void coreturn(int n) {
+ co_await a;
+ if (n == 0)
+ co_return 3;
+ if (n == 1)
+ co_return {4};
+ if (n == 2)
+ co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}}
+ co_return;
+}
void mixed_yield() {
co_yield 0; // expected-note {{use of 'co_yield'}}
@@ -73,8 +140,17 @@
}
};
-constexpr void constexpr_coroutine() { // expected-error {{never produces a constant expression}}
- co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} expected-note {{subexpression}}
+void unevaluated() {
+ decltype(co_await a); // expected-error {{cannot be used in an unevaluated context}}
+ sizeof(co_await a); // expected-error {{cannot be used in an unevaluated context}}
+ typeid(co_await a); // expected-error {{cannot be used in an unevaluated context}}
+ decltype(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
+ sizeof(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
+ typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
+}
+
+constexpr void constexpr_coroutine() {
+ co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
}
void varargs_coroutine(const char *, ...) {
@@ -105,3 +181,88 @@
template void await_template(outer); // expected-note {{instantiation}}
template void await_template_2(outer);
}
+
+struct yield_fn_tag {};
+template<> struct std::coroutine_traits<void, yield_fn_tag> {
+ struct promise_type {
+ // FIXME: add an await_transform overload for functions
+ awaitable yield_value(int());
+ void return_value(int());
+
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ void get_return_object();
+ };
+};
+
+namespace placeholder {
+ awaitable f(), f(int); // expected-note 4{{possible target}}
+ int g(), g(int); // expected-note 2{{candidate}}
+ void x() {
+ co_await f; // expected-error {{reference to overloaded function}}
+ }
+ void y() {
+ co_yield g; // expected-error {{no matching member function for call to 'yield_value'}}
+ }
+ void z() {
+ co_await a;
+ co_return g; // expected-error {{address of overloaded function 'g' does not match required type 'int'}}
+ }
+
+ void x(yield_fn_tag) {
+ co_await f; // expected-error {{reference to overloaded function}}
+ }
+ void y(yield_fn_tag) {
+ co_yield g;
+ }
+ void z(yield_fn_tag) {
+ co_await a;
+ co_return g;
+ }
+}
+
+struct bad_promise_1 {
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+};
+coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}}
+ co_await a;
+}
+
+struct bad_promise_2 {
+ coro<bad_promise_2> get_return_object();
+ // FIXME: We shouldn't offer a typo-correction here!
+ suspend_always final_suspend(); // expected-note {{here}}
+};
+coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}}
+ co_await a;
+}
+
+struct bad_promise_3 {
+ coro<bad_promise_3> get_return_object();
+ // FIXME: We shouldn't offer a typo-correction here!
+ suspend_always initial_suspend(); // expected-note {{here}}
+};
+coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
+ co_await a;
+}
+
+struct bad_promise_4 {
+ coro<bad_promise_4> get_return_object();
+ not_awaitable initial_suspend();
+ suspend_always final_suspend();
+};
+// FIXME: This diagnostic is terrible.
+coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+ co_await a;
+}
+
+struct bad_promise_5 {
+ coro<bad_promise_5> get_return_object();
+ suspend_always initial_suspend();
+ not_awaitable final_suspend();
+};
+// FIXME: This diagnostic is terrible.
+coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+ co_await a;
+}
diff --git a/test/SemaCXX/crashes.cpp b/test/SemaCXX/crashes.cpp
index 12251bb..926d13a 100644
--- a/test/SemaCXX/crashes.cpp
+++ b/test/SemaCXX/crashes.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// <rdar://problem/8124080>
template<typename _Alloc> class allocator;
@@ -31,7 +33,11 @@
namespace rdar8605381 {
struct X {};
-struct Y { // expected-note{{candidate}}
+struct Y { // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
Y();
};
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 9456dd7..060a0f2 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -117,8 +117,10 @@
void auto_deduction() {
auto l = {1, 2, 3, 4};
- auto l2 {1, 2, 3, 4}; // expected-warning {{will change meaning in a future version of Clang}}
+ auto l2 {1, 2, 3, 4}; // expected-error {{initializer for variable 'l2' with type 'auto' contains multiple expressions}}
+ auto l3 {1};
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
+ static_assert(same_type<decltype(l3), int>::value, "");
auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
for (int i : {1, 2, 3, 4}) {}
@@ -190,7 +192,7 @@
}
namespace PR14272 {
- auto x { { 0, 0 } }; // expected-error {{cannot deduce actual type for variable 'x' with type 'auto' from initializer list}}
+ auto x { { 0, 0 } }; // expected-error {{cannot deduce type for variable 'x' with type 'auto' from nested initializer list}}
}
namespace initlist_of_array {
@@ -282,3 +284,28 @@
void foo() { f({{0}}, {{'\0'}}); }
}
+
+namespace update_rbrace_loc_crash {
+ // We used to crash-on-invalid on this example when updating the right brace
+ // location.
+ template <typename T, T>
+ struct A {};
+ template <typename T, typename F, int... I>
+ std::initializer_list<T> ExplodeImpl(F p1, A<int, I...>) {
+ // expected-error@+1 {{reference to type 'const update_rbrace_loc_crash::Incomplete' could not bind to an rvalue of type 'void'}}
+ return {p1(I)...};
+ }
+ template <typename T, int N, typename F>
+ void Explode(F p1) {
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ ExplodeImpl<T>(p1, A<int, N>());
+ }
+ class Incomplete;
+ struct ContainsIncomplete {
+ const Incomplete &obstacle;
+ };
+ void f() {
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ Explode<ContainsIncomplete, 4>([](int) {});
+ }
+}
diff --git a/test/SemaCXX/cxx0x-noexcept-expression.cpp b/test/SemaCXX/cxx0x-noexcept-expression.cpp
index ba51365..f1fe01a 100644
--- a/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -1,19 +1,19 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-
-void f(); // expected-note {{possible target for call}}
-void f(int); // expected-note {{possible target for call}}
-
-void g() {
- bool b = noexcept(f); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
- bool b2 = noexcept(f(0));
-}
-
-struct S {
- void g(); // expected-note {{possible target for call}}
- void g(int); // expected-note {{possible target for call}}
-
- void h() {
- bool b = noexcept(this->g); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
- bool b2 = noexcept(this->g(0));
- }
-};
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+void f(); // expected-note {{possible target for call}}
+void f(int); // expected-note {{possible target for call}}
+
+void g() {
+ bool b = noexcept(f); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
+ bool b2 = noexcept(f(0));
+}
+
+struct S {
+ void g(); // expected-note {{possible target for call}}
+ void g(int); // expected-note {{possible target for call}}
+
+ void h() {
+ bool b = noexcept(this->g); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ bool b2 = noexcept(this->g(0));
+ }
+};
diff --git a/test/SemaCXX/cxx0x-return-init-list.cpp b/test/SemaCXX/cxx0x-return-init-list.cpp
index 84bd89b..2aeec7b 100644
--- a/test/SemaCXX/cxx0x-return-init-list.cpp
+++ b/test/SemaCXX/cxx0x-return-init-list.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// Test that a very basic variation of generalized initializer returns (that
// required for libstdc++ 4.5) is supported in C++98.
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index 225d234..e3f6f96 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -496,3 +496,9 @@
}
};
};
+
+namespace PR24989 {
+ auto x = [](auto){};
+ using T = decltype(x);
+ void (T::*p)(int) const = &T::operator();
+}
diff --git a/test/SemaCXX/cxx1y-init-captures.cpp b/test/SemaCXX/cxx1y-init-captures.cpp
index 203e28d..d36882d 100644
--- a/test/SemaCXX/cxx1y-init-captures.cpp
+++ b/test/SemaCXX/cxx1y-init-captures.cpp
@@ -190,3 +190,9 @@
}
}
+
+namespace N3922 {
+ struct X { X(); explicit X(const X&); int n; };
+ auto a = [x{X()}] { return x.n; }; // ok
+ auto b = [x = {X()}] {}; // expected-error{{<initializer_list>}}
+}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 4227272..25a086d 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -100,6 +100,9 @@
};
auto f() -> int; // expected-warning {{trailing return types are incompatible with C++98}}
+#ifdef CXX14COMPAT
+auto ff() { return 5; } // expected-warning {{'auto' type specifier is incompatible with C++98}}
+#endif
void RangeFor() {
int xs[] = {1, 2, 3};
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 6abfb2f..1b1f7dc 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors -std=gnu++98 %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors -std=gnu++11 %s
// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors -x objective-c++ %s
void f() {
@@ -60,6 +62,9 @@
func(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
S s(); // expected-warning {{function declaration}}
+#if __cplusplus >= 201103L
+ // expected-note@-2 {{replace parentheses with an initializer to declare a variable}}
+#endif
}
void nonEmptyParens() {
int f = 0, // g = 0; expected-note {{change this ',' to a ';' to call 'func2'}}
diff --git a/test/SemaCXX/decltype-crash.cpp b/test/SemaCXX/decltype-crash.cpp
index 002bd4c..1cebfcd 100644
--- a/test/SemaCXX/decltype-crash.cpp
+++ b/test/SemaCXX/decltype-crash.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat -std=c++98 %s
int& a();
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index 6001001..fcaa2c8 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
void f(int i);
void f(int i = 0); // expected-note {{previous definition is here}}
void f(int i = 17); // expected-error {{redefinition of default argument}}
@@ -23,7 +26,11 @@
void j(X x = 17); // expected-note{{'::j' declared here}}
-struct Y { // expected-note 2{{candidate}}
+struct Y { // expected-note 2{{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
explicit Y(int);
};
diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp
index 5fcf213..4ce0589 100644
--- a/test/SemaCXX/deprecated.cpp
+++ b/test/SemaCXX/deprecated.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -Wdeprecated -verify -triple x86_64-linux-gnu
// RUN: %clang_cc1 -std=c++11 %s -Wdeprecated -verify -triple x86_64-linux-gnu
// RUN: %clang_cc1 -std=c++1y %s -Wdeprecated -verify -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++1z %s -Wdeprecated -verify -triple x86_64-linux-gnu
// RUN: %clang_cc1 -std=c++1y %s -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
@@ -17,15 +18,29 @@
void stuff() {
register int n;
-#if __cplusplus >= 201103L && !defined(NO_DEPRECATED_FLAGS)
- // expected-warning@-2 {{'register' storage class specifier is deprecated}}
+#if __cplusplus > 201402L
+ // expected-error@-2 {{ISO C++1z does not allow 'register' storage class specifier}}
+#elif __cplusplus >= 201103L && !defined(NO_DEPRECATED_FLAGS)
+ // expected-warning@-4 {{'register' storage class specifier is deprecated}}
#endif
register int m asm("rbx"); // no-warning
int k = to_int(n); // no-warning
bool b;
- ++b; // expected-warning {{incrementing expression of type bool is deprecated}}
+ ++b;
+#if __cplusplus > 201402L
+ // expected-error@-2 {{ISO C++1z does not allow incrementing expression of type bool}}
+#else
+ // expected-warning@-4 {{incrementing expression of type bool is deprecated}}
+#endif
+
+ b++;
+#if __cplusplus > 201402L
+ // expected-error@-2 {{ISO C++1z does not allow incrementing expression of type bool}}
+#else
+ // expected-warning@-4 {{incrementing expression of type bool is deprecated}}
+#endif
char *p = "foo";
#if __cplusplus < 201103L
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 60cb0ef..caff14e 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -217,8 +217,8 @@
public:
simple_ptr(T* t): _ptr(t) {}
~simple_ptr() { delete _ptr; } // \
- // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} \
- // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}}
+ // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \
+ // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}
T& operator*() const { return *_ptr; }
private:
T* _ptr;
@@ -228,7 +228,7 @@
class simple_ptr2 {
public:
simple_ptr2(T* t): _ptr(t) {}
- ~simple_ptr2() { delete _ptr; } // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ ~simple_ptr2() { delete _ptr; } // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}
T& operator*() const { return *_ptr; }
private:
T* _ptr;
@@ -257,6 +257,7 @@
}
}
+// FIXME: Why are these supposed to not warn?
void nowarnarray() {
{
B* b = new B[4];
@@ -311,21 +312,40 @@
}
}
+void nowarn0_explicit_dtor(F* f, VB* vb, VD* vd, VF* vf) {
+ f->~F();
+ f->~F();
+ vb->~VB();
+ vd->~VD();
+ vf->~VF();
+}
+
void warn0() {
{
B* b = new B();
- delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ delete b; // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}
}
{
B* b = new D();
- delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ delete b; // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}
}
{
D* d = new D();
- delete d; // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}}
+ delete d; // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}
}
}
+void warn0_explicit_dtor(B* b, B& br, D* d) {
+ b->~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}
+ b->B::~B(); // No warning when the call isn't virtual.
+
+ br.~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}
+ br.B::~B();
+
+ d->~D(); // expected-warning {{destructor called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}
+ d->D::~D();
+}
+
void nowarn1() {
{
simple_ptr<F> f(new F());
diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp
index a7899c7..947622c 100644
--- a/test/SemaCXX/direct-initializer.cpp
+++ b/test/SemaCXX/direct-initializer.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int x(1);
int (x2)(1);
@@ -14,6 +16,10 @@
};
class X { // expected-note{{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
public:
explicit X(int); // expected-note{{candidate constructor}}
X(float, float, float); // expected-note{{candidate constructor}}
@@ -21,6 +27,10 @@
};
class Z { // expected-note{{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
+
public:
Z(int); // expected-note{{candidate constructor}}
};
diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp
index a32ba44..0bbf9b3 100644
--- a/test/SemaCXX/dllexport.cpp
+++ b/test/SemaCXX/dllexport.cpp
@@ -730,7 +730,12 @@
__declspec(dllexport) const int MemberRedecl::StaticConstField = 1; // expected-error{{redeclaration of 'MemberRedecl::StaticConstField' cannot add 'dllexport' attribute}}
__declspec(dllexport) constexpr int MemberRedecl::ConstexprField; // expected-error{{redeclaration of 'MemberRedecl::ConstexprField' cannot add 'dllexport' attribute}}
-
+#ifdef MS
+struct __declspec(dllexport) ClassWithMultipleDefaultCtors {
+ ClassWithMultipleDefaultCtors(int = 40) {} // expected-error{{'__declspec(dllexport)' cannot be applied to more than one default constructor}}
+ ClassWithMultipleDefaultCtors(int = 30, ...) {} // expected-note{{declared here}}
+};
+#endif
//===----------------------------------------------------------------------===//
// Class member templates
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index b32bcd0..cd82418 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -233,4 +233,23 @@
a = templatedConflict<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
a = &templatedConflict<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
}
+
+ int ovlNoCandidate(int m) __attribute__((enable_if(false, "")));
+ int ovlNoCandidate(int m) __attribute__((enable_if(0, "")));
+ void test7() {
+ int (*p)(int) = ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
+ int (*p2)(int) = &ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
+ int (*a)(int);
+ a = ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
+ a = &ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
+ }
+
+ int noOvlNoCandidate(int m) __attribute__((enable_if(false, "")));
+ void test8() {
+ int (*p)(int) = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ int (*p2)(int) = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ int (*a)(int);
+ a = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ a = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ }
}
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
index 370e1c3..6b0824b 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++98 -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s
enum E { // expected-note{{previous definition is here}}
Val1,
Val2
@@ -88,10 +89,24 @@
// PR7921
enum PR7921E {
- PR7921V = (PR7921E)(123) // expected-error {{expression is not an integral constant expression}}
+ PR7921V = (PR7921E)(123)
+#if __cplusplus < 201103L
+// expected-error@-2 {{expression is not an integral constant expression}}
+#else
+// expected-error@-4 {{must have integral or unscoped enumeration type}}
+// FIXME: The above diagnostic isn't very good; we should instead complain about the type being incomplete.
+#endif
};
void PR8089() {
enum E; // expected-error{{ISO C++ forbids forward references to 'enum' types}}
int a = (E)3; // expected-error{{cannot initialize a variable of type 'int' with an rvalue of type 'E'}}
}
+
+// This is accepted as a GNU extension. In C++98, there was no provision for
+// expressions with UB to be non-constant.
+enum { overflow = 123456 * 234567 };
+#if __cplusplus >= 201103L
+// expected-warning@-2 {{not an integral constant expression}}
+// expected-note@-3 {{value 28958703552 is outside the range of representable values}}
+#endif
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
index 1a50c99..5a0d6dd 100644
--- a/test/SemaCXX/expressions.cpp
+++ b/test/SemaCXX/expressions.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-constant-conversion %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-constant-conversion -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-constant-conversion -std=c++11 %s
void choice(int);
int choice(bool);
@@ -12,6 +14,9 @@
void f0() {
extern void f0_1(int*);
register int x;
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-warning@-2 {{'register' storage class specifier is deprecated}}
+#endif
f0_1(&x);
}
diff --git a/test/SemaCXX/gnu-flags.cpp b/test/SemaCXX/gnu-flags.cpp
index 05770c5..3cd18ca 100644
--- a/test/SemaCXX/gnu-flags.cpp
+++ b/test/SemaCXX/gnu-flags.cpp
@@ -1,13 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wno-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DNONE -Wno-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DNONE -Wno-gnu
+
// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DALL -Wgnu
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DALL -Wgnu
+
// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \
// RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \
// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \
// RUN: -Wgnu-empty-struct
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DALL -Wno-gnu \
+// RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \
+// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \
+// RUN: -Wgnu-empty-struct
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DALL -Wno-gnu \
+// RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \
+// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \
+// RUN: -Wgnu-empty-struct
+
// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \
// RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \
// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \
// RUN: -Wno-gnu-empty-struct
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DNONE -Wgnu \
+// RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \
+// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \
+// RUN: -Wno-gnu-empty-struct
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DNONE -Wgnu \
+// RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \
+// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \
+// RUN: -Wno-gnu-empty-struct
+
// Additional disabled tests:
// %clang_cc1 -fsyntax-only -verify %s -DANONYMOUSSTRUCT -Wno-gnu -Wgnu-anonymous-struct
// %clang_cc1 -fsyntax-only -verify %s -DREDECLAREDCLASSMEMBER -Wno-gnu -Wredeclared-class-member
@@ -59,7 +83,7 @@
};
-#if ALL || FOLDINGCONSTANT
+#if (ALL || FOLDINGCONSTANT) && (__cplusplus <= 199711L) // C++03 or earlier modes
// expected-warning@+4 {{in-class initializer for static data member is not a constant expression; folding it to a constant is a GNU extension}}
#endif
diff --git a/test/SemaCXX/init-priority-attr.cpp b/test/SemaCXX/init-priority-attr.cpp
index a2e6df2..8f31e2f 100644
--- a/test/SemaCXX/init-priority-attr.cpp
+++ b/test/SemaCXX/init-priority-attr.cpp
@@ -21,7 +21,7 @@
Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{'init_priority' attribute takes one argument}}
-Two coo[2] __attribute__((init_priority(3))); // expected-error {{init_priority attribute requires integer constant between 101 and 65535 inclusive}}
+Two coo[2] __attribute__((init_priority(3))); // expected-error {{'init_priority' attribute requires integer constant between 101 and 65535 inclusive}}
Two koo[4] __attribute__((init_priority(1.13))); // expected-error {{'init_priority' attribute requires an integer constant}}
diff --git a/test/SemaCXX/internal_linkage.cpp b/test/SemaCXX/internal_linkage.cpp
new file mode 100644
index 0000000..d5cc676
--- /dev/null
+++ b/test/SemaCXX/internal_linkage.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+int f() __attribute__((internal_linkage));
+
+class A;
+class __attribute__((internal_linkage)) A {
+public:
+ int x __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+ static int y __attribute__((internal_linkage));
+ void f1() __attribute__((internal_linkage));
+ void f2() __attribute__((internal_linkage)) {}
+ static void f3() __attribute__((internal_linkage)) {}
+ void f4(); // expected-note{{previous definition is here}}
+ static int zz; // expected-note{{previous definition is here}}
+ A() __attribute__((internal_linkage)) {}
+ ~A() __attribute__((internal_linkage)) {}
+ A& operator=(const A&) __attribute__((internal_linkage)) { return *this; }
+ struct {
+ int z __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+ };
+};
+
+__attribute__((internal_linkage)) void A::f4() {} // expected-error{{'internal_linkage' attribute does not appear on the first declaration of 'f4'}}
+
+__attribute__((internal_linkage)) int A::zz; // expected-error{{'internal_linkage' attribute does not appear on the first declaration of 'zz'}}
+
+namespace Z __attribute__((internal_linkage)) { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+}
+
+__attribute__((internal_linkage("foo"))) int g() {} // expected-error{{'internal_linkage' attribute takes no arguments}}
+
+[[clang::internal_linkage]] int h() {}
+
+enum struct __attribute__((internal_linkage)) E { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+ a = 1,
+ b = 2
+};
+
+int A::y;
+
+void A::f1() {
+}
+
+void g(int a [[clang::internal_linkage]]) { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+ int x [[clang::internal_linkage]]; // expected-warning{{'internal_linkage' attribute on a non-static local variable is ignored}}
+ static int y [[clang::internal_linkage]];
+}
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
index 87da79a..172be6b 100644
--- a/test/SemaCXX/invalid-member-expr.cpp
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
class X {};
@@ -23,9 +25,17 @@
// PR6327
namespace test3 {
template <class A, class B> struct pair {};
+ template <class _E> class initializer_list {};
+ template <typename _Tp> pair<_Tp, _Tp> minmax(initializer_list<_Tp> __l) {};
void test0() {
- pair<int, int> z = minmax({}); // expected-error {{expected expression}}
+ pair<int, int> z = minmax({});
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-error@-2 {{expected expression}}
+#else
+ // expected-error@-4 {{no matching function for call to 'minmax'}}
+ // expected-note@-8 {{candidate template ignored: couldn't infer template argument '_Tp'}}
+#endif
}
struct string {
diff --git a/test/SemaCXX/linkage-invalid-decl.cpp b/test/SemaCXX/linkage-invalid-decl.cpp
new file mode 100644
index 0000000..0a991ba
--- /dev/null
+++ b/test/SemaCXX/linkage-invalid-decl.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This invalid declaration used to call infinite recursion in linkage
+// calculation for enum as a function argument.
+inline foo(A)(enum E;
+// expected-error@-1 {{unknown type name 'foo'}}
+// expected-error@-2 {{ISO C++ forbids forward references to 'enum' types}}
+// expected-error@-3 {{expected ')'}}
+// expected-note@-4 {{to match this '('}}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 5b3393e..3571fa7 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
class X{
public:
@@ -116,8 +118,10 @@
void f(Y *y) {
y->N::X1<int>; // expected-error{{'rdar8231724::N::X1' is not a member of class 'rdar8231724::Y'}}
y->Z<int>::n; // expected-error{{'rdar8231724::Z<int>::n' is not a member of class 'rdar8231724::Y'}}
- y->template Z<int>::n; // expected-error{{'rdar8231724::Z<int>::n' is not a member of class 'rdar8231724::Y'}} \
- // expected-warning{{'template' keyword outside of a template}}
+ y->template Z<int>::n; // expected-error{{'rdar8231724::Z<int>::n' is not a member of class 'rdar8231724::Y'}}
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{'template' keyword outside of a template}}
+#endif
}
}
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index afb7455..f3adb95 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A {};
enum B { Dummy };
@@ -14,8 +16,11 @@
int (A::*pfi)(int);
void (*A::*ppfie)() throw(); // expected-error {{exception specifications are not allowed beyond a single level of indirection}}
-int B::*pbi; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
- // expected-error {{'pbi' does not point into a class}}
+int B::*pbi;
+#if __cplusplus <= 199711L // C++03 or earlier modes
+// expected-warning@-2 {{use of enumeration in a nested name specifier is a C++11 extension}}
+#endif
+// expected-error@-4 {{'pbi' does not point into a class}}
int C::*pci; // expected-error {{'pci' does not point into a class}}
void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}}
int& A::*pdr; // expected-error {{'pdr' declared as a member pointer to a reference}}
diff --git a/test/SemaCXX/ms-interface.cpp b/test/SemaCXX/ms-interface.cpp
index e7386ce..4a1c13d 100644
--- a/test/SemaCXX/ms-interface.cpp
+++ b/test/SemaCXX/ms-interface.cpp
@@ -58,10 +58,12 @@
struct S { };
class C { };
__interface I { };
+union U;
static_assert(!__is_interface_class(S), "oops");
static_assert(!__is_interface_class(C), "oops");
-static_assert(__is_interface_class(I), "oops");
+static_assert(!__is_interface_class(I), "oops");
+static_assert(!__is_interface_class(U), "oops");
// expected-error@55 {{interface type cannot inherit from 'struct S'}}
// expected-note@+1 {{in instantiation of template class 'I6<S>' requested here}}
diff --git a/test/SemaCXX/ms-property-error.cpp b/test/SemaCXX/ms-property-error.cpp
new file mode 100644
index 0000000..ca52538
--- /dev/null
+++ b/test/SemaCXX/ms-property-error.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -verify -fms-compatibility %s -fsyntax-only -o -
+
+class S {
+public:
+ __declspec(property(get=GetX,put=PutX)) int x[];
+ int GetX(int i, int j) { return i+j; } // expected-note {{'GetX' declared here}}
+ void PutX(int i, int j, int k) { j = i = k; } // expected-note {{'PutX' declared here}}
+};
+
+char *ptr;
+template <typename T>
+class St {
+public:
+ __declspec(property(get=GetX,put=PutX)) T x[];
+ T GetX(T i, T j) { return i+j; } // expected-note 3 {{'GetX' declared here}}
+ T PutX(T i, T j, T k) { return j = i = k; } // expected-note 2 {{'PutX' declared here}}
+ ~St() {
+ x[1] = 0; // expected-error {{too few arguments to function call, expected 3, have 2}}
+ x[2][3] = 4;
+ ++x[2][3];
+ x[1][2] = x[3][4][5]; // expected-error {{too many arguments to function call, expected 2, have 3}}
+ ptr = x[1][2] = x[3][4]; // expected-error {{assigning to 'char *' from incompatible type 'int'}}
+ }
+};
+
+// CHECK-LABEL: main
+int main(int argc, char **argv) {
+ S *p1 = 0;
+ St<float> *p2 = 0;
+ St<int> a; // expected-note {{in instantiation of member function 'St<int>::~St' requested here}}
+ int j = (p1->x)[223][11][2]; // expected-error {{too many arguments to function call, expected 2, have 3}}
+ (p1->x[23]) = argc; // expected-error {{too few arguments to function call, expected 3, have 2}}
+ float j1 = (p2->x); // expected-error {{too few arguments to function call, expected 2, have 0}}
+ ((p2->x)[23])[1][2] = *argv; // expected-error {{too many arguments to function call, expected 3, have 4}}
+ argv = p2->x[11][22] = argc; // expected-error {{assigning to 'char **' from incompatible type 'float'}}
+ return ++(((p2->x)[23])); // expected-error {{too few arguments to function call, expected 2, have 1}}
+}
diff --git a/test/SemaCXX/ms-property.cpp b/test/SemaCXX/ms-property.cpp
new file mode 100644
index 0000000..d33dbf0
--- /dev/null
+++ b/test/SemaCXX/ms-property.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+class Test1 {
+private:
+ int x_;
+
+public:
+ Test1(int x) : x_(x) {}
+ __declspec(property(get = get_x)) int X;
+ int get_x() const { return x_; }
+ static Test1 *GetTest1() { return new Test1(10); }
+};
+
+class S {
+public:
+ __declspec(property(get=GetX,put=PutX)) int x[];
+ int GetX(int i, int j) { return i+j; }
+ void PutX(int i, int j, int k) { j = i = k; }
+};
+
+template <typename T>
+class St {
+public:
+ __declspec(property(get=GetX,put=PutX)) T x[];
+ T GetX(T i, T j) { return i+j; }
+ T PutX(T i, T j, T k) { return j = i = k; }
+ ~St() { x[0][0] = x[1][1]; }
+};
+
+// CHECK: this->x[0][0] = this->x[1][1];
+// CHECK: this->x[0][0] = this->x[1][1];
+
+// CHECK-LABEL: main
+int main(int argc, char **argv) {
+ S *p1 = 0;
+ St<float> *p2 = 0;
+ // CHECK: St<int> a;
+ St<int> a;
+ // CHECK-NEXT: int j = (p1->x)[223][11];
+ int j = (p1->x)[223][11];
+ // CHECK-NEXT: (p1->x[23])[1] = j;
+ (p1->x[23])[1] = j;
+ // CHECK-NEXT: float j1 = (p2->x[223][11]);
+ float j1 = (p2->x[223][11]);
+ // CHECK-NEXT: ((p2->x)[23])[1] = j1;
+ ((p2->x)[23])[1] = j1;
+ // CHECK-NEXT: ++(((p2->x)[23])[1]);
+ ++(((p2->x)[23])[1]);
+ // CHECK-NEXT: j1 = ((p2->x)[23])[1] = j1;
+ j1 = ((p2->x)[23])[1] = j1;
+ // CHECK-NEXT: return Test1::GetTest1()->X;
+ return Test1::GetTest1()->X;
+}
+#endif // HEADER
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index 63615ec..281ee99 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -125,3 +125,46 @@
namespace Y = X::Y;
}
+
+namespace PR25731 {
+ void f() {
+ namespace X = PR25731;
+ namespace X = PR25731;
+ X::f();
+ }
+}
+
+namespace MultipleUnambiguousLookupResults {
+ namespace A { int y; }
+ namespace B {
+ namespace X { int x; }
+ namespace Y = A;
+ namespace Z = A; // expected-note {{candidate}}
+ }
+ namespace C {
+ namespace X = B::X;
+ namespace Y = A;
+ namespace Z = X; // expected-note {{candidate}}
+ }
+ using namespace B;
+ using namespace C;
+ int x1 = X::x; // ok, unambiguous
+ int y1 = Y::y; // ok, unambiguous
+ int z1 = Z::x; // expected-error {{ambiguous}}
+
+ namespace X = C::X;
+ namespace Y = A;
+ int x2 = X::x; // ok, unambiguous
+ int y2 = Y::y; // ok, unambiguous
+}
+
+namespace RedeclOfNonNamespace {
+ int a; // expected-note {{previous}}
+ namespace X { int b; }
+ using X::b; // expected-note {{previous}}
+ namespace c {} // expected-note {{previous}}
+
+ namespace a = X; // expected-error {{different kind}}
+ namespace b = X; // expected-error {{different kind}}
+ namespace c = X; // expected-error-re {{redefinition of 'c'{{$}}}}
+}
diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp
index d47b707..e2c1516 100644
--- a/test/SemaCXX/namespace.cpp
+++ b/test/SemaCXX/namespace.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
namespace A { // expected-note 2 {{previous definition is here}}
int A;
void f() { A = 0; }
@@ -8,8 +11,11 @@
int A; // expected-error {{redefinition of 'A' as different kind of symbol}}
class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
-class B {}; // expected-note {{previous definition is here}} \
- // expected-note{{candidate function (the implicit copy assignment operator)}}
+class B {}; // expected-note {{previous definition is here}}
+// expected-note@-1 {{candidate function (the implicit copy assignment operator) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
void C(); // expected-note {{previous definition is here}}
namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}}
diff --git a/test/SemaCXX/new-array-size-conv.cpp b/test/SemaCXX/new-array-size-conv.cpp
index c987c28..dbdd4bd 100644
--- a/test/SemaCXX/new-array-size-conv.cpp
+++ b/test/SemaCXX/new-array-size-conv.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++11 %s
struct ValueInt
{
@@ -20,8 +22,15 @@
void test() {
- (void)new int[ValueInt(10)]; // expected-warning{{implicit conversion from array size expression of type 'ValueInt' to integral type 'int' is a C++11 extension}}
- (void)new int[ValueEnum()]; // expected-warning{{implicit conversion from array size expression of type 'ValueEnum' to enumeration type 'E' is a C++11 extension}}
+ (void)new int[ValueInt(10)];
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{implicit conversion from array size expression of type 'ValueInt' to integral type 'int' is a C++11 extension}}
+#endif
+
+ (void)new int[ValueEnum()];
+#if __cplusplus <= 199711L
+// expected-warning@-2{{implicit conversion from array size expression of type 'ValueEnum' to enumeration type 'E' is a C++11 extension}}
+#endif
(void)new int[ValueBoth()]; // expected-error{{ambiguous conversion of array size expression of type 'ValueBoth' to an integral or enumeration type}}
(void)new int[TwoValueInts()]; // expected-error{{ambiguous conversion of array size expression of type 'TwoValueInts' to an integral or enumeration type}}
diff --git a/test/SemaCXX/nullability.cpp b/test/SemaCXX/nullability.cpp
index edce6b05..c73c01a 100644
--- a/test/SemaCXX/nullability.cpp
+++ b/test/SemaCXX/nullability.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion
#if __has_feature(nullability)
#else
@@ -67,3 +67,33 @@
}
template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}}
+
+void TakeNonnull(void *_Nonnull);
+// Check different forms of assignment to a nonull type from a nullable one.
+void AssignAndInitNonNull() {
+ void *_Nullable nullable;
+ void *_Nonnull p(nullable); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p2{nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p3 = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p4 = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull nonnull;
+ nonnull = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ nonnull = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+
+ TakeNonnull(nullable); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}
+ TakeNonnull(nonnull); // OK
+}
+
+void *_Nullable ReturnNullable();
+
+void AssignAndInitNonNullFromFn() {
+ void *_Nonnull p(ReturnNullable()); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p2{ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p3 = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull p4 = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ void *_Nonnull nonnull;
+ nonnull = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+ nonnull = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+
+ TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}
+}
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index e6069ac9..c4b288a 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s -Winvalid-offsetof
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s -Winvalid-offsetof -std=c++98
struct NonPOD {
virtual void f();
diff --git a/test/SemaCXX/overload-call-copycon.cpp b/test/SemaCXX/overload-call-copycon.cpp
index 6720cb6..8497102 100644
--- a/test/SemaCXX/overload-call-copycon.cpp
+++ b/test/SemaCXX/overload-call-copycon.cpp
@@ -1,6 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wnon-pod-varargs
-class X { }; // expected-note {{the implicit copy constructor}} \
- // expected-note{{the implicit default constructor}}
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wnon-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wnon-pod-varargs
+
+class X { }; // expected-note {{the implicit copy constructor}}
+// expected-note@-1 {{the implicit default constructor}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-3 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
int& copycon(X x); // expected-note{{passing argument to parameter}}
float& copycon(...);
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 7c6fe2b..3d286a9 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++98 %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++11 %s
+
int* f(int) { return 0; }
float* f(float) { return 0; }
void f();
@@ -53,8 +56,19 @@
double* k(bool);
void test_k() {
- int* ip1 = k("foo"); // expected-warning{{conversion from string literal to 'char *' is deprecated}}
- int* ip2 = k(("foo")); // expected-warning{{conversion from string literal to 'char *' is deprecated}}
+ int* ip1 = k("foo");
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+ // expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'double *'}}
+#endif
+
+ int* ip2 = k(("foo"));
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+ // expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'double *'}}
+#endif
double* dp1 = k(L"foo");
}
@@ -62,7 +76,12 @@
double* l(bool);
void test_l() {
- int* ip1 = l(L"foo"); // expected-warning{{conversion from string literal to 'wchar_t *' is deprecated}}
+ int* ip1 = l(L"foo");
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{conversion from string literal to 'wchar_t *' is deprecated}}
+#else
+ // expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'double *'}}
+#endif
double* dp1 = l("foo");
}
@@ -80,8 +99,12 @@
void test_n(E* e) {
char ca[7];
int* ip1 = n(ca);
- int* ip2 = n("foo"); // expected-warning{{conversion from string literal to 'char *' is deprecated}}
-
+ int* ip2 = n("foo");
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+ // expected-warning@-4 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
float fa[7];
double* dp1 = n(fa);
@@ -593,8 +616,16 @@
namespace PR20218 {
void f(void (*const &)()); // expected-note 2{{candidate}}
- void f(void (&&)()) = delete; // expected-note 2{{candidate}} expected-warning 2{{extension}}
- void g(void (&&)()) = delete; // expected-note 2{{candidate}} expected-warning 2{{extension}}
+ void f(void (&&)()) = delete; // expected-note 2{{candidate}}
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{rvalue references are a C++11 extension}}
+ // expected-warning@-3 {{deleted function definitions are a C++11 extension}}
+#endif
+ void g(void (&&)()) = delete; // expected-note 2{{candidate}}
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{rvalue references are a C++11 extension}}
+ // expected-warning@-3 {{deleted function definitions are a C++11 extension}}
+#endif
void g(void (*const &)()); // expected-note 2{{candidate}}
void x();
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 7899403..4c2953b 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify -triple x86_64-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify -triple x86_64-linux-gnu -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify -triple x86_64-linux-gnu -std=c++11 %s
struct yes;
struct no;
@@ -60,7 +62,10 @@
// FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
}
-struct ShortRef { // expected-note{{candidate function (the implicit copy assignment operator)}}
+struct ShortRef { // expected-note{{candidate function (the implicit copy assignment operator) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
operator short&();
};
@@ -68,7 +73,10 @@
operator volatile long&();
};
-struct XpmfRef { // expected-note{{candidate function (the implicit copy assignment operator)}}
+struct XpmfRef { // expected-note{{candidate function (the implicit copy assignment operator) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
operator pmf&();
};
diff --git a/test/SemaCXX/pass-object-size.cpp b/test/SemaCXX/pass-object-size.cpp
new file mode 100644
index 0000000..94c9cc9
--- /dev/null
+++ b/test/SemaCXX/pass-object-size.cpp
@@ -0,0 +1,136 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+namespace simple {
+int Foo(void *const p __attribute__((pass_object_size(0))));
+
+int OvlFoo(void *const p __attribute__((pass_object_size(0))));
+int OvlFoo(void *const p, int);
+
+struct Statics {
+ static int Foo(void *const p __attribute__((pass_object_size(0))));
+ static int OvlFoo(void *const p __attribute__((pass_object_size(0))));
+ static int OvlFoo(void *const p __attribute__((pass_object_size(1)))); // expected-error{{conflicting pass_object_size attributes on parameters}} expected-note@-1{{previous declaration is here}}
+ static int OvlFoo(double *p);
+};
+
+struct Members {
+ int Foo(void *const p __attribute__((pass_object_size(0))));
+ int OvlFoo(void *const p __attribute__((pass_object_size(0))));
+ int OvlFoo(void *const p, int);
+};
+
+void Decls() {
+ int (*A)(void *) = &Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ int (*B)(void *) = Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+
+ int (*C)(void *) = &OvlFoo; //expected-error{{address of overloaded function 'OvlFoo' does not match required type 'int (void *)'}} expected-note@6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@7{{candidate function has different number of parameters (expected 1 but has 2)}}
+ int (*D)(void *) = OvlFoo; //expected-error{{address of overloaded function 'OvlFoo' does not match required type 'int (void *)'}} expected-note@6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@7{{candidate function has different number of parameters (expected 1 but has 2)}}
+
+ int (*E)(void *) = &Statics::Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ int (*F)(void *) = &Statics::OvlFoo; //expected-error{{address of overloaded function 'OvlFoo' does not match required type 'int (void *)'}} expected-note@11{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@13{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'double *')}}
+
+ int (*G)(void *) = &Members::Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ int (*H)(void *) = &Members::OvlFoo; //expected-error{{address of overloaded function 'OvlFoo' does not match required type 'int (void *)'}} expected-note@18{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@19{{candidate function has different number of parameters (expected 1 but has 2)}}
+}
+
+void Assigns() {
+ int (*A)(void *);
+ A = &Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ A = Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+
+ A = &OvlFoo; //expected-error{{assigning to 'int (*)(void *)' from incompatible type '<overloaded function type>'}} expected-note@6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@7{{candidate function has different number of parameters (expected 1 but has 2)}}
+ A = OvlFoo; //expected-error{{assigning to 'int (*)(void *)' from incompatible type '<overloaded function type>'}} expected-note@6{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@7{{candidate function has different number of parameters (expected 1 but has 2)}}
+
+ A = &Statics::Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ A = &Statics::OvlFoo; //expected-error{{assigning to 'int (*)(void *)' from incompatible type '<overloaded function type>'}} expected-note@11{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@13{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'double *')}}
+
+ int (Members::*M)(void *);
+ M = &Members::Foo; //expected-error{{cannot take address of function 'Foo' because parameter 1 has pass_object_size attribute}}
+ M = &Members::OvlFoo; //expected-error-re{{assigning to '{{.*}}' from incompatible type '<overloaded function type>'}} expected-note@18{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@19{{candidate function has different number of parameters (expected 1 but has 2)}}
+}
+
+} // namespace simple
+
+namespace templates {
+template <typename T>
+int Foo(void *const __attribute__((pass_object_size(0)))) {
+ return 0;
+}
+
+template <typename T> struct Bar {
+ template <typename U>
+ int Foo(void *const __attribute__((pass_object_size(0)))) {
+ return 0;
+ }
+};
+
+void Decls() {
+ int (*A)(void *) = &Foo<void*>; //expected-error{{address of overloaded function 'Foo' does not match required type 'int (void *)'}} expected-note@56{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}}
+ int (Bar<int>::*B)(void *) = &Bar<int>::Foo<double>; //expected-error{{address of overloaded function 'Foo' does not match required type}} expected-note@62{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}}
+}
+
+void Assigns() {
+ int (*A)(void *);
+ A = &Foo<void*>; // expected-error{{assigning to 'int (*)(void *)' from incompatible type '<overloaded function type>'}} expected-note@56{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}}
+ int (Bar<int>::*B)(void *) = &Bar<int>::Foo<double>; //expected-error{{address of overloaded function 'Foo' does not match required type}} expected-note@62{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}}
+}
+} // namespace templates
+
+namespace virt {
+struct Foo {
+ virtual void DoIt(void *const p __attribute__((pass_object_size(0))));
+};
+
+struct Bar : public Foo {
+ void DoIt(void *const p __attribute__((pass_object_size(0)))) override; // OK
+};
+
+struct Baz : public Foo {
+ void DoIt(void *const p) override; //expected-error{{non-virtual member function marked 'override' hides virtual member function}} expected-note@81{{hidden overloaded virtual function 'virt::Foo::DoIt' declared here}}
+};
+}
+
+namespace why {
+void TakeFn(void (*)(int, void *));
+void ObjSize(int, void *const __attribute__((pass_object_size(0))));
+
+void Check() {
+ TakeFn(ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn(&ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn(*ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn(*****ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn(*****&ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+
+ void (*P)(int, void *) = ****ObjSize; //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ P = ****ObjSize; //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+
+ TakeFn((ObjSize)); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn((void*)ObjSize); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+ TakeFn((decltype(P))((void*)ObjSize)); //expected-error{{cannot take address of function 'ObjSize' because parameter 2 has pass_object_size attribute}}
+}
+}
+
+namespace constexpr_support {
+constexpr int getObjSizeType() { return 0; }
+void Foo(void *p __attribute__((pass_object_size(getObjSizeType()))));
+}
+
+namespace lambdas {
+void Bar() {
+ (void)+[](void *const p __attribute__((pass_object_size(0)))) {}; //expected-error-re{{invalid argument type '(lambda at {{.*}})' to unary expression}}
+}
+}
+
+namespace ovlbug {
+// Directly calling an address-of function expression (e.g. in (&foo)(args...))
+// doesn't go through regular address-of-overload logic. This caused the above
+// code to generate an ICE.
+void DirectAddrOf(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(int *);
+
+void Test() {
+ (&DirectAddrOf)(nullptr); //expected-error{{cannot take address of function 'DirectAddrOf' because parameter 1 has pass_object_size attribute}}
+ (&DirectAddrOfOvl)((char*)nullptr); //expected-error{{no matching function}} expected-note@129{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@130{{candidate function not viable: no known conversion from 'char *' to 'int *' for 1st argument}}
+}
+}
diff --git a/test/SemaCXX/pragma-init_seg.cpp b/test/SemaCXX/pragma-init_seg.cpp
index e18d0e6..1b22939 100644
--- a/test/SemaCXX/pragma-init_seg.cpp
+++ b/test/SemaCXX/pragma-init_seg.cpp
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-pc-win32
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -std=c++98 %s -triple x86_64-pc-win32
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -std=c++11 %s -triple x86_64-pc-win32
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple i386-apple-darwin13.3.0
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -std=c++98 %s -triple i386-apple-darwin13.3.0
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -std=c++11 %s -triple i386-apple-darwin13.3.0
#ifndef __APPLE__
#pragma init_seg(L".my_seg") // expected-warning {{expected 'compiler', 'lib', 'user', or a string literal}}
@@ -19,3 +23,6 @@
int f();
int __declspec(thread) x = f(); // expected-error {{initializer for thread-local variable must be a constant expression}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{use 'thread_local' to allow this}}
+#endif
diff --git a/test/SemaCXX/pragma-vtordisp.cpp b/test/SemaCXX/pragma-vtordisp.cpp
index 49841c5..649c0ee 100644
--- a/test/SemaCXX/pragma-vtordisp.cpp
+++ b/test/SemaCXX/pragma-vtordisp.cpp
@@ -32,9 +32,41 @@
#pragma vtordisp(), stuff // expected-warning {{extra tokens}}
struct C {
-// FIXME: Our implementation based on token insertion makes it impossible for
-// the pragma to appear everywhere we should support it.
-//#pragma vtordisp()
+#pragma vtordisp()
struct D : virtual A {
};
};
+
+struct E {
+ virtual ~E();
+ virtual void f();
+};
+
+#pragma vtordisp(pop) // expected-warning {{#pragma vtordisp(pop, ...) failed: stack empty}}
+
+void g() {
+ #pragma vtordisp(push, 2)
+ struct F : virtual E {
+ virtual ~F();
+ virtual void f();
+ };
+}
+
+#pragma vtordisp(pop) // OK because of local vtordisp(2) in g().
+
+struct G {
+ void f() {
+ #pragma vtordisp(push, 2) // Method-local pragma - stack will be restored on exit.
+ }
+};
+
+// Stack is restored on exit from G::f(), nothing to pop.
+#pragma vtordisp(pop) // expected-warning {{#pragma vtordisp(pop, ...) failed: stack empty}}
+
+int g2()
+// FIXME: Our implementation based on token insertion makes it impossible for
+// the pragma to appear everywhere we should support it.
+// #pragma vtordisp()
+{
+ return 0;
+}
diff --git a/test/SemaCXX/printf-block.cpp b/test/SemaCXX/printf-block.cpp
index 4a58003..b9d06d6 100644
--- a/test/SemaCXX/printf-block.cpp
+++ b/test/SemaCXX/printf-block.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -Wformat -verify %s -Wno-error=non-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wformat -verify %s -Wno-error=non-pod-varargs -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wformat -verify %s -Wno-error=non-pod-varargs -std=c++11
int (^block) (int, const char *,...) __attribute__((__format__(__printf__,2,3))) = ^ __attribute__((__format__(__printf__,2,3))) (int arg, const char *format,...) {return 5;};
@@ -14,5 +16,11 @@
HasNoCStr hncs(str);
int n = 4;
block(n, "%s %d", str, n); // no-warning
- block(n, "%s %s", hncs, n); // expected-warning{{cannot pass non-POD object of type 'HasNoCStr' to variadic block; expected type from format string was 'char *'}} expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+ block(n, "%s %s", hncs, n);
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{cannot pass non-POD object of type 'HasNoCStr' to variadic block; expected type from format string was 'char *'}}
+#else
+ // expected-warning@-4{{format specifies type 'char *' but the argument has type 'HasNoCStr'}}
+#endif
+ // expected-warning@-6{{format specifies type 'char *' but the argument has type 'int'}}
}
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index d8b40e3..69760fd 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -14,6 +14,7 @@
typedef Int IntArNB[];
class Statics { static int priv; static NonPOD np; };
union EmptyUnion {};
+union IncompleteUnion;
union Union { int i; float f; };
struct HasFunc { void f (); };
struct HasOp { void operator *(); };
@@ -235,6 +236,7 @@
{ int arr[F(__is_empty(Int))]; }
{ int arr[F(__is_empty(POD))]; }
{ int arr[F(__is_empty(EmptyUnion))]; }
+ { int arr[F(__is_empty(IncompleteUnion))]; }
{ int arr[F(__is_empty(EmptyAr))]; }
{ int arr[F(__is_empty(HasRef))]; }
{ int arr[F(__is_empty(HasVirt))]; }
@@ -313,8 +315,23 @@
template<>
struct PotentiallyFinal<int> final { };
+struct SealedClass sealed {
+};
+
+template<typename T>
+struct PotentiallySealed { };
+
+template<typename T>
+struct PotentiallySealed<T*> sealed { };
+
+template<>
+struct PotentiallySealed<int> sealed { };
+
void is_final()
{
+ { int arr[T(__is_final(SealedClass))]; }
+ { int arr[T(__is_final(PotentiallySealed<float*>))]; }
+ { int arr[T(__is_final(PotentiallySealed<int>))]; }
{ int arr[T(__is_final(FinalClass))]; }
{ int arr[T(__is_final(PotentiallyFinal<float*>))]; }
{ int arr[T(__is_final(PotentiallyFinal<int>))]; }
@@ -330,25 +347,17 @@
{ int arr[F(__is_final(IntArNB))]; }
{ int arr[F(__is_final(HasAnonymousUnion))]; }
{ int arr[F(__is_final(PotentiallyFinal<float>))]; }
+ { int arr[F(__is_final(PotentiallySealed<float>))]; }
}
-struct SealedClass sealed {
-};
-
-template<typename T>
-struct PotentiallySealed { };
-
-template<typename T>
-struct PotentiallySealed<T*> sealed { };
-
-template<>
-struct PotentiallySealed<int> sealed { };
-
void is_sealed()
{
{ int arr[T(__is_sealed(SealedClass))]; }
{ int arr[T(__is_sealed(PotentiallySealed<float*>))]; }
{ int arr[T(__is_sealed(PotentiallySealed<int>))]; }
+ { int arr[T(__is_sealed(FinalClass))]; }
+ { int arr[T(__is_sealed(PotentiallyFinal<float*>))]; }
+ { int arr[T(__is_sealed(PotentiallyFinal<int>))]; }
{ int arr[F(__is_sealed(int))]; }
{ int arr[F(__is_sealed(Union))]; }
@@ -361,6 +370,7 @@
{ int arr[F(__is_sealed(IntArNB))]; }
{ int arr[F(__is_sealed(HasAnonymousUnion))]; }
{ int arr[F(__is_sealed(PotentiallyFinal<float>))]; }
+ { int arr[F(__is_sealed(PotentiallySealed<float>))]; }
}
typedef HasVirt Polymorph;
@@ -373,6 +383,7 @@
{ int arr[F(__is_polymorphic(int))]; }
{ int arr[F(__is_polymorphic(Union))]; }
+ { int arr[F(__is_polymorphic(IncompleteUnion))]; }
{ int arr[F(__is_polymorphic(Int))]; }
{ int arr[F(__is_polymorphic(IntAr))]; }
{ int arr[F(__is_polymorphic(UnionAr))]; }
@@ -1991,6 +2002,9 @@
// PR20228
{ int arr[T(__is_constructible(VariadicCtor,
int, int, int, int, int, int, int, int, int))]; }
+
+ // PR25513
+ { int arr[F(__is_constructible(int(int)))]; }
}
// Instantiation of __is_trivially_constructible
diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
index 121863d..610d439 100644
--- a/test/SemaCXX/typo-correction-delayed.cpp
+++ b/test/SemaCXX/typo-correction-delayed.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -Wno-c++11-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A {};
struct B {};
@@ -109,8 +111,10 @@
namespace foo {}
void test_paren_suffix() {
- foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \
- // expected-error {{expected expression}}
+ foo::bar({5, 6}); // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{expected expression}}
+#endif
}
const int kNum = 10; // expected-note {{'kNum' declared here}}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index d5b42d0..07c1634 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -307,14 +307,21 @@
void CreateBar(float, float);
};
struct B : A {
- using A::CreateFoo;
+ using A::CreateFoo; // expected-note {{'CreateFoo' declared here}}
void CreateFoo(int, int); // expected-note {{'CreateFoo' declared here}}
};
void f(B &x) {
x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+ x.Createfoo(0.f,0.f); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
}
}
+namespace using_decl {
+ namespace somewhere { int foobar; }
+ using somewhere::foobar; // expected-note {{declared here}}
+ int k = goobar; // expected-error {{did you mean 'foobar'?}}
+}
+
struct DataStruct {void foo();};
struct T {
DataStruct data_struct;
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index 0138967..29ca5de 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -1,7 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wbind-to-temporary-copy %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wbind-to-temporary-copy -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wbind-to-temporary-copy -std=c++11 %s
// Make sure we don't produce invalid IR.
// RUN: %clang_cc1 -emit-llvm-only %s
+// RUN: %clang_cc1 -emit-llvm-only -std=c++98 %s
+// RUN: %clang_cc1 -emit-llvm-only -std=c++11 %s
namespace test1 {
static void foo(); // expected-warning {{function 'test1::foo' has internal linkage but is not defined}}
@@ -119,7 +123,12 @@
}
void f(const Uncopyable&) {}
void test() {
- f(Uncopyable()); // expected-warning {{C++98 requires an accessible copy constructor}}
+ f(Uncopyable());
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{C++98 requires an accessible copy constructor}}
+#else
+ // expected-warning@-4 {{copying parameter of type 'PR9323::(anonymous namespace)::Uncopyable' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}}
+#endif
};
}
diff --git a/test/SemaCXX/unknown-anytype.cpp b/test/SemaCXX/unknown-anytype.cpp
index a07ec83..95ad040 100644
--- a/test/SemaCXX/unknown-anytype.cpp
+++ b/test/SemaCXX/unknown-anytype.cpp
@@ -45,3 +45,14 @@
int x = (int) test1; // expected-error {{function 'test1' with unknown type must be given a function type}}
}
}
+
+// rdar://problem/23959960
+namespace test5 {
+ template<typename T> struct X; // expected-note{{template is declared here}}
+
+ extern __unknown_anytype test0(...);
+
+ void test() {
+ (X<int>)test0(); // expected-error{{implicit instantiation of undefined template 'test5::X<int>'}}
+ }
+}
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
index 9d28c31..2a9748e 100644
--- a/test/SemaCXX/unknown-type-name.cpp
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// PR3990
namespace N {
@@ -95,7 +97,11 @@
template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++14 extension}}
template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}}
+template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+#if __cplusplus <= 199711L
+//expected-warning@-2 {{deleted function definitions are a C++11 extension}}
+#endif
+
template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
// FIXME: We can tell this was intended to be a function because it does not
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index 5afd15f..ec45b31 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -30,9 +30,7 @@
};
struct X1 : X0 {
- // FIXME: give this operator() a 'float' parameter to test overloading
- // behavior. It currently fails.
- void operator()();
+ void operator()(float&);
using X0::operator();
void test() {
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index bcd7fed..9b27244 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++11 %s
+
typedef char char16 __attribute__ ((__vector_size__ (16)));
typedef long long longlong16 __attribute__ ((__vector_size__ (16)));
typedef char char16_e __attribute__ ((__ext_vector_type__ (16)));
@@ -101,7 +104,10 @@
}
template<typename T>
-struct convertible_to { // expected-note 3 {{candidate function (the implicit copy assignment operator)}}
+struct convertible_to { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
operator T() const;
};
diff --git a/test/SemaCXX/warn-literal-conversion.cpp b/test/SemaCXX/warn-literal-conversion.cpp
index d7bec4c..5d4b6f7 100644
--- a/test/SemaCXX/warn-literal-conversion.cpp
+++ b/test/SemaCXX/warn-literal-conversion.cpp
@@ -38,3 +38,14 @@
int y = (24*60*60) * 0.25;
int pennies = 123.45 * 100;
}
+
+// Similarly, test floating point conversion to bool. Only float values of zero
+// are converted to false; everything else is converted to true.
+void test1() {
+ bool b1 = 0.99f; // expected-warning {{implicit conversion from 'float' to 'bool' changes value from 0.99 to true}}
+ bool b2 = 0.99; // expected-warning {{implicit conversion from 'double' to 'bool' changes value from 0.99 to true}}
+ // These do not warn because they can be directly converted to integral
+ // values.
+ bool b3 = 0.0f;
+ bool b4 = 0.0;
+}
diff --git a/test/SemaCXX/warn-unused-local-typedef-serialize.cpp b/test/SemaCXX/warn-unused-local-typedef-serialize.cpp
index ccb5a09..aa2c48b 100644
--- a/test/SemaCXX/warn-unused-local-typedef-serialize.cpp
+++ b/test/SemaCXX/warn-unused-local-typedef-serialize.cpp
@@ -1,4 +1,3 @@
-// XFAIL: hexagon
// RUN: %clang -x c++-header -c -Wunused-local-typedef %s -o %t.gch -Werror
// RUN: %clang -DBE_THE_SOURCE -c -Wunused-local-typedef -include %t %s -o /dev/null 2>&1 | FileCheck %s
// RUN: %clang -DBE_THE_SOURCE -c -Wunused-local-typedef -include %t %s -o /dev/null 2>&1 | FileCheck %s
diff --git a/test/SemaCXX/writable-strings-deprecated.cpp b/test/SemaCXX/writable-strings-deprecated.cpp
index f925833..7de11b5 100644
--- a/test/SemaCXX/writable-strings-deprecated.cpp
+++ b/test/SemaCXX/writable-strings-deprecated.cpp
@@ -1,25 +1,31 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-writable-strings -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated -Wdeprecated-increment-bool -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fwritable-strings -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-write-strings -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Werror=c++11-compat -verify %s -DERROR
-// RUN: %clang_cc1 -fsyntax-only -Werror=deprecated -Wno-error=deprecated-increment-bool -verify %s -DERROR
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wno-deprecated -Wdeprecated-increment-bool
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DWARNING
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s -DWARNING
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wno-deprecated-writable-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wno-deprecated -Wdeprecated-increment-bool -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -fwritable-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wno-write-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror=c++11-compat -verify %s -DERROR
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror=deprecated -Wno-error=deprecated-increment-bool -verify %s -DERROR
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -DWARNING
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wno-deprecated -Wdeprecated-increment-bool -DWARNING
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -pedantic-errors -DERROR
// rdar://8827606
char *fun(void)
{
return "foo";
+#if defined(ERROR)
#if __cplusplus >= 201103L
-#ifdef ERROR
// expected-error@-3 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
#else
- // expected-warning@-5 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+ // expected-error@-5 {{conversion from string literal to 'char *' is deprecated}}
#endif
-#elif defined(ERROR)
- // expected-error@-8 {{deprecated}}
+#elif defined(WARNING)
+#if __cplusplus >= 201103L
+ // expected-warning@-9 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#else
+ // expected-warning@-11 {{conversion from string literal to 'char *' is deprecated}}
+#endif
#endif
}
diff --git a/test/SemaObjC/arc-property-decl-attrs.m b/test/SemaObjC/arc-property-decl-attrs.m
index 408b270..6c96ba4 100644
--- a/test/SemaObjC/arc-property-decl-attrs.m
+++ b/test/SemaObjC/arc-property-decl-attrs.m
@@ -105,3 +105,19 @@
@property(nonatomic, weak, nonnull, readonly) id ROdelegate; // expected-error {{property attributes 'nonnull' and 'weak' are mutually exclusive}}
@end
+// rdar://problem/23931441
+@protocol P
+@property(readonly, retain) id prop;
+@end
+
+__attribute__((objc_root_class))
+@interface I2<P>
+@end
+
+@interface I2()
+@property (readwrite) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+@end
diff --git a/test/SemaObjC/gc-attributes.m b/test/SemaObjC/gc-attributes.m
index 2f54328..1023ba6 100644
--- a/test/SemaObjC/gc-attributes.m
+++ b/test/SemaObjC/gc-attributes.m
@@ -20,3 +20,7 @@
f1(&a);
f1(&a2); // expected-warning{{passing 'A *__strong *' to parameter of type 'A *__weak *' discards qualifiers}}
}
+
+// These qualifiers should silently expand to nothing in GC mode.
+void test_unsafe_unretained(__unsafe_unretained id *x) {}
+void test_autoreleasing(__autoreleasing id *x) {}
diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m
index b19e423..f205e68 100644
--- a/test/SemaObjC/kindof.m
+++ b/test/SemaObjC/kindof.m
@@ -302,3 +302,19 @@
void processCopyable(__typeof(getSomeCopyable()) string);
processCopyable(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
+
+// Check that clang doesn't crash when a type parameter is illegal.
+@interface Array1<T> : NSObject
+@end
+
+@interface I1 : NSObject
+@end
+
+@interface Array1<__kindof I1*>(extensions1) // expected-error{{expected type parameter name}}
+@end
+
+@interface Array2<T1, T2, T3> : NSObject
+@end
+
+@interface Array2<T, T, __kindof I1*>(extensions2) // expected-error{{expected type parameter name}} expected-error{{redeclaration of type parameter 'T'}}
+@end
diff --git a/test/SemaObjC/mrc-weak.m b/test/SemaObjC/mrc-weak.m
index ec03cf7..e961e0a 100644
--- a/test/SemaObjC/mrc-weak.m
+++ b/test/SemaObjC/mrc-weak.m
@@ -12,7 +12,7 @@
@property (unsafe_unretained) id ud;
@property (strong) id sa;
@property (strong) id sb; // expected-note {{property declared here}}
-@property (strong) id sc; // expected-note {{property declared here}}
+@property (strong) id sc;
@property (strong) id sd;
@end
@@ -25,7 +25,7 @@
__unsafe_unretained id _uc;
id _sa;
__weak id _sb; // expected-error {{existing instance variable '_sb' for strong property 'sb' may not be __weak}}
- __unsafe_unretained id _sc; // expected-error {{existing instance variable '_sc' for strong property 'sc' may not be __unsafe_unretained}}
+ __unsafe_unretained id _sc;
}
@synthesize wa = _wa; // expected-note {{property synthesized here}}
@synthesize wb = _wb;
@@ -37,7 +37,7 @@
@synthesize ud = _ud;
@synthesize sa = _sa;
@synthesize sb = _sb; // expected-note {{property synthesized here}}
-@synthesize sc = _sc; // expected-note {{property synthesized here}}
+@synthesize sc = _sc;
@synthesize sd = _sd;
@end
@@ -62,6 +62,6 @@
void test_cast_qualifier_inference(__weak id *value) {
__weak id *a = (id*) value;
- __unsafe_unretained id *b = (id*) value; // expected-error {{initializing '__unsafe_unretained id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
+ __unsafe_unretained id *b = (id*) value; // expected-error {{initializing 'id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
}
diff --git a/test/SemaObjC/objc-class-property.m b/test/SemaObjC/objc-class-property.m
new file mode 100644
index 0000000..7775440
--- /dev/null
+++ b/test/SemaObjC/objc-class-property.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+@interface A : Root {
+ int x;
+ int z;
+}
+@property int x;
+@property int y;
+@property int z;
+@property(readonly) int ro, ro2;
+@property (class) int c;
+@property (class) int c2;
+@property (class) int x;
+@end
+
+@implementation A
+@dynamic x; // refers to the instance property
+@dynamic (class) x; // refers to the class property
+@synthesize z, c2; // expected-error {{@synthesize not allowed on a class property 'c2'}}
+@dynamic c; // refers to the class property
+@end
+
+int test() {
+ A *a = [[A alloc] init];
+ return a.x + A.c;
+}
diff --git a/test/SemaObjC/ovl-check.m b/test/SemaObjC/ovl-check.m
new file mode 100644
index 0000000..7fc8a64
--- /dev/null
+++ b/test/SemaObjC/ovl-check.m
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify %s -fobjc-arc
+//
+// These tests exist as a means to help ensure that diagnostics aren't printed
+// in overload resolution in ObjC.
+
+struct Type1 { int a; };
+@interface Iface1 @end
+
+@interface NeverCalled
+- (void) test:(struct Type1 *)arg;
+@end
+
+@interface TakesIface1
+- (void) test:(Iface1 *)arg;
+@end
+
+// PR26085, rdar://problem/24111333
+void testTakesIface1(id x, Iface1 *arg) {
+ // This should resolve silently to `TakesIface1`.
+ [x test:arg];
+}
+
+@class NSString;
+@interface NeverCalledv2
+- (void) testStr:(NSString *)arg;
+@end
+
+@interface TakesVanillaConstChar
+- (void) testStr:(const void *)a;
+@end
+
+// Not called out explicitly by PR26085, but related.
+void testTakesNSString(id x) {
+ // Overload resolution should not emit a diagnostic about needing to add an
+ // '@' before "someStringLiteral".
+ [x testStr:"someStringLiteral"];
+}
+
+typedef const void *CFTypeRef;
+id CreateSomething();
+
+@interface NeverCalledv3
+- (void) testCFTypeRef:(struct Type1 *)arg;
+@end
+
+@interface TakesCFTypeRef
+- (void) testCFTypeRef:(CFTypeRef)arg;
+@end
+
+// Not called out explicitly by PR26085, but related.
+void testTakesCFTypeRef(id x) {
+ // Overload resolution should occur silently, select the CFTypeRef overload,
+ // and produce a single complaint. (with notes)
+ [x testCFTypeRef:CreateSomething()]; // expected-error{{implicit conversion of Objective-C pointer type 'id' to C pointer type 'CFTypeRef'}} expected-note{{use __bridge}} expected-note{{use __bridge_retained}}
+}
diff --git a/test/SemaObjC/property-3.m b/test/SemaObjC/property-3.m
index 7c0ba57..8f2aa2d 100644
--- a/test/SemaObjC/property-3.m
+++ b/test/SemaObjC/property-3.m
@@ -29,5 +29,14 @@
@interface EKCalendar () <EKProtocolMutableCalendar>
@property (nonatomic, assign) BOOL allowReminders;
-@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from EKProtocolCalendar}}
+@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from 'EKProtocolCalendar'}}
+@end
+
+__attribute__((objc_root_class))
+@interface A
+@property (nonatomic, readonly, getter=isAvailable) int available; // expected-note{{property declared here}}
+@end
+
+@interface A ()
+@property (nonatomic, assign, getter=wasAvailable) int available; // expected-warning{{getter name mismatch between property redeclaration ('wasAvailable') and its original declaration ('isAvailable')}}
@end
diff --git a/test/SemaObjC/property-atomic-redecl.m b/test/SemaObjC/property-atomic-redecl.m
new file mode 100644
index 0000000..cb6d73a
--- /dev/null
+++ b/test/SemaObjC/property-atomic-redecl.m
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface A
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper
+@property (readonly) A *property;
+@end
+
+@interface AtomicInheritanceSuper()
+@property (nonatomic,readwrite,retain) A *property;
+@end
+
+@interface AtomicInheritanceSub : AtomicInheritanceSuper
+@property (readonly) A *property;
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper2
+@property (readonly) A *property;
+@end
+
+@interface AtomicInheritanceSub2 : AtomicInheritanceSuper2
+@property (nonatomic, readwrite, retain) A *property;
+@end
+
+@interface ReadonlyAtomic
+@property (readonly, nonatomic) A *property;
+@end
+
+@interface ReadonlyAtomic ()
+@property (readwrite) A *property;
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper3
+@property (readonly,atomic) A *property; // expected-note{{property declared here}}
+@end
+
+@interface AtomicInheritanceSuper3()
+@property (nonatomic,readwrite,retain) A *property; // expected-warning{{'atomic' attribute on property 'property' does not match the property inherited from 'AtomicInheritanceSuper3'}}
+@end
+
+@interface AtomicInheritanceSub3 : AtomicInheritanceSuper3
+@property (readonly) A *property;
+@end
+
+// Readonly, atomic public redeclaration of property in subclass.
+@interface AtomicInheritanceSuper4
+@property (readonly, atomic) A *property; // expected-note{{property declared here}}
+@end
+
+@interface AtomicInheritanceSub4 : AtomicInheritanceSuper4
+@property (nonatomic, readwrite, retain) A *property; // expected-warning{{atomic' attribute on property 'property' does not match the property inherited from 'AtomicInheritanceSuper4'}}
+@end
+
diff --git a/test/SemaObjC/property-in-class-extension-1.m b/test/SemaObjC/property-in-class-extension-1.m
index 8f5907b..67b57e5 100644
--- a/test/SemaObjC/property-in-class-extension-1.m
+++ b/test/SemaObjC/property-in-class-extension-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -verify -Weverything -Wno-objc-weak-compat %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -fsyntax-only -verify -Weverything -Wno-objc-weak-compat %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -verify -Weverything %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -fsyntax-only -verify -Weverything %s
// rdar://12103400
@class NSString;
@@ -58,6 +58,6 @@
@property (atomic, nonatomic, readonly, readwrite) float propertyName; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}} \
// expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
-@property (atomic, readwrite) float propertyName2; // expected-warning {{'atomic' attribute on property 'propertyName2' does not match the property inherited from radar12214070}}
+@property (atomic, readwrite) float propertyName2; // expected-warning {{'atomic' attribute on property 'propertyName2' does not match the property inherited from 'radar12214070'}}
@end
diff --git a/test/SemaObjCXX/block-for-lambda-conversion.mm b/test/SemaObjCXX/block-for-lambda-conversion.mm
new file mode 100644
index 0000000..671e83d
--- /dev/null
+++ b/test/SemaObjCXX/block-for-lambda-conversion.mm
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -std=c++11 %s
+
+enum NSEventType {
+ NSEventTypeFlagsChanged = 12
+};
+
+enum NSEventMask {
+ NSEventMaskLeftMouseDown = 1
+};
+
+static const NSEventType NSFlagsChanged = NSEventTypeFlagsChanged;
+
+@interface NSObject
+@end
+@interface NSEvent : NSObject {
+}
++ (nullable id)
+addMonitor:(NSEventMask)mask handler:(NSEvent *_Nullable (^)(NSEvent *))block;
+@end
+
+void test(id weakThis) {
+ id m_flagsChangedEventMonitor = [NSEvent
+ addMonitor:NSFlagsChangedMask //expected-error {{use of undeclared identifier 'NSFlagsChangedMask'}}
+ handler:[weakThis](NSEvent *flagsChangedEvent) {
+ return flagsChangedEvent;
+ }];
+}
diff --git a/test/SemaObjCXX/crash.mm b/test/SemaObjCXX/crash.mm
index 521b923..19cf309 100644
--- a/test/SemaObjCXX/crash.mm
+++ b/test/SemaObjCXX/crash.mm
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
// <rdar://problem/11286701>
namespace std {
@@ -18,6 +20,8 @@
typedef std::pair<int, int> IntegerPair;
-template<typename...Ts> void f(Ts); // expected-error {{unexpanded}} expected-warning {{extension}}
-
+template<typename...Ts> void f(Ts); // expected-error {{unexpanded}}
+#if __cplusplus <= 199711L // C++03 or earlier modes
+// expected-warning@-2 {{variadic templates are a C++11 extension}}
+#endif
@end
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index 7d8520c..e2bdd13 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile-10.5 -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile-10.5 -verify -Wno-objc-root-class -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile-10.5 -verify -Wno-objc-root-class -std=c++11 %s
+
@interface I1
- (int*)method;
@end
@@ -62,15 +65,25 @@
// or typename-specifiers.
if (false) {
if (true)
- return [typename identity<I3>::type method]; // expected-warning{{occurs outside of a template}}
+ return [typename identity<I3>::type method];
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
return [::I3 method];
}
int* ip1 = {[super method]};
int* ip2 = {[::I3 method]};
- int* ip3 = {[typename identity<I3>::type method]}; // expected-warning{{occurs outside of a template}}
- int* ip4 = {[typename identity<I2_holder>::type().get() method]}; // expected-warning{{occurs outside of a template}}
+ int* ip3 = {[typename identity<I3>::type method]};
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
+
+ int* ip4 = {[typename identity<I2_holder>::type().get() method]};
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
int array[5] = {[3] = 2};
return [super method];
}
diff --git a/test/SemaObjCXX/property-type-mismatch.mm b/test/SemaObjCXX/property-type-mismatch.mm
index 2b267ad..6ab07b8 100644
--- a/test/SemaObjCXX/property-type-mismatch.mm
+++ b/test/SemaObjCXX/property-type-mismatch.mm
@@ -18,3 +18,13 @@
@property (assign) NSObject<P2> *prop;
@end
+@interface C<T> : NSObject
+@end
+
+@interface D
+@property (nonatomic,readonly,nonnull) C<D *> *property;
+@end
+
+@interface D ()
+@property (nonatomic, setter=_setProperty:) C *property; // okay
+@end
diff --git a/test/SemaObjCXX/pseudo-destructor.mm b/test/SemaObjCXX/pseudo-destructor.mm
new file mode 100644
index 0000000..06570c1
--- /dev/null
+++ b/test/SemaObjCXX/pseudo-destructor.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+__attribute__((objc_root_class))
+@interface Root
+@end
+
+@class Forward;
+
+template <class T> void destroyPointer(T *t) {
+ t->~T();
+}
+
+template <class T> void destroyReference(T &t) {
+ t.~T();
+}
+
+template void destroyPointer<Root*>(Root **);
+template void destroyReference<Root*>(Root *&);
+
+// rdar://18522255
+template void destroyPointer<Forward*>(Forward **);
+template void destroyReference<Forward*>(Forward *&);
diff --git a/test/SemaObjCXX/vararg-non-pod.mm b/test/SemaObjCXX/vararg-non-pod.mm
index 5a6281d..daf9aa9 100644
--- a/test/SemaObjCXX/vararg-non-pod.mm
+++ b/test/SemaObjCXX/vararg-non-pod.mm
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-error=non-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-error=non-pod-varargs -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-error=non-pod-varargs -std=c++11
extern char version[];
@@ -17,7 +19,12 @@
{
C c(10);
- [d g:10, c]; // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
+ [d g:10, c];
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
+#else
+ // expected-no-diagnostics@-4
+#endif
[d g:10, version];
}
diff --git a/test/SemaOpenCL/cond.cl b/test/SemaOpenCL/cond.cl
index 8cc4f1e..60f7056 100644
--- a/test/SemaOpenCL/cond.cl
+++ b/test/SemaOpenCL/cond.cl
@@ -128,5 +128,5 @@
unsigned int ntest12(int2 C)
{
- return (unsigned int)(C ? foo1 : foo2); // expected-error {{taking address of function is not allowed}}
+ return (unsigned int)(C ? foo1 : foo2); // expected-error {{taking address of function is not allowed}} expected-error {{taking address of function is not allowed}}
}
diff --git a/test/SemaOpenCL/func_ptr.cl b/test/SemaOpenCL/func_ptr.cl
index f21a3d3..abeab73 100644
--- a/test/SemaOpenCL/func_ptr.cl
+++ b/test/SemaOpenCL/func_ptr.cl
@@ -11,6 +11,9 @@
foo((void*)foo); // expected-error{{taking address of function is not allowed}}
foo(&foo); // expected-error{{taking address of function is not allowed}}
+ // initializing an array with the address of functions is an error
+ void* vptrarr[2] = {foo, &foo}; // expected-error{{taking address of function is not allowed}} expected-error{{taking address of function is not allowed}}
+
// just calling a function is correct
foo(0);
}
diff --git a/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
new file mode 100644
index 0000000..ee36892
--- /dev/null
+++ b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0
+
+void test1(pipe int *p){// expected-error {{pipes packet types cannot be of reference type}}
+}
+void test2(pipe p){// expected-error {{missing actual type specifier for pipe}}
+}
+void test3(int pipe p){// expected-error {{cannot combine with previous 'int' declaration specifier}}
+}
diff --git a/test/SemaOpenCL/null_literal.cl b/test/SemaOpenCL/null_literal.cl
new file mode 100644
index 0000000..2fb2872
--- /dev/null
+++ b/test/SemaOpenCL/null_literal.cl
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -cl-std=CL2.0 -DCL20 -verify %s
+
+#define NULL ((void*)0)
+
+void foo(){
+
+global int* ptr1 = NULL;
+
+global int* ptr2 = (global void*)0;
+
+constant int* ptr3 = NULL;
+
+constant int* ptr4 = (global void*)0; // expected-error{{initializing '__constant int *' with an expression of type '__global void *' changes address space of pointer}}
+
+#ifdef CL20
+// Accept explicitly pointer to generic address space in OpenCL v2.0.
+global int* ptr5 = (generic void*)0;
+#endif
+
+global int* ptr6 = (local void*)0; // expected-error{{initializing '__global int *' with an expression of type '__local void *' changes address space of pointer}}
+
+bool cmp = ptr1 == NULL;
+
+cmp = ptr1 == (local void*)0; // expected-error{{comparison between ('__global int *' and '__local void *') which are pointers to non-overlapping address spaces}}
+
+cmp = ptr3 == NULL;
+
+}
diff --git a/test/SemaOpenCL/pipes-1.2-negative.cl b/test/SemaOpenCL/pipes-1.2-negative.cl
new file mode 100644
index 0000000..441a24c
--- /dev/null
+++ b/test/SemaOpenCL/pipes-1.2-negative.cl
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2
+
+void foo(read_only pipe int p); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-note {{to match this '('}}
diff --git a/test/SemaOpenCL/storageclass-cl20.cl b/test/SemaOpenCL/storageclass-cl20.cl
index f379d59..c8e7faa 100644
--- a/test/SemaOpenCL/storageclass-cl20.cl
+++ b/test/SemaOpenCL/storageclass-cl20.cl
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -DCL20 -cl-std=CL2.0
static constant int G1 = 0;
-int G2 = 0;// expected-error{{program scope variable must reside in global or constant address space}}
+int G2 = 0;
global int G3 = 0;
local int G4 = 0;// expected-error{{program scope variable must reside in global or constant address space}}
void kernel foo() {
- static int S1 = 5;// expected-error{{program scope variable must reside in global or constant address space}}
+ static int S1 = 5;
static global int S2 = 5;
static private int S3 = 5;// expected-error{{program scope variable must reside in global or constant address space}}
diff --git a/test/SemaTemplate/class-template-ctor-initializer.cpp b/test/SemaTemplate/class-template-ctor-initializer.cpp
index 6043327..6dae207 100644
--- a/test/SemaTemplate/class-template-ctor-initializer.cpp
+++ b/test/SemaTemplate/class-template-ctor-initializer.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<class X> struct A {};
@@ -55,7 +57,11 @@
}
namespace NonDependentError {
- struct Base { Base(int); }; // expected-note 2{{candidate}}
+ struct Base { Base(int); }; // expected-note {{candidate constructor not viable}}
+// expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-3 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
template<typename T>
struct Derived1 : Base {
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index 4f861de..63482d8 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -152,3 +152,10 @@
T &pT = T();
pT;
}
+
+namespace abstract_dependent_class {
+ template<typename T> struct A {
+ virtual A<T> *clone() = 0; // expected-note {{pure virtual}}
+ };
+ template<typename T> A<T> *A<T>::clone() { return new A<T>; } // expected-error {{abstract class type 'A<T>'}}
+}
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
index c5306a6..ee8475b 100644
--- a/test/SemaTemplate/constructor-template.cpp
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -1,5 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-struct X0 { // expected-note{{candidate}}
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct X0 { // expected-note {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
X0(int); // expected-note{{candidate}}
template<typename T> X0(T); // expected-note {{candidate}}
template<typename T, typename U> X0(T*, U*); // expected-note {{candidate}}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index bf08122..6826774 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -207,3 +207,14 @@
template<typename F> F Quux(F &&f);
auto Baz = Quux(Quux<float>);
}
+
+namespace NonDeducedNestedNameSpecifier {
+ template<typename T> struct A {
+ template<typename U> struct B {
+ B(int) {}
+ };
+ };
+
+ template<typename T> int f(A<T>, typename A<T>::template B<T>);
+ int k = f(A<int>(), 0);
+}
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index 4cfd7a5..0c97c20 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -56,3 +56,22 @@
baz data{0};
}
+
+// rdar://23810407
+// An IRGen failure due to a symbol collision due to a default argument
+// being instantiated twice. Credit goes to Richard Smith for this
+// reduction to a -fsyntax-only failure.
+namespace rdar23810407 {
+ // Instantiating the default argument multiple times will produce two
+ // different lambda types and thus instantiate this function multiple
+ // times, which will produce conflicting extern variable declarations.
+ template<typename T> int f(T t) {
+ extern T rdar23810407_variable;
+ return 0;
+ }
+ template<typename T> int g(int a = f([] {}));
+ void test() {
+ g<int>();
+ g<int>();
+ }
+}
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index 37d144b..d3e249d 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T, int N = 2> struct X; // expected-note{{template is declared here}}
X<int, 1> *x1;
@@ -142,7 +144,10 @@
namespace PR16288 {
template<typename X>
struct S {
- template<typename T = int, typename U> // expected-warning {{C++11}}
+ template<typename T = int, typename U>
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
+#endif
void f();
};
template<typename X>
@@ -152,8 +157,10 @@
namespace DR1635 {
template <class T> struct X {
- template <class U = typename T::type> static void f(int) {} // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} \
- // expected-warning {{C++11}}
+ template <class U = typename T::type> static void f(int) {} // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
+#endif
static void f(...) {}
};
@@ -172,3 +179,31 @@
C(T t = ); // expected-error {{expected expression}}
};
C<int> obj;
+
+namespace PR26134 {
+// Make sure when substituting default template arguments we do it in the current context.
+template<class T, bool Val = T::value>
+struct X {};
+
+template<bool B> struct Y {
+ void f() { X<Y> xy; }
+ static const bool value = B;
+};
+
+namespace ns1 {
+template<class T0>
+struct X {
+ template<bool B = T0::value> struct XInner { static const bool value = B; };
+};
+template<bool B> struct S { static const bool value = B; };
+#if __cplusplus > 199711L
+template<bool B> struct Y {
+ static constexpr bool f() { return typename X<S<B>>::template XInner<>{}.value; }
+ static_assert(f() == B, "");
+};
+Y<true> y;
+Y<false> y2;
+#endif
+
+} // end ns1
+} // end ns PR26134
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index 14b072a..438f5b1 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
template<typename T>
class C { C(int a0 = 0); };
@@ -6,6 +9,9 @@
C<char>::C(int a0);
struct S { }; // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
template<typename T> void f1(T a, T b = 10) { } // expected-error{{no viable conversion}} \
// expected-note{{passing argument to parameter 'b' here}}
@@ -67,7 +73,10 @@
xi.f(17);
}
-struct NotDefaultConstructible { // expected-note 2{{candidate}}
+struct NotDefaultConstructible { // expected-note 2 {{candidate constructor (the implicit copy constructor) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
NotDefaultConstructible(int); // expected-note 2{{candidate}}
};
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
index 2d515b4..037747d 100644
--- a/test/SemaTemplate/fun-template-def.cpp
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Tests that dependent expressions are always allowed, whereas non-dependent
// are checked as usual.
@@ -9,6 +11,9 @@
namespace std { class type_info {}; }
struct dummy {}; // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
template<typename T>
int f0(T x) {
diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp
index f5089c9..ffdb4c9 100644
--- a/test/SemaTemplate/instantiate-function-2.cpp
+++ b/test/SemaTemplate/instantiate-function-2.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
template <typename T> struct S {
S() { }
S(T t);
@@ -46,7 +49,10 @@
namespace AliasTagDef {
template<typename T>
T f() {
- using S = struct { // expected-warning {{C++11}}
+ using S = struct {
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{alias declarations are a C++11 extension}}
+#endif
T g() {
return T();
}
diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp
index c0ea6a0..a61af7a 100644
--- a/test/SemaTemplate/instantiate-local-class.cpp
+++ b/test/SemaTemplate/instantiate-local-class.cpp
@@ -448,3 +448,30 @@
}
template void f7<int>();
}
+
+// rdar://23721638: Ensure that we correctly perform implicit
+// conversions when instantiating the default arguments of local functions.
+namespace rdar23721638 {
+ struct A {
+ A(const char *) = delete; // expected-note 2 {{explicitly marked deleted here}}
+ };
+
+ template <typename T> void foo() {
+ struct Inner { // expected-note {{in instantiation}}
+ void operator()(T a = "") {} // expected-error {{conversion function from 'const char [1]' to 'rdar23721638::A' invokes a deleted function}}
+ // expected-note@-1 {{passing argument to parameter 'a' here}}
+ // expected-note@-2 {{candidate function not viable}}
+ };
+ Inner()(); // expected-error {{no matching function}}
+ }
+ template void foo<A>(); // expected-note 2 {{in instantiation}}
+
+ template <typename T> void bar() {
+ auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char [1]' to 'rdar23721638::A' invokes a deleted function}}
+ // expected-note@-1 {{passing argument to parameter 'a' here}}
+ // expected-note@-2 {{candidate function not viable}}
+ // expected-note@-3 {{conversion candidate of type}}
+ lambda(); // expected-error {{no matching function}}
+ }
+ template void bar<A>(); // expected-note {{in instantiation}}
+}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index a7b3433..648ee41 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
template<typename T, T Divisor>
class X {
public:
@@ -11,7 +14,13 @@
template<typename T>
class Y {
- static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'const float' is a GNU extension}}
+ static const T value = 0;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{in-class initializer for static data member of type 'const float' is a GNU extension}}
+#else
+// expected-error@-4 {{in-class initializer for static data member of type 'const float' requires 'constexpr' specifier}}
+// expected-note@-5 {{add 'constexpr'}}
+#endif
};
Y<float> fy; // expected-note{{in instantiation of template class 'Y<float>' requested here}}
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index e1a052c..4f3df27 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -308,7 +308,7 @@
template <typename T> struct C : A<T>, B<T> {
NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
};
-static_assert(sizeof(C<int>) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
+static_assert(sizeof(C<int>) != 0, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}}
}
namespace type_and_decl_in_base {
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index 635687d..78d09d1 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace N {
namespace M {
@@ -21,8 +23,15 @@
}
M::Promote<int>::type *ret_intptr3(int* ip) { return ip; }
- M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; } // expected-warning{{'template' keyword outside of a template}}
- M::template Promote<int> pi; // expected-warning{{'template' keyword outside of a template}}
+ M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; }
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'template' keyword outside of a template}}
+#endif
+
+ M::template Promote<int> pi;
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'template' keyword outside of a template}}
+#endif
}
N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; }
diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp
index 544d897..c0abb5b 100644
--- a/test/SemaTemplate/overload-candidates.cpp
+++ b/test/SemaTemplate/overload-candidates.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T>
const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}}
@@ -94,8 +96,11 @@
struct a_trait : std::false_type {};
template<typename T,
- typename Requires = typename std::enable_if<a_trait<T>::value>::type> // expected-warning {{C++11 extension}}
- // expected-note@-1 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+ typename Requires = typename std::enable_if<a_trait<T>::value>::type>
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
+#endif
+ // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
void foo() {}
void bar() { foo<int>(); } // expected-error {{no matching function for call to 'foo'}}
@@ -108,7 +113,10 @@
struct a_pony : std::enable_if<some_trait<T>::value> {};
template<typename T,
- typename Requires = typename a_pony<T>::type> // expected-warning {{C++11 extension}}
+ typename Requires = typename a_pony<T>::type>
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
+#endif
// FIXME: The source location here is poor.
void baz() { } // expected-note {{candidate template ignored: substitution failure [with T = int]: no type named 'type' in 'PR15673::a_pony<int>'}}
void quux() { baz<int>(); } // expected-error {{no matching function for call to 'baz'}}
@@ -116,11 +124,17 @@
// FIXME: This note doesn't make it clear which candidate we rejected.
template <typename T>
- using unicorns = typename std::enable_if<some_trait<T>::value>::type; // expected-warning {{C++11 extension}}
- // expected-note@-1 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+ using unicorns = typename std::enable_if<some_trait<T>::value>::type;
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{alias declarations are a C++11 extension}}
+#endif
+ // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
template<typename T,
- typename Requires = unicorns<T> > // expected-warning {{C++11 extension}}
+ typename Requires = unicorns<T> >
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
+#endif
void wibble() {}
void wobble() { wibble<int>(); } // expected-error {{no matching function for call to 'wibble'}}
}
diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp
index a93af50..d5ecd8c 100644
--- a/test/SemaTemplate/partial-spec-instantiate.cpp
+++ b/test/SemaTemplate/partial-spec-instantiate.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// PR4607
template <class T> struct X {};
@@ -47,4 +49,9 @@
};
X<bool, -1>::type value;
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{non-type template argument evaluates to -1, which cannot be narrowed to type 'bool'}}
+#else
+ // expected-no-diagnostics
+#endif
}
diff --git a/test/SemaTemplate/qualified-names-diag.cpp b/test/SemaTemplate/qualified-names-diag.cpp
index b2df47b..06b9492 100644
--- a/test/SemaTemplate/qualified-names-diag.cpp
+++ b/test/SemaTemplate/qualified-names-diag.cpp
@@ -1,7 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace std {
- template<typename T> class vector { }; // expected-note{{candidate}}
+ template<typename T> class vector { }; // expected-note{{candidate function (the implicit copy assignment operator) not viable}}
+#if __cplusplus >= 201103L // C++11 or later
+ // expected-note@-2 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
}
typedef int INT;
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index dec5dd3..6d93f15 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<template<typename T> class X> struct A; // expected-note 2{{previous template template parameter is here}}
@@ -31,7 +33,10 @@
A<f> *a9; // expected-error{{must be a class template}}
// Evil digraph '<:' is parsed as '[', expect error.
-A<::N::Z> *a10; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+A<::N::Z> *a10;
+#if __cplusplus <= 199711L
+// expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+#endif
// Do not do a digraph correction here.
A<: :N::Z> *a11; // expected-error{{expected expression}} \
@@ -56,18 +61,40 @@
}
// PR12179
-template <typename Primitive, template <Primitive...> class F> // expected-warning {{variadic templates are a C++11 extension}}
+template <typename Primitive, template <Primitive...> class F>
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{variadic templates are a C++11 extension}}
+#endif
+
struct unbox_args {
typedef typename Primitive::template call<F> x;
};
-template <template <typename> class... Templates> // expected-warning {{variadic templates are a C++11 extension}}
-struct template_tuple {};
+template <template <typename> class... Templates>
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{variadic templates are a C++11 extension}}
+#endif
+
+struct template_tuple {
+#if __cplusplus >= 201103L
+ static constexpr int N = sizeof...(Templates);
+#endif
+};
template <typename T>
struct identity {};
-template <template <typename> class... Templates> // expected-warning {{variadic templates are a C++11 extension}}
+template <template <typename> class... Templates>
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{variadic templates are a C++11 extension}}
+#endif
+
template_tuple<Templates...> f7() {}
+#if __cplusplus >= 201103L
+struct S : public template_tuple<identity, identity> {
+ static_assert(N == 2, "Number of template arguments incorrect");
+};
+#endif
+
void foo() {
f7<identity>();
}
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index be5fbb1..1c77038 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -1,15 +1,23 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T> struct vector;
// C++ [temp.class.spec]p6:
namespace N {
namespace M {
- template<typename T> struct A; // expected-note{{here}}
+ template<typename T> struct A;
+#if __cplusplus <= 199711L // C++03 or earlier modes
+ // expected-note@-2{{explicitly specialized declaration is here}}
+#endif
}
}
template<typename T>
-struct N::M::A<T*> { }; // expected-warning{{C++11 extension}}
+struct N::M::A<T*> { };
+#if __cplusplus <= 199711L
+// expected-warning@-2{{first declaration of class template partial specialization of 'A' outside namespace 'M' is a C++11 extension}}
+#endif
// C++ [temp.class.spec]p9
// bullet 1
diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp
index 44cf966..2856c99 100644
--- a/test/SemaTemplate/typename-specifier-4.cpp
+++ b/test/SemaTemplate/typename-specifier-4.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T, typename U>
struct is_same {
static const bool value = false;
@@ -27,8 +29,11 @@
int a0[is_same<metafun_apply2<make_pair, int, float>::type,
pair<int, float> >::value? 1 : -1];
int a1[is_same<
- typename make_pair::template apply<int, float>, // expected-warning{{'template' keyword outside of a template}} \
- // expected-warning{{'typename' occurs outside of a template}}
+ typename make_pair::template apply<int, float>,
+#if __cplusplus <= 199711L // C++03 and earlier modes
+ // expected-warning@-2 {{'template' keyword outside of a template}}
+ // expected-warning@-3 {{'typename' occurs outside of a template}}
+#endif
make_pair::apply<int, float>
>::value? 1 : -1];
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index 602e903..b36a103 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -DMSVC
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -fms-compatibility -DMSVC
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -fms-compatibility -DMSVC
namespace N {
struct A {
typedef int type;
@@ -16,22 +20,38 @@
int i;
-typename N::A::type *ip1 = &i; // expected-warning{{'typename' occurs outside of a template}}
-typename N::B::type *ip2 = &i; // expected-error{{no type named 'type' in 'N::B'}} \
-// expected-warning{{'typename' occurs outside of a template}}
-typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}} \
-// expected-warning{{'typename' occurs outside of a template}}
+typename N::A::type *ip1 = &i;
+#if __cplusplus <= 199711L // C++03 or earlier modes
+// expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
+typename N::B::type *ip2 = &i; // expected-error{{no type named 'type' in 'N::B'}}
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
+typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}}
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
void test(double d) {
- typename N::A::type f(typename N::A::type(a)); // expected-warning{{disambiguated as a function declaration}} \
- // expected-note{{add a pair of parentheses}} expected-warning 2{{'typename' occurs outside of a template}}
+ typename N::A::type f(typename N::A::type(a)); // expected-warning{{disambiguated as a function declaration}}
+ // expected-note@-1 {{add a pair of parentheses}}
+#if __cplusplus <= 199711L
+ // expected-warning@-3 2{{'typename' occurs outside of a template}}
+#endif
int five = f(5);
using namespace N;
- for (typename A::type i = 0; i < 10; ++i) // expected-warning{{'typename' occurs outside of a template}}
+ for (typename A::type i = 0; i < 10; ++i)
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
five += 1;
- const typename N::A::type f2(d); // expected-warning{{'typename' occurs outside of a template}}
+ const typename N::A::type f2(d);
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{'typename' occurs outside of a template}}
+#endif
}
namespace N {
diff --git a/test/Tooling/clang-check-analyzer.cpp b/test/Tooling/clang-check-analyzer.cpp
index 16cf7ce..ee0a6dc 100644
--- a/test/Tooling/clang-check-analyzer.cpp
+++ b/test/Tooling/clang-check-analyzer.cpp
@@ -1,4 +1,4 @@
// RUN: clang-check -analyze "%s" -- -c 2>&1 | FileCheck %s
// CHECK: Dereference of null pointer
-int a(int *x) { if(x){} *x = 47; }
+void a(int *x) { if(x){} *x = 47; }
diff --git a/test/Tooling/clang-check-extra-arg.cpp b/test/Tooling/clang-check-extra-arg.cpp
index f671535..a5d00bc 100644
--- a/test/Tooling/clang-check-extra-arg.cpp
+++ b/test/Tooling/clang-check-extra-arg.cpp
@@ -2,4 +2,4 @@
// CHECK: unknown warning option '-Wunimplemented-warning-before'
// CHECK: unknown warning option '-Wunimplemented-warning'
-int a(){}
+void a(){}
diff --git a/test/lit.cfg b/test/lit.cfg
index 9c5c71e..c602650 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -422,10 +422,6 @@
if platform.system() not in ['Windows']:
config.available_features.add('can-remove-opened-file')
-# Not set for targeting tls-incapable targets.
-if not re.match(r'.*-cygwin$', config.target_triple):
- config.available_features.add('tls')
-
# Returns set of available features, registered-target(s) and asserts.
def get_llvm_config_props():
set_of_features = set()
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index dba676a..510bc44 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -5,8 +5,6 @@
add_clang_subdirectory(clang-format)
add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
-add_clang_subdirectory(scan-build)
-add_clang_subdirectory(scan-view)
add_clang_subdirectory(c-index-test)
add_clang_subdirectory(libclang)
@@ -18,6 +16,8 @@
if(CLANG_ENABLE_STATIC_ANALYZER)
add_clang_subdirectory(clang-check)
+ add_clang_subdirectory(scan-build)
+ add_clang_subdirectory(scan-view)
endif()
# We support checking out the clang-tools-extra repository into the 'extra'
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 26ef5f2..b2f9120 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -76,7 +76,9 @@
options |= CXTranslationUnit_SkipFunctionBodies;
if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
-
+ if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
+ options |= CXTranslationUnit_CreatePreambleOnFirstParse;
+
return options;
}
@@ -1248,6 +1250,32 @@
}
/******************************************************************************/
+/* Visibility testing. */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ const char *visibility = 0;
+
+ if (clang_isInvalid(clang_getCursorKind(cursor)))
+ return CXChildVisit_Recurse;
+
+ switch (clang_getCursorVisibility(cursor)) {
+ case CXVisibility_Invalid: break;
+ case CXVisibility_Hidden: visibility = "Hidden"; break;
+ case CXVisibility_Protected: visibility = "Protected"; break;
+ case CXVisibility_Default: visibility = "Default"; break;
+ }
+
+ if (visibility) {
+ PrintCursor(cursor, NULL);
+ printf("visibility=%s\n", visibility);
+ }
+
+ return CXChildVisit_Recurse;
+}
+
+/******************************************************************************/
/* Typekind testing. */
/******************************************************************************/
@@ -1441,6 +1469,25 @@
return CXChildVisit_Continue;
}
+static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ unsigned I, E;
+ CXStringSet *Manglings = NULL;
+ if (clang_isUnexposed(clang_getCursorKind(cursor)))
+ return CXChildVisit_Recurse;
+ if (!clang_isDeclaration(clang_getCursorKind(cursor)))
+ return CXChildVisit_Recurse;
+ if (clang_getCursorKind(cursor) == CXCursor_ParmDecl)
+ return CXChildVisit_Continue;
+ PrintCursor(cursor, NULL);
+ Manglings = clang_Cursor_getCXXManglings(cursor);
+ for (I = 0, E = Manglings->Count; I < E; ++I)
+ printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
+ clang_disposeStringSet(Manglings);
+ printf("\n");
+ return CXChildVisit_Recurse;
+}
+
/******************************************************************************/
/* Bitwidth testing. */
/******************************************************************************/
@@ -1461,6 +1508,22 @@
}
/******************************************************************************/
+/* Type declaration testing */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
+
+ if (clang_isDeclaration(typeDeclaration.kind)) {
+ PrintCursor(cursor, NULL);
+ PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
+ }
+
+ return CXChildVisit_Recurse;
+}
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
@@ -1546,6 +1609,8 @@
int num_unsaved_files = 0;
enum CXErrorCode Err;
int result;
+ unsigned Repeats = 0;
+ unsigned I;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
(!strcmp(filter, "local") ||
@@ -1562,6 +1627,9 @@
return -1;
}
+ if (getenv("CINDEXTEST_EDITING"))
+ Repeats = 5;
+
Err = clang_parseTranslationUnit2(Idx, 0,
argv + num_unsaved_files,
argc - num_unsaved_files,
@@ -1575,6 +1643,22 @@
return 1;
}
+ for (I = 0; I != Repeats; ++I) {
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ if (Repeats > 1) {
+ Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ clang_defaultReparseOptions(TU));
+ if (Err != CXError_Success) {
+ describeLibclangFailure(Err);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ clang_disposeIndex(Idx);
+ return 1;
+ }
+ }
+ }
+
result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
CommentSchemaFile);
free_remapped_files(unsaved_files, num_unsaved_files);
@@ -2203,7 +2287,11 @@
unsigned column;
} CursorSourceLocation;
-static int inspect_cursor_at(int argc, const char **argv) {
+typedef void (*cursor_handler_t)(CXCursor cursor);
+
+static int inspect_cursor_at(int argc, const char **argv,
+ const char *locations_flag,
+ cursor_handler_t handler) {
CXIndex CIdx;
int errorCode;
struct CXUnsavedFile *unsaved_files = 0;
@@ -2217,7 +2305,7 @@
unsigned I;
/* Count the number of locations. */
- while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
+ while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
++NumLocations;
/* Parse the locations. */
@@ -2225,7 +2313,7 @@
Locations = (CursorSourceLocation *)malloc(
NumLocations * sizeof(CursorSourceLocation));
for (Loc = 0; Loc < NumLocations; ++Loc) {
- const char *input = argv[Loc + 1] + strlen("-cursor-at=");
+ const char *input = argv[Loc + 1] + strlen(locations_flag);
if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
&Locations[Loc].line,
&Locations[Loc].column, 0, 0)))
@@ -2284,72 +2372,7 @@
return -1;
if (I + 1 == Repeats) {
- CXCompletionString completionString = clang_getCursorCompletionString(
- Cursor);
- CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
- CXString Spelling;
- const char *cspell;
- unsigned line, column;
- clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
- printf("%d:%d ", line, column);
- PrintCursor(Cursor, NULL);
- PrintCursorExtent(Cursor);
- Spelling = clang_getCursorSpelling(Cursor);
- cspell = clang_getCString(Spelling);
- if (cspell && strlen(cspell) != 0) {
- unsigned pieceIndex;
- printf(" Spelling=%s (", cspell);
- for (pieceIndex = 0; ; ++pieceIndex) {
- CXSourceRange range =
- clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
- if (clang_Range_isNull(range))
- break;
- PrintRange(range, 0);
- }
- printf(")");
- }
- clang_disposeString(Spelling);
- if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
- printf(" Selector index=%d",
- clang_Cursor_getObjCSelectorIndex(Cursor));
- if (clang_Cursor_isDynamicCall(Cursor))
- printf(" Dynamic-call");
- if (Cursor.kind == CXCursor_ObjCMessageExpr) {
- CXType T = clang_Cursor_getReceiverType(Cursor);
- CXString S = clang_getTypeKindSpelling(T.kind);
- printf(" Receiver-type=%s", clang_getCString(S));
- clang_disposeString(S);
- }
-
- {
- CXModule mod = clang_Cursor_getModule(Cursor);
- CXFile astFile;
- CXString name, astFilename;
- unsigned i, numHeaders;
- if (mod) {
- astFile = clang_Module_getASTFile(mod);
- astFilename = clang_getFileName(astFile);
- name = clang_Module_getFullName(mod);
- numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
- printf(" ModuleName=%s (%s) system=%d Headers(%d):",
- clang_getCString(name), clang_getCString(astFilename),
- clang_Module_isSystem(mod), numHeaders);
- clang_disposeString(name);
- clang_disposeString(astFilename);
- for (i = 0; i < numHeaders; ++i) {
- CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
- CXString filename = clang_getFileName(file);
- printf("\n%s", clang_getCString(filename));
- clang_disposeString(filename);
- }
- }
- }
-
- if (completionString != NULL) {
- printf("\nCompletion string: ");
- print_completion_string(completionString, stdout);
- }
- printf("\n");
+ handler(Cursor);
free(Locations[Loc].filename);
}
}
@@ -2363,6 +2386,184 @@
return 0;
}
+static void inspect_print_cursor(CXCursor Cursor) {
+ CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
+ CXCompletionString completionString = clang_getCursorCompletionString(
+ Cursor);
+ CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+ CXString Spelling;
+ const char *cspell;
+ unsigned line, column;
+ clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+ printf("%d:%d ", line, column);
+ PrintCursor(Cursor, NULL);
+ PrintCursorExtent(Cursor);
+ Spelling = clang_getCursorSpelling(Cursor);
+ cspell = clang_getCString(Spelling);
+ if (cspell && strlen(cspell) != 0) {
+ unsigned pieceIndex;
+ printf(" Spelling=%s (", cspell);
+ for (pieceIndex = 0; ; ++pieceIndex) {
+ CXSourceRange range =
+ clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+ if (clang_Range_isNull(range))
+ break;
+ PrintRange(range, 0);
+ }
+ printf(")");
+ }
+ clang_disposeString(Spelling);
+ if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
+ printf(" Selector index=%d",
+ clang_Cursor_getObjCSelectorIndex(Cursor));
+ if (clang_Cursor_isDynamicCall(Cursor))
+ printf(" Dynamic-call");
+ if (Cursor.kind == CXCursor_ObjCMessageExpr) {
+ CXType T = clang_Cursor_getReceiverType(Cursor);
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" Receiver-type=%s", clang_getCString(S));
+ clang_disposeString(S);
+ }
+
+ {
+ CXModule mod = clang_Cursor_getModule(Cursor);
+ CXFile astFile;
+ CXString name, astFilename;
+ unsigned i, numHeaders;
+ if (mod) {
+ astFile = clang_Module_getASTFile(mod);
+ astFilename = clang_getFileName(astFile);
+ name = clang_Module_getFullName(mod);
+ numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
+ printf(" ModuleName=%s (%s) system=%d Headers(%d):",
+ clang_getCString(name), clang_getCString(astFilename),
+ clang_Module_isSystem(mod), numHeaders);
+ clang_disposeString(name);
+ clang_disposeString(astFilename);
+ for (i = 0; i < numHeaders; ++i) {
+ CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
+ CXString filename = clang_getFileName(file);
+ printf("\n%s", clang_getCString(filename));
+ clang_disposeString(filename);
+ }
+ }
+ }
+
+ if (completionString != NULL) {
+ printf("\nCompletion string: ");
+ print_completion_string(completionString, stdout);
+ }
+ printf("\n");
+}
+
+static void display_evaluate_results(CXEvalResult result) {
+ switch (clang_EvalResult_getKind(result)) {
+ case CXEval_Int:
+ {
+ int val = clang_EvalResult_getAsInt(result);
+ printf("Kind: Int , Value: %d", val);
+ break;
+ }
+ case CXEval_Float:
+ {
+ double val = clang_EvalResult_getAsDouble(result);
+ printf("Kind: Float , Value: %f", val);
+ break;
+ }
+ case CXEval_ObjCStrLiteral:
+ {
+ const char* str = clang_EvalResult_getAsStr(result);
+ printf("Kind: ObjCString , Value: %s", str);
+ break;
+ }
+ case CXEval_StrLiteral:
+ {
+ const char* str = clang_EvalResult_getAsStr(result);
+ printf("Kind: CString , Value: %s", str);
+ break;
+ }
+ case CXEval_CFStr:
+ {
+ const char* str = clang_EvalResult_getAsStr(result);
+ printf("Kind: CFString , Value: %s", str);
+ break;
+ }
+ default:
+ printf("Unexposed");
+ break;
+ }
+}
+
+static void inspect_evaluate_cursor(CXCursor Cursor) {
+ CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+ CXString Spelling;
+ const char *cspell;
+ unsigned line, column;
+ CXEvalResult ER;
+
+ clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+ printf("%d:%d ", line, column);
+ PrintCursor(Cursor, NULL);
+ PrintCursorExtent(Cursor);
+ Spelling = clang_getCursorSpelling(Cursor);
+ cspell = clang_getCString(Spelling);
+ if (cspell && strlen(cspell) != 0) {
+ unsigned pieceIndex;
+ printf(" Spelling=%s (", cspell);
+ for (pieceIndex = 0; ; ++pieceIndex) {
+ CXSourceRange range =
+ clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+ if (clang_Range_isNull(range))
+ break;
+ PrintRange(range, 0);
+ }
+ printf(")");
+ }
+ clang_disposeString(Spelling);
+
+ ER = clang_Cursor_Evaluate(Cursor);
+ if (!ER) {
+ printf("Not Evaluatable");
+ } else {
+ display_evaluate_results(ER);
+ clang_EvalResult_dispose(ER);
+ }
+ printf("\n");
+}
+
+static void inspect_macroinfo_cursor(CXCursor Cursor) {
+ CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+ CXString Spelling;
+ const char *cspell;
+ unsigned line, column;
+ clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+ printf("%d:%d ", line, column);
+ PrintCursor(Cursor, NULL);
+ PrintCursorExtent(Cursor);
+ Spelling = clang_getCursorSpelling(Cursor);
+ cspell = clang_getCString(Spelling);
+ if (cspell && strlen(cspell) != 0) {
+ unsigned pieceIndex;
+ printf(" Spelling=%s (", cspell);
+ for (pieceIndex = 0; ; ++pieceIndex) {
+ CXSourceRange range =
+ clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+ if (clang_Range_isNull(range))
+ break;
+ PrintRange(range, 0);
+ }
+ printf(")");
+ }
+ clang_disposeString(Spelling);
+
+ if (clang_Cursor_isMacroBuiltin(Cursor)) {
+ printf("[builtin macro]");
+ } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
+ printf("[function macro]");
+ }
+ printf("\n");
+}
+
static enum CXVisitorResult findFileRefsVisit(void *context,
CXCursor cursor, CXSourceRange range) {
if (clang_Range_isNull(range))
@@ -4037,6 +4238,8 @@
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
+ " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
+ " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
" c-index-test -file-refs-at=<site> <compiler arguments>\n"
" c-index-test -file-includes-in=<filename> <compiler arguments>\n");
fprintf(stderr,
@@ -4065,9 +4268,11 @@
" c-index-test -test-inclusion-stack-tu <AST file>\n");
fprintf(stderr,
" c-index-test -test-print-linkage-source {<args>}*\n"
+ " c-index-test -test-print-visibility {<args>}*\n"
" c-index-test -test-print-type {<args>}*\n"
" c-index-test -test-print-type-size {<args>}*\n"
" c-index-test -test-print-bitwidth {<args>}*\n"
+ " c-index-test -test-print-type-declaration {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
" c-index-test -write-pch <file> <compiler arguments>\n");
@@ -4100,7 +4305,13 @@
if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
return perform_code_completion(argc, argv, 1);
if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
- return inspect_cursor_at(argc, argv);
+ return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
+ if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
+ return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
+ inspect_evaluate_cursor);
+ if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
+ return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
+ inspect_macroinfo_cursor);
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
@@ -4152,17 +4363,25 @@
else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
NULL);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility,
+ NULL);
else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintType, 0);
else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintTypeSize, 0);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all",
+ PrintTypeDeclaration, 0);
else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintBitWidth, 0);
else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
+ return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
if (argc > 2)
return print_usrs(argv + 2, argv + argc);
diff --git a/tools/clang-format-vs/README.txt b/tools/clang-format-vs/README.txt
index 636b89f..b23355d 100644
--- a/tools/clang-format-vs/README.txt
+++ b/tools/clang-format-vs/README.txt
@@ -2,9 +2,10 @@
for clang-format.
Build prerequisites are:
-- Visual Studio 2012 Professional
-- Visual Studio 2010 Professional
-- Visual Studio 2010 SDK.
+- Visual Studio 2013 Professional
+- Visual Studio 2013 SDK
+- Visual Studio 2010 Professional (?)
+- Visual Studio 2010 SDK (?)
The extension is built using CMake by setting BUILD_CLANG_FORMAT_VS_PLUGIN=ON
when configuring a Clang build, and building the clang_format_vsix target.
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index 7cdb823..36f237f 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -98,9 +98,11 @@
"clang-format from an editor integration"),
cl::init(0), cl::cat(ClangFormatCategory));
-static cl::opt<bool> SortIncludes("sort-includes",
- cl::desc("Sort touched include lines"),
- cl::cat(ClangFormatCategory));
+static cl::opt<bool> SortIncludes(
+ "sort-includes",
+ cl::desc("If set, overrides the include sorting behavior determined by the "
+ "SortIncludes style flag"),
+ cl::cat(ClangFormatCategory));
static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"),
cl::cat(ClangFormatCategory));
@@ -138,18 +140,18 @@
InMemoryFileSystem.get());
if (!LineRanges.empty()) {
if (!Offsets.empty() || !Lengths.empty()) {
- llvm::errs() << "error: cannot use -lines with -offset/-length\n";
+ errs() << "error: cannot use -lines with -offset/-length\n";
return true;
}
for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) {
unsigned FromLine, ToLine;
if (parseLineRange(LineRanges[i], FromLine, ToLine)) {
- llvm::errs() << "error: invalid <start line>:<end line> pair\n";
+ errs() << "error: invalid <start line>:<end line> pair\n";
return true;
}
if (FromLine > ToLine) {
- llvm::errs() << "error: start line should be less than end line\n";
+ errs() << "error: start line should be less than end line\n";
return true;
}
SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
@@ -167,14 +169,12 @@
Offsets.push_back(0);
if (Offsets.size() != Lengths.size() &&
!(Offsets.size() == 1 && Lengths.empty())) {
- llvm::errs()
- << "error: number of -offset and -length arguments must match.\n";
+ errs() << "error: number of -offset and -length arguments must match.\n";
return true;
}
for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
if (Offsets[i] >= Code->getBufferSize()) {
- llvm::errs() << "error: offset " << Offsets[i]
- << " is outside the file\n";
+ errs() << "error: offset " << Offsets[i] << " is outside the file\n";
return true;
}
SourceLocation Start =
@@ -182,9 +182,9 @@
SourceLocation End;
if (i < Lengths.size()) {
if (Offsets[i] + Lengths[i] > Code->getBufferSize()) {
- llvm::errs() << "error: invalid length " << Lengths[i]
- << ", offset + length (" << Offsets[i] + Lengths[i]
- << ") is outside the file.\n";
+ errs() << "error: invalid length " << Lengths[i]
+ << ", offset + length (" << Offsets[i] + Lengths[i]
+ << ") is outside the file.\n";
return true;
}
End = Start.getLocWithOffset(Lengths[i]);
@@ -204,26 +204,26 @@
size_t From = 0;
size_t Index;
while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) {
- llvm::outs() << Text.substr(From, Index - From);
+ outs() << Text.substr(From, Index - From);
switch (Text[Index]) {
case '\n':
- llvm::outs() << " ";
+ outs() << " ";
break;
case '\r':
- llvm::outs() << " ";
+ outs() << " ";
break;
case '<':
- llvm::outs() << "<";
+ outs() << "<";
break;
case '&':
- llvm::outs() << "&";
+ outs() << "&";
break;
default:
llvm_unreachable("Unexpected character encountered!");
}
From = Index + 1;
}
- llvm::outs() << Text.substr(From);
+ outs() << Text.substr(From);
}
static void outputReplacementsXML(const Replacements &Replaces) {
@@ -241,7 +241,7 @@
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
MemoryBuffer::getFileOrSTDIN(FileName);
if (std::error_code EC = CodeOrErr.getError()) {
- llvm::errs() << EC.message() << "\n";
+ errs() << EC.message() << "\n";
return true;
}
std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
@@ -252,33 +252,31 @@
return true;
StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName;
FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle);
- Replacements Replaces;
- std::string ChangedCode;
- if (SortIncludes) {
- Replaces =
- sortIncludes(FormatStyle, Code->getBuffer(), Ranges, AssumedFileName);
- ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
- for (const auto &R : Replaces)
- Ranges.push_back({R.getOffset(), R.getLength()});
- } else {
- ChangedCode = Code->getBuffer().str();
- }
+ if (SortIncludes.getNumOccurrences() != 0)
+ FormatStyle.SortIncludes = SortIncludes;
+ unsigned CursorPosition = Cursor;
+ Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges,
+ AssumedFileName, &CursorPosition);
+ std::string ChangedCode =
+ tooling::applyAllReplacements(Code->getBuffer(), Replaces);
+ for (const auto &R : Replaces)
+ Ranges.push_back({R.getOffset(), R.getLength()});
bool IncompleteFormat = false;
- Replaces = tooling::mergeReplacements(
- Replaces, reformat(FormatStyle, ChangedCode, Ranges, AssumedFileName,
- &IncompleteFormat));
+ Replacements FormatChanges = reformat(FormatStyle, ChangedCode, Ranges,
+ AssumedFileName, &IncompleteFormat);
+ Replaces = tooling::mergeReplacements(Replaces, FormatChanges);
if (OutputXML) {
- llvm::outs() << "<?xml version='1.0'?>\n<replacements "
- "xml:space='preserve' incomplete_format='"
- << (IncompleteFormat ? "true" : "false") << "'>\n";
+ outs() << "<?xml version='1.0'?>\n<replacements "
+ "xml:space='preserve' incomplete_format='"
+ << (IncompleteFormat ? "true" : "false") << "'>\n";
if (Cursor.getNumOccurrences() != 0)
- llvm::outs() << "<cursor>"
- << tooling::shiftedCodePosition(Replaces, Cursor)
- << "</cursor>\n";
+ outs() << "<cursor>"
+ << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
+ << "</cursor>\n";
outputReplacementsXML(Replaces);
- llvm::outs() << "</replacements>\n";
+ outs() << "</replacements>\n";
} else {
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
new vfs::InMemoryFileSystem);
@@ -293,13 +291,13 @@
tooling::applyAllReplacements(Replaces, Rewrite);
if (Inplace) {
if (FileName == "-")
- llvm::errs() << "error: cannot use -i when reading from stdin.\n";
+ errs() << "error: cannot use -i when reading from stdin.\n";
else if (Rewrite.overwriteChangedFiles())
return true;
} else {
if (Cursor.getNumOccurrences() != 0)
outs() << "{ \"Cursor\": "
- << tooling::shiftedCodePosition(Replaces, Cursor)
+ << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
<< ", \"IncompleteFormat\": "
<< (IncompleteFormat ? "true" : "false") << " }\n";
Rewrite.getEditBuffer(ID).write(outs());
@@ -339,7 +337,7 @@
clang::format::configurationAsText(clang::format::getStyle(
Style, FileNames.empty() ? AssumeFileName : FileNames[0],
FallbackStyle));
- llvm::outs() << Config << "\n";
+ outs() << Config << "\n";
return 0;
}
@@ -353,8 +351,8 @@
break;
default:
if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) {
- llvm::errs() << "error: -offset, -length and -lines can only be used for "
- "single file.\n";
+ errs() << "error: -offset, -length and -lines can only be used for "
+ "single file.\n";
return 1;
}
for (unsigned i = 0; i < FileNames.size(); ++i)
diff --git a/tools/clang-format/clang-format-sublime.py b/tools/clang-format/clang-format-sublime.py
index 1cffcec..16ff56e 100644
--- a/tools/clang-format/clang-format-sublime.py
+++ b/tools/clang-format/clang-format-sublime.py
@@ -32,7 +32,7 @@
if encoding == 'Undefined':
encoding = 'utf-8'
regions = []
- command = [binary, '-sort-includes', '-style', style]
+ command = [binary, '-style', style]
for region in self.view.sel():
regions.append(region)
region_offset = min(region.a, region.b)
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index 6de45de..ca46144 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -126,7 +126,6 @@
nil `(,temp-buffer ,temp-file) nil
"-output-replacements-xml"
- "-sort-includes"
"-assume-filename" (or (buffer-file-name) "")
"-style" style
"-offset" (number-to-string start)
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index 1725e86..5cb41fc 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -72,7 +72,7 @@
startupinfo.wShowWindow = subprocess.SW_HIDE
# Call formatter.
- command = [binary, '-style', style, '-cursor', str(cursor), '-sort-includes']
+ command = [binary, '-style', style, '-cursor', str(cursor)]
if lines != 'all':
command.extend(['-lines', lines])
if fallback_style:
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index 06f7432..abbd3af 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -64,9 +64,11 @@
new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
// Try to build a CompilerInvocation.
+ SmallVector<const char *, 4> Args;
+ Args.push_back("diagtool");
+ Args.append(argv, argv + argc);
std::unique_ptr<CompilerInvocation> Invocation(
- createInvocationFromCommandLine(llvm::makeArrayRef(argv, argc),
- InterimDiags));
+ createInvocationFromCommandLine(Args, InterimDiags));
if (!Invocation)
return nullptr;
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 73bebb6..3645734 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -24,7 +24,7 @@
set(LLVM_NO_DEAD_STRIP 1)
endif()
-add_clang_executable(clang
+add_clang_tool(clang
driver.cpp
cc1_main.cpp
cc1as_main.cpp
@@ -53,15 +53,6 @@
add_dependencies(clang clang-headers)
-install(TARGETS clang
- RUNTIME DESTINATION bin
- COMPONENT clang)
-add_custom_target(install-clang
- DEPENDS clang
- COMMAND "${CMAKE_COMMAND}"
- -DCMAKE_INSTALL_COMPONENT=clang
- -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
-
if(NOT CLANG_LINKS_TO_CREATE)
set(CLANG_LINKS_TO_CREATE clang++ clang-cl)
@@ -98,8 +89,12 @@
set(TOOL_INFO_BUILD_VERSION)
endif()
-if(CLANG_ORDER_FILE)
+check_cxx_compiler_flag("-Wl,-order_file,${CLANG_ORDER_FILE}"
+ LINKER_HAS_ORDER_FILE_FLAG)
+
+if(LINKER_HAS_ORDER_FILE_FLAG AND CLANG_ORDER_FILE)
target_link_libraries(clang "-Wl,-order_file,${CLANG_ORDER_FILE}")
+ set_target_properties(clang PROPERTIES LINK_DEPENDS ${CLANG_ORDER_FILE})
endif()
if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index d98ba6e..388a769 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -30,10 +30,10 @@
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -125,6 +125,7 @@
unsigned RelaxAll : 1;
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
+ unsigned IncrementalLinkerCompatible : 1;
/// The name of the relocation model to use.
std::string RelocationModel;
@@ -144,6 +145,7 @@
RelaxAll = 0;
NoExecStack = 0;
FatalWarnings = 0;
+ IncrementalLinkerCompatible = 0;
DwarfVersion = 0;
}
@@ -248,6 +250,8 @@
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.IncrementalLinkerCompatible =
+ Args.hasArg(OPT_mincremental_linker_compatible);
return Success;
}
@@ -394,9 +398,10 @@
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
Opts.CPU);
Triple T(Opts.Triple);
- Str.reset(TheTarget->createMCObjectStreamer(T, Ctx, *MAB, *Out, CE, *STI,
- Opts.RelaxAll,
- /*DWARFMustBeAtTheEnd*/ true));
+ Str.reset(TheTarget->createMCObjectStreamer(
+ T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll,
+ Opts.IncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 00ba309..1a677ea 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -292,9 +292,9 @@
if (CanonicalPrefixes)
llvm::sys::fs::make_absolute(InstalledPath);
- InstalledPath = llvm::sys::path::parent_path(InstalledPath);
- if (llvm::sys::fs::exists(InstalledPath.c_str()))
- TheDriver.setInstalledDir(InstalledPath);
+ StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
+ if (llvm::sys::fs::exists(InstalledPathParent))
+ TheDriver.setInstalledDir(InstalledPathParent);
}
static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 5fa2566..79c7b62 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -664,6 +664,13 @@
llvm_unreachable("Translation units are visited directly by Visit()");
}
+bool CursorVisitor::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ return Visit(MakeCXCursor(D->getTemplatedDecl(), TU, RegionOfInterest));
+}
+
bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
@@ -710,11 +717,8 @@
return true;
}
}
-
- if (ShouldVisitBody && VisitCXXRecordDecl(D))
- return true;
-
- return false;
+
+ return ShouldVisitBody && VisitCXXRecordDecl(D);
}
bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
@@ -939,11 +943,8 @@
return true;
}
- if (ND->isThisDeclarationADefinition() &&
- Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
- return true;
-
- return false;
+ return ND->isThisDeclarationADefinition() &&
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest));
}
template <typename DeclIt>
@@ -1076,7 +1077,8 @@
IdentifierInfo *PropertyId = PD->getIdentifier();
ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId);
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId,
+ PD->getQueryKind());
if (!prevDecl)
return false;
@@ -1685,6 +1687,10 @@
return Visit(TL.getValueLoc());
}
+bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ return Visit(TL.getValueLoc());
+}
+
#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \
bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
return Visit##PARENT##Loc(TL); \
@@ -1748,13 +1754,27 @@
DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind)
DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind)
DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
-DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
- ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
#undef DEF_JOB
+class ExplicitTemplateArgsVisit : public VisitorJob {
+public:
+ ExplicitTemplateArgsVisit(const TemplateArgumentLoc *Begin,
+ const TemplateArgumentLoc *End, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::ExplicitTemplateArgsVisitKind, Begin,
+ End) {}
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == ExplicitTemplateArgsVisitKind;
+ }
+ const TemplateArgumentLoc *begin() const {
+ return static_cast<const TemplateArgumentLoc *>(data[0]);
+ }
+ const TemplateArgumentLoc *end() {
+ return static_cast<const TemplateArgumentLoc *>(data[1]);
+ }
+};
class DeclVisit : public VisitorJob {
public:
DeclVisit(const Decl *D, CXCursor parent, bool isFirst) :
@@ -1935,11 +1955,15 @@
void VisitOMPTargetDirective(const OMPTargetDirective *D);
void VisitOMPTargetDataDirective(const OMPTargetDataDirective *D);
void VisitOMPTeamsDirective(const OMPTeamsDirective *D);
+ void VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D);
+ void VisitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective *D);
+ void VisitOMPDistributeDirective(const OMPDistributeDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
- void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A);
+ void AddExplicitTemplateArgs(const TemplateArgumentLoc *A,
+ unsigned NumTemplateArgs);
void AddMemberRef(const FieldDecl *D, SourceLocation L);
void AddStmt(const Stmt *S);
void AddDecl(const Decl *D, bool isFirst = true);
@@ -1969,10 +1993,9 @@
if (D)
WL.push_back(DeclVisit(D, Parent, isFirst));
}
-void EnqueueVisitor::
- AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) {
- if (A)
- WL.push_back(ExplicitTemplateArgsVisit(A, Parent));
+void EnqueueVisitor::AddExplicitTemplateArgs(const TemplateArgumentLoc *A,
+ unsigned NumTemplateArgs) {
+ WL.push_back(ExplicitTemplateArgsVisit(A, A + NumTemplateArgs, Parent));
}
void EnqueueVisitor::AddMemberRef(const FieldDecl *D, SourceLocation L) {
if (D)
@@ -2064,10 +2087,36 @@
void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {}
+void OMPClauseEnqueue::VisitOMPNogroupClause(const OMPNogroupClause *) {}
+
void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Visitor->AddStmt(C->getDevice());
}
+void OMPClauseEnqueue::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
+ Visitor->AddStmt(C->getNumTeams());
+}
+
+void OMPClauseEnqueue::VisitOMPThreadLimitClause(const OMPThreadLimitClause *C) {
+ Visitor->AddStmt(C->getThreadLimit());
+}
+
+void OMPClauseEnqueue::VisitOMPPriorityClause(const OMPPriorityClause *C) {
+ Visitor->AddStmt(C->getPriority());
+}
+
+void OMPClauseEnqueue::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) {
+ Visitor->AddStmt(C->getGrainsize());
+}
+
+void OMPClauseEnqueue::VisitOMPNumTasksClause(const OMPNumTasksClause *C) {
+ Visitor->AddStmt(C->getNumTasks());
+}
+
+void OMPClauseEnqueue::VisitOMPHintClause(const OMPHintClause *C) {
+ Visitor->AddStmt(C->getHint());
+}
+
template<typename T>
void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
for (const auto *I : Node->varlists()) {
@@ -2171,6 +2220,14 @@
void OMPClauseEnqueue::VisitOMPDependClause(const OMPDependClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseEnqueue::VisitOMPMapClause(const OMPMapClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseEnqueue::VisitOMPDistScheduleClause(
+ const OMPDistScheduleClause *C) {
+ Visitor->AddStmt(C->getChunkSize());
+ Visitor->AddStmt(C->getHelperChunkSize());
+}
}
void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {
@@ -2208,7 +2265,8 @@
void EnqueueVisitor::
VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) {
- AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ if (E->hasExplicitTemplateArgs())
+ AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs());
AddDeclarationNameInfo(E);
if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
AddNestedNameSpecifierLoc(QualifierLoc);
@@ -2283,14 +2341,14 @@
}
void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) {
- if (DR->hasExplicitTemplateArgs()) {
- AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
- }
+ if (DR->hasExplicitTemplateArgs())
+ AddExplicitTemplateArgs(DR->getTemplateArgs(), DR->getNumTemplateArgs());
WL.push_back(DeclRefExprParts(DR, Parent));
}
void EnqueueVisitor::VisitDependentScopeDeclRefExpr(
const DependentScopeDeclRefExpr *E) {
- AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ if (E->hasExplicitTemplateArgs())
+ AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs());
AddDeclarationNameInfo(E);
AddNestedNameSpecifierLoc(E->getQualifierLoc());
}
@@ -2386,7 +2444,6 @@
void EnqueueVisitor::VisitOffsetOfExpr(const OffsetOfExpr *E) {
// Visit the components of the offsetof expression.
for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) {
- typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
const OffsetOfNode &Node = E->getComponent(I-1);
switch (Node.getKind()) {
case OffsetOfNode::Array:
@@ -2404,7 +2461,8 @@
AddTypeLoc(E->getTypeSourceInfo());
}
void EnqueueVisitor::VisitOverloadExpr(const OverloadExpr *E) {
- AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ if (E->hasExplicitTemplateArgs())
+ AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs());
WL.push_back(OverloadExprParts(E, Parent));
}
void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr(
@@ -2589,6 +2647,20 @@
VisitOMPExecutableDirective(D);
}
+void EnqueueVisitor::VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTaskLoopSimdDirective(
+ const OMPTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPDistributeDirective(
+ const OMPDistributeDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -2624,12 +2696,9 @@
continue;
}
case VisitorJob::ExplicitTemplateArgsVisitKind: {
- const ASTTemplateArgumentListInfo *ArgList =
- cast<ExplicitTemplateArgsVisit>(&LI)->get();
- for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(),
- *ArgEnd = Arg + ArgList->NumTemplateArgs;
- Arg != ArgEnd; ++Arg) {
- if (VisitTemplateArgumentLoc(*Arg))
+ for (const TemplateArgumentLoc &Arg :
+ *cast<ExplicitTemplateArgsVisit>(&LI)) {
+ if (VisitTemplateArgumentLoc(Arg))
return true;
}
continue;
@@ -2831,10 +2900,9 @@
namespace {
typedef SmallVector<SourceRange, 4> RefNamePieces;
-RefNamePieces
-buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
- const DeclarationNameInfo &NI, SourceRange QLoc,
- const ASTTemplateArgumentListInfo *TemplateArgs = nullptr) {
+RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
+ const DeclarationNameInfo &NI, SourceRange QLoc,
+ const SourceRange *TemplateArgsLoc = nullptr) {
const bool WantQualifier = NameFlags & CXNameRange_WantQualifier;
const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs;
const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece;
@@ -2848,11 +2916,10 @@
if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr)
Pieces.push_back(NI.getLoc());
-
- if (WantTemplateArgs && TemplateArgs)
- Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc,
- TemplateArgs->RAngleLoc));
-
+
+ if (WantTemplateArgs && TemplateArgsLoc && TemplateArgsLoc->isValid())
+ Pieces.push_back(*TemplateArgsLoc);
+
if (Kind == DeclarationName::CXXOperatorName) {
Pieces.push_back(SourceLocation::getFromRawEncoding(
NI.getInfo().CXXOperatorName.BeginOpNameLoc));
@@ -3030,6 +3097,8 @@
setThreadBackgroundPriority();
bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
+ bool CreatePreambleOnFirstParse =
+ options & CXTranslationUnit_CreatePreambleOnFirstParse;
// FIXME: Add a flag for modules.
TranslationUnitKind TUKind
= (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
@@ -3082,12 +3151,12 @@
break;
}
}
- if (!FoundSpellCheckingArgument)
- Args->push_back("-fno-spell-checking");
-
Args->insert(Args->end(), command_line_args,
command_line_args + num_command_line_args);
+ if (!FoundSpellCheckingArgument)
+ Args->insert(Args->begin() + 1, "-fno-spell-checking");
+
// The 'source_filename' argument is optional. If the caller does not
// specify it then it is assumed that the source file is specified
// in the actual argument list.
@@ -3104,13 +3173,18 @@
unsigned NumErrors = Diags->getClient()->getNumErrors();
std::unique_ptr<ASTUnit> ErrUnit;
+ // Unless the user specified that they want the preamble on the first parse
+ // set it up to be created on the first reparse. This makes the first parse
+ // faster, trading for a slower (first) reparse.
+ unsigned PrecompilePreambleAfterNParses =
+ !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine(
Args->data(), Args->data() + Args->size(),
CXXIdx->getPCHContainerOperations(), Diags,
CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(),
/*CaptureDiagnostics=*/true, *RemappedFiles.get(),
- /*RemappedFilesKeepOriginalName=*/true, PrecompilePreamble, TUKind,
- CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion,
+ /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses,
+ TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion,
/*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies,
/*UserFilesAreVolatile=*/true, ForSerialization,
CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(),
@@ -3152,14 +3226,23 @@
}
enum CXErrorCode clang_parseTranslationUnit2(
- CXIndex CIdx,
- const char *source_filename,
- const char *const *command_line_args,
- int num_command_line_args,
- struct CXUnsavedFile *unsaved_files,
- unsigned num_unsaved_files,
- unsigned options,
- CXTranslationUnit *out_TU) {
+ CXIndex CIdx, const char *source_filename,
+ const char *const *command_line_args, int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
+ unsigned options, CXTranslationUnit *out_TU) {
+ SmallVector<const char *, 4> Args;
+ Args.push_back("clang");
+ Args.append(command_line_args, command_line_args + num_command_line_args);
+ return clang_parseTranslationUnit2FullArgv(
+ CIdx, source_filename, Args.data(), Args.size(), unsaved_files,
+ num_unsaved_files, options, out_TU);
+}
+
+enum CXErrorCode clang_parseTranslationUnit2FullArgv(
+ CXIndex CIdx, const char *source_filename,
+ const char *const *command_line_args, int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
+ unsigned options, CXTranslationUnit *out_TU) {
LOG_FUNC_SECTION {
*Log << source_filename << ": ";
for (int i = 0; i != num_command_line_args; ++i)
@@ -3207,6 +3290,329 @@
return result;
}
+CXString clang_Type_getObjCEncoding(CXType CT) {
+ CXTranslationUnit tu = static_cast<CXTranslationUnit>(CT.data[1]);
+ ASTContext &Ctx = getASTUnit(tu)->getASTContext();
+ std::string encoding;
+ Ctx.getObjCEncodingForType(QualType::getFromOpaquePtr(CT.data[0]),
+ encoding);
+
+ return cxstring::createDup(encoding);
+}
+
+static const IdentifierInfo *getMacroIdentifier(CXCursor C) {
+ if (C.kind == CXCursor_MacroDefinition) {
+ if (const MacroDefinitionRecord *MDR = getCursorMacroDefinition(C))
+ return MDR->getName();
+ } else if (C.kind == CXCursor_MacroExpansion) {
+ MacroExpansionCursor ME = getCursorMacroExpansion(C);
+ return ME.getName();
+ }
+ return nullptr;
+}
+
+unsigned clang_Cursor_isMacroFunctionLike(CXCursor C) {
+ const IdentifierInfo *II = getMacroIdentifier(C);
+ if (!II) {
+ return false;
+ }
+ ASTUnit *ASTU = getCursorASTUnit(C);
+ Preprocessor &PP = ASTU->getPreprocessor();
+ if (const MacroInfo *MI = PP.getMacroInfo(II))
+ return MI->isFunctionLike();
+ return false;
+}
+
+unsigned clang_Cursor_isMacroBuiltin(CXCursor C) {
+ const IdentifierInfo *II = getMacroIdentifier(C);
+ if (!II) {
+ return false;
+ }
+ ASTUnit *ASTU = getCursorASTUnit(C);
+ Preprocessor &PP = ASTU->getPreprocessor();
+ if (const MacroInfo *MI = PP.getMacroInfo(II))
+ return MI->isBuiltinMacro();
+ return false;
+}
+
+unsigned clang_Cursor_isFunctionInlined(CXCursor C) {
+ const Decl *D = getCursorDecl(C);
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (!FD) {
+ return false;
+ }
+ return FD->isInlined();
+}
+
+static StringLiteral* getCFSTR_value(CallExpr *callExpr) {
+ if (callExpr->getNumArgs() != 1) {
+ return nullptr;
+ }
+
+ StringLiteral *S = nullptr;
+ auto *arg = callExpr->getArg(0);
+ if (arg->getStmtClass() == Stmt::ImplicitCastExprClass) {
+ ImplicitCastExpr *I = static_cast<ImplicitCastExpr *>(arg);
+ auto *subExpr = I->getSubExprAsWritten();
+
+ if(subExpr->getStmtClass() != Stmt::StringLiteralClass){
+ return nullptr;
+ }
+
+ S = static_cast<StringLiteral *>(I->getSubExprAsWritten());
+ } else if (arg->getStmtClass() == Stmt::StringLiteralClass) {
+ S = static_cast<StringLiteral *>(callExpr->getArg(0));
+ } else {
+ return nullptr;
+ }
+ return S;
+}
+
+typedef struct {
+ CXEvalResultKind EvalType;
+ union {
+ int intVal;
+ double floatVal;
+ char *stringVal;
+ } EvalData;
+} ExprEvalResult;
+
+void clang_EvalResult_dispose(CXEvalResult E) {
+ ExprEvalResult *ER = (ExprEvalResult *)E;
+ if (ER) {
+ CXEvalResultKind evalType = ER->EvalType;
+
+ if (evalType != CXEval_UnExposed && evalType != CXEval_Float &&
+ evalType != CXEval_Int && ER->EvalData.stringVal) {
+ free((void *) ER->EvalData.stringVal);
+ }
+ free((void *)ER);
+ }
+}
+
+CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E) {
+ if (!E) {
+ return CXEval_UnExposed;
+ }
+ return ((ExprEvalResult *)E)->EvalType;
+}
+
+int clang_EvalResult_getAsInt(CXEvalResult E) {
+ if (!E) {
+ return 0;
+ }
+ return ((ExprEvalResult *)E)->EvalData.intVal;
+}
+
+double clang_EvalResult_getAsDouble(CXEvalResult E) {
+ if (!E) {
+ return 0;
+ }
+ return ((ExprEvalResult *)E)->EvalData.floatVal;
+}
+
+const char* clang_EvalResult_getAsStr(CXEvalResult E) {
+ if (!E) {
+ return nullptr;
+ }
+ return ((ExprEvalResult *)E)->EvalData.stringVal;
+}
+
+static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) {
+ Expr::EvalResult ER;
+ ASTContext &ctx = getCursorContext(C);
+ if (!expr) {
+ return nullptr;
+ }
+ expr = expr->IgnoreParens();
+ bool res = expr->EvaluateAsRValue(ER, ctx);
+ QualType rettype;
+ CallExpr *callExpr;
+ ExprEvalResult *result = (ExprEvalResult *) malloc(sizeof(ExprEvalResult));
+ if (!result) {
+ return nullptr;
+ }
+ result->EvalType = CXEval_UnExposed;
+
+ if (res) {
+
+ if (ER.Val.isInt()) {
+ result->EvalType = CXEval_Int;
+ result->EvalData.intVal = ER.Val.getInt().getExtValue();
+ return result;
+ } else if (ER.Val.isFloat()) {
+
+ llvm::SmallVector<char, 100> Buffer;
+ ER.Val.getFloat().toString(Buffer);
+ std::string floatStr(Buffer.data(), Buffer.size());
+ result->EvalType = CXEval_Float;
+ bool ignored;
+ llvm::APFloat apFloat = ER.Val.getFloat();
+ apFloat.convert(llvm::APFloat::IEEEdouble,
+ llvm::APFloat::rmNearestTiesToEven, &ignored);
+ result->EvalData.floatVal = apFloat.convertToDouble();
+ return result;
+
+ } else if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
+
+ const ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(expr);
+ auto *subExpr = I->getSubExprAsWritten();
+ if (subExpr->getStmtClass() == Stmt::StringLiteralClass ||
+ subExpr->getStmtClass() == Stmt::ObjCStringLiteralClass) {
+
+ const StringLiteral *StrE = nullptr;
+ const ObjCStringLiteral *ObjCExpr;
+ ObjCExpr = dyn_cast<ObjCStringLiteral>(subExpr);
+
+ if (ObjCExpr) {
+ StrE = ObjCExpr->getString();
+ result->EvalType = CXEval_ObjCStrLiteral;
+ } else {
+ StrE = cast<StringLiteral>(I->getSubExprAsWritten());
+ result->EvalType = CXEval_StrLiteral;
+ }
+
+ std::string strRef(StrE->getString().str());
+ result->EvalData.stringVal = (char *)malloc(strRef.size()+1);
+ strncpy((char*)result->EvalData.stringVal, strRef.c_str(),
+ strRef.size());
+ result->EvalData.stringVal[strRef.size()] = '\0';
+ return result;
+ }
+
+ } else if (expr->getStmtClass() == Stmt::ObjCStringLiteralClass ||
+ expr->getStmtClass() == Stmt::StringLiteralClass) {
+
+ const StringLiteral *StrE = nullptr;
+ const ObjCStringLiteral *ObjCExpr;
+ ObjCExpr = dyn_cast<ObjCStringLiteral>(expr);
+
+ if (ObjCExpr) {
+ StrE = ObjCExpr->getString();
+ result->EvalType = CXEval_ObjCStrLiteral;
+ } else {
+ StrE = cast<StringLiteral>(expr);
+ result->EvalType = CXEval_StrLiteral;
+ }
+
+ std::string strRef(StrE->getString().str());
+ result->EvalData.stringVal = (char *)malloc(strRef.size()+1);
+ strncpy((char*)result->EvalData.stringVal, strRef.c_str(),
+ strRef.size());
+ result->EvalData.stringVal[strRef.size()] = '\0';
+ return result;
+
+ } else if (expr->getStmtClass() == Stmt::CStyleCastExprClass) {
+
+ CStyleCastExpr *CC = static_cast<CStyleCastExpr *>(expr);
+
+ rettype = CC->getType();
+ if (rettype.getAsString() == "CFStringRef" &&
+ CC->getSubExpr()->getStmtClass() == Stmt::CallExprClass) {
+
+ callExpr = static_cast<CallExpr *>(CC->getSubExpr());
+ StringLiteral* S = getCFSTR_value(callExpr);
+ if (S) {
+ std::string strLiteral(S->getString().str());
+ result->EvalType = CXEval_CFStr;
+
+ result->EvalData.stringVal = (char *)malloc(strLiteral.size()+1);
+ strncpy((char*)result->EvalData.stringVal, strLiteral.c_str(),
+ strLiteral.size());
+ result->EvalData.stringVal[strLiteral.size()] = '\0';
+ return result;
+ }
+ }
+
+ } else if (expr->getStmtClass() == Stmt::CallExprClass) {
+
+ callExpr = static_cast<CallExpr *>(expr);
+ rettype = callExpr->getCallReturnType(ctx);
+
+ if (rettype->isVectorType() || callExpr->getNumArgs() > 1) {
+ return nullptr;
+ }
+ if (rettype->isIntegralType(ctx) || rettype->isRealFloatingType()) {
+ if(callExpr->getNumArgs() == 1 &&
+ !callExpr->getArg(0)->getType()->isIntegralType(ctx)){
+
+ return nullptr;
+ }
+ } else if(rettype.getAsString() == "CFStringRef") {
+
+ StringLiteral* S = getCFSTR_value(callExpr);
+ if (S) {
+ std::string strLiteral(S->getString().str());
+ result->EvalType = CXEval_CFStr;
+ result->EvalData.stringVal = (char *)malloc(strLiteral.size()+1);
+ strncpy((char*)result->EvalData.stringVal, strLiteral.c_str(),
+ strLiteral.size());
+ result->EvalData.stringVal[strLiteral.size()] = '\0';
+ return result;
+ }
+ }
+
+ } else if (expr->getStmtClass() == Stmt::DeclRefExprClass) {
+
+ DeclRefExpr *D = static_cast<DeclRefExpr *>(expr);
+ ValueDecl *V = D->getDecl();
+ if (V->getKind() == Decl::Function) {
+ std::string strName(V->getNameAsString());
+ result->EvalType = CXEval_Other;
+ result->EvalData.stringVal = (char *)malloc(strName.size()+1);
+ strncpy((char*)result->EvalData.stringVal, strName.c_str(),
+ strName.size());
+ result->EvalData.stringVal[strName.size()] = '\0';
+ return result;
+ }
+ }
+
+ }
+
+ clang_EvalResult_dispose((CXEvalResult *)result);
+ return nullptr;
+}
+
+CXEvalResult clang_Cursor_Evaluate(CXCursor C) {
+ const Decl *D = getCursorDecl(C);
+ if (D) {
+ const Expr *expr = nullptr;
+ if (auto *Var = dyn_cast<VarDecl>(D)) {
+ expr = Var->getInit();
+ } else if (auto *Field = dyn_cast<FieldDecl>(D)) {
+ expr = Field->getInClassInitializer();
+ }
+ if (expr)
+ return (CXEvalResult)evaluateExpr((Expr *)expr, C);
+ return nullptr;
+ }
+
+ const CompoundStmt *compoundStmt = dyn_cast_or_null<CompoundStmt>(getCursorStmt(C));
+ if (compoundStmt) {
+ Expr *expr = nullptr;
+ for (auto *bodyIterator : compoundStmt->body()) {
+ if ((expr = dyn_cast<Expr>(bodyIterator))) {
+ break;
+ }
+ }
+ if (expr)
+ return (CXEvalResult)evaluateExpr(expr, C);
+ }
+ return nullptr;
+}
+
+unsigned clang_Cursor_hasAttrs(CXCursor C) {
+ const Decl *D = getCursorDecl(C);
+ if (!D) {
+ return 0;
+ }
+
+ if (D->hasAttrs()) {
+ return 1;
+ }
+
+ return 0;
+}
unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
return CXSaveTranslationUnit_None;
}
@@ -3540,6 +3946,26 @@
return E->getLocStart();
}
+static std::string getMangledStructor(std::unique_ptr<MangleContext> &M,
+ std::unique_ptr<llvm::DataLayout> &DL,
+ const NamedDecl *ND,
+ unsigned StructorType) {
+ std::string FrontendBuf;
+ llvm::raw_string_ostream FOS(FrontendBuf);
+
+ if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND))
+ M->mangleCXXCtor(CD, static_cast<CXXCtorType>(StructorType), FOS);
+ else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND))
+ M->mangleCXXDtor(DD, static_cast<CXXDtorType>(StructorType), FOS);
+
+ std::string BackendBuf;
+ llvm::raw_string_ostream BOS(BackendBuf);
+
+ llvm::Mangler::getNameWithPrefix(BOS, llvm::Twine(FOS.str()), *DL);
+
+ return BOS.str();
+}
+
extern "C" {
unsigned clang_visitChildren(CXCursor parent,
@@ -3913,6 +4339,54 @@
return cxstring::createDup(FinalBufOS.str());
}
+CXStringSet *clang_Cursor_getCXXManglings(CXCursor C) {
+ if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind))
+ return nullptr;
+
+ const Decl *D = getCursorDecl(C);
+ if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D)))
+ return nullptr;
+
+ const NamedDecl *ND = cast<NamedDecl>(D);
+
+ ASTContext &Ctx = ND->getASTContext();
+ std::unique_ptr<MangleContext> M(Ctx.createMangleContext());
+ std::unique_ptr<llvm::DataLayout> DL(
+ new llvm::DataLayout(Ctx.getTargetInfo().getDataLayoutString()));
+
+ std::vector<std::string> Manglings;
+
+ auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) {
+ auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false,
+ /*IsCSSMethod=*/true);
+ auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ return CC == DefaultCC;
+ };
+
+ if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) {
+ Manglings.emplace_back(getMangledStructor(M, DL, CD, Ctor_Base));
+
+ if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily())
+ if (!CD->getParent()->isAbstract())
+ Manglings.emplace_back(getMangledStructor(M, DL, CD, Ctor_Complete));
+
+ if (Ctx.getTargetInfo().getCXXABI().isMicrosoft())
+ if (CD->hasAttr<DLLExportAttr>() && CD->isDefaultConstructor())
+ if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0))
+ Manglings.emplace_back(getMangledStructor(M, DL, CD,
+ Ctor_DefaultClosure));
+ } else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) {
+ Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Base));
+ if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) {
+ Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Complete));
+ if (DD->isVirtual())
+ Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Deleting));
+ }
+ }
+
+ return cxstring::createSet(Manglings);
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -4269,6 +4743,10 @@
return cxstring::createRef("attribute(shared)");
case CXCursor_VisibilityAttr:
return cxstring::createRef("attribute(visibility)");
+ case CXCursor_DLLExport:
+ return cxstring::createRef("attribute(dllexport)");
+ case CXCursor_DLLImport:
+ return cxstring::createRef("attribute(dllimport)");
case CXCursor_PreprocessingDirective:
return cxstring::createRef("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -4367,8 +4845,16 @@
return cxstring::createRef("OMPCancellationPointDirective");
case CXCursor_OMPCancelDirective:
return cxstring::createRef("OMPCancelDirective");
+ case CXCursor_OMPTaskLoopDirective:
+ return cxstring::createRef("OMPTaskLoopDirective");
+ case CXCursor_OMPTaskLoopSimdDirective:
+ return cxstring::createRef("OMPTaskLoopSimdDirective");
+ case CXCursor_OMPDistributeDirective:
+ return cxstring::createRef("OMPDistributeDirective");
case CXCursor_OverloadCandidate:
return cxstring::createRef("OverloadCandidate");
+ case CXCursor_TypeAliasTemplateDecl:
+ return cxstring::createRef("TypeAliasTemplateDecl");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -5375,10 +5861,12 @@
break;
case CXCursor_DeclRefExpr:
- if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
- Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
- E->getQualifierLoc().getSourceRange(),
- E->getOptionalExplicitTemplateArgs());
+ if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) {
+ SourceRange TemplateArgLoc(E->getLAngleLoc(), E->getRAngleLoc());
+ Pieces =
+ buildPieces(NameFlags, false, E->getNameInfo(),
+ E->getQualifierLoc().getSourceRange(), &TemplateArgLoc);
+ }
break;
case CXCursor_CallExpr:
@@ -6077,10 +6565,7 @@
++NextIdx;
Lex.LexFromRawLexer(Tok);
- if (Tok.is(tok::eof))
- return true;
-
- return false;
+ return Tok.is(tok::eof);
}
static void annotatePreprocessorTokens(CXTranslationUnit TU,
@@ -6361,6 +6846,27 @@
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Operations for querying visibility of a cursor.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) {
+ if (!clang_isDeclaration(cursor.kind))
+ return CXVisibility_Invalid;
+
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
+ switch (ND->getVisibility()) {
+ case HiddenVisibility: return CXVisibility_Hidden;
+ case ProtectedVisibility: return CXVisibility_Protected;
+ case DefaultVisibility: return CXVisibility_Default;
+ };
+
+ return CXVisibility_Invalid;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// Operations for querying language of a cursor.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
index 365609b..0959374 100644
--- a/tools/libclang/CIndexInclusionStack.cpp
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -21,6 +21,55 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+static void getInclusions(const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const, unsigned n,
+ CXTranslationUnit TU, CXInclusionVisitor CB,
+ CXClientData clientData)
+{
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ SourceManager &SM = CXXUnit->getSourceManager();
+ ASTContext &Ctx = CXXUnit->getASTContext();
+ SmallVector<CXSourceLocation, 10> InclusionStack;
+ const bool HasPreamble = SM.getPreambleFileID().isValid();
+
+ for (unsigned i = 0 ; i < n ; ++i) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid);
+
+ if (!SL.isFile() || Invalid)
+ continue;
+
+ const SrcMgr::FileInfo &FI = SL.getFile();
+ if (!FI.getContentCache()->OrigEntry)
+ continue;
+
+ // If this is the main file, and there is a preamble, skip this SLoc. The
+ // inclusions of the preamble already showed it.
+ SourceLocation L = FI.getIncludeLoc();
+ if (HasPreamble && CXXUnit->isInMainFileID(L))
+ continue;
+
+ // Build the inclusion stack.
+ InclusionStack.clear();
+ while (L.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(L);
+ InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L));
+ L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation();
+ }
+
+ // If there is a preamble, the last entry is the "inclusion" of that
+ // preamble into the main file, which has the bogus entry of main.c:1:1
+ if (HasPreamble && !InclusionStack.empty())
+ InclusionStack.pop_back();
+
+ // Callback to the client.
+ // FIXME: We should have a function to construct CXFiles.
+ CB(static_cast<CXFile>(
+ const_cast<FileEntry *>(FI.getContentCache()->OrigEntry)),
+ InclusionStack.data(), InclusionStack.size(), clientData);
+ }
+}
+
+
extern "C" {
void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
CXClientData clientData) {
@@ -29,48 +78,24 @@
return;
}
- ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
- SourceManager &SM = CXXUnit->getSourceManager();
- ASTContext &Ctx = CXXUnit->getASTContext();
-
- SmallVector<CXSourceLocation, 10> InclusionStack;
- unsigned n = SM.local_sloc_entry_size();
+ SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
+ const unsigned n = SM.local_sloc_entry_size();
// In the case where all the SLocEntries are in an external source, traverse
// those SLocEntries as well. This is the case where we are looking
- // at the inclusion stack of an AST/PCH file.
- const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const;
- if (n == 1) {
- Getter = &SourceManager::getLoadedSLocEntry;
- n = SM.loaded_sloc_entry_size();
- } else
- Getter = &SourceManager::getLocalSLocEntry;
+ // at the inclusion stack of an AST/PCH file. Also, if we are not looking at
+ // a AST/PCH file, but this file has a pre-compiled preamble, we also need
+ // to look in that file.
+ if (n == 1 || SM.getPreambleFileID().isValid()) {
+ getInclusions(&SourceManager::getLoadedSLocEntry,
+ SM.loaded_sloc_entry_size(), TU, CB, clientData);
+ }
- for (unsigned i = 0 ; i < n ; ++i) {
- bool Invalid = false;
- const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid);
-
- if (!SL.isFile() || Invalid)
- continue;
+ // Not a PCH/AST file. Note, if there is a preamble, it could still be that
+ // there are #includes in this file (e.g. for any include after the first
+ // declaration).
+ if (n != 1)
+ getInclusions(&SourceManager::getLocalSLocEntry, n, TU, CB, clientData);
- const SrcMgr::FileInfo &FI = SL.getFile();
- if (!FI.getContentCache()->OrigEntry)
- continue;
-
- // Build the inclusion stack.
- SourceLocation L = FI.getIncludeLoc();
- InclusionStack.clear();
- while (L.isValid()) {
- PresumedLoc PLoc = SM.getPresumedLoc(L);
- InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L));
- L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation();
- }
-
- // Callback to the client.
- // FIXME: We should have a function to construct CXFiles.
- CB(static_cast<CXFile>(
- const_cast<FileEntry *>(FI.getContentCache()->OrigEntry)),
- InclusionStack.data(), InclusionStack.size(), clientData);
- }
}
} // end extern C
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index bd8368a..56d0534 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -116,3 +116,25 @@
DEFINE_SYMBOL _CINDEX_LIB_)
endif()
endif()
+
+if(INTERNAL_INSTALL_PREFIX)
+ set(LIBCLANG_HEADERS_INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/include")
+else()
+ set(LIBCLANG_HEADERS_INSTALL_DESTINATION include)
+endif()
+
+install(DIRECTORY ../../include/clang-c
+ COMPONENT libclang-headers
+ DESTINATION "${LIBCLANG_HEADERS_INSTALL_DESTINATION}"
+ FILES_MATCHING
+ PATTERN "*.h"
+ PATTERN ".svn" EXCLUDE
+ )
+
+if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's.
+ add_custom_target(install-libclang-headers
+ DEPENDS
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=libclang-headers
+ -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+endif()
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 0e47bf9..c766d2d 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -59,6 +59,8 @@
case attr::CUDAHost: return CXCursor_CUDAHostAttr;
case attr::CUDAShared: return CXCursor_CUDASharedAttr;
case attr::Visibility: return CXCursor_VisibilityAttr;
+ case attr::DLLExport: return CXCursor_DLLExport;
+ case attr::DLLImport: return CXCursor_DLLImport;
}
return CXCursor_UnexposedAttr;
@@ -329,6 +331,7 @@
K = CXCursor_UnaryExpr;
break;
+ case Stmt::MSPropertySubscriptExprClass:
case Stmt::ArraySubscriptExprClass:
K = CXCursor_ArraySubscriptExpr;
break;
@@ -606,6 +609,15 @@
case Stmt::OMPCancelDirectiveClass:
K = CXCursor_OMPCancelDirective;
break;
+ case Stmt::OMPTaskLoopDirectiveClass:
+ K = CXCursor_OMPTaskLoopDirective;
+ break;
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ K = CXCursor_OMPTaskLoopSimdDirective;
+ break;
+ case Stmt::OMPDistributeDirectiveClass:
+ K = CXCursor_OMPDistributeDirective;
+ break;
}
CXCursor C = { K, 0, { Parent, S, TU } };
diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp
index dec8ebc..1ccbed3 100644
--- a/tools/libclang/CXString.cpp
+++ b/tools/libclang/CXString.cpp
@@ -112,6 +112,15 @@
return Str;
}
+CXStringSet *createSet(const std::vector<std::string> &Strings) {
+ CXStringSet *Set = new CXStringSet;
+ Set->Count = Strings.size();
+ Set->Strings = new CXString[Set->Count];
+ for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI)
+ Set->Strings[SI] = createDup(Strings[SI]);
+ return Set;
+}
+
//===----------------------------------------------------------------------===//
// String pools.
@@ -175,5 +184,13 @@
break;
}
}
+
+void clang_disposeStringSet(CXStringSet *set) {
+ for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
+ clang_disposeString(set->Strings[SI]);
+ delete[] set->Strings;
+ delete set;
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index 72ac0cf..6473eb2 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -68,6 +68,8 @@
/// \brief Create a CXString object that is backed by a string buffer.
CXString createCXString(CXStringBuf *buf);
+CXStringSet *createSet(const std::vector<std::string> &Strings);
+
/// \brief A string pool used for fast allocation/deallocation of strings.
class CXStringPool {
public:
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 066b49a..44bb631 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -90,6 +90,7 @@
TKCASE(DependentSizedArray);
TKCASE(Vector);
TKCASE(MemberPointer);
+ TKCASE(Auto);
default:
return CXType_Unexposed;
}
@@ -144,7 +145,7 @@
CXType clang_getCursorType(CXCursor C) {
using namespace cxcursor;
-
+
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (!TU)
return MakeCXType(QualType(), TU);
@@ -174,7 +175,7 @@
return MakeCXType(FTD->getTemplatedDecl()->getType(), TU);
return MakeCXType(QualType(), TU);
}
-
+
if (clang_isReference(C.kind)) {
switch (C.kind) {
case CXCursor_ObjCSuperClassRef: {
@@ -182,18 +183,18 @@
= Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first);
return MakeCXType(T, TU);
}
-
+
case CXCursor_ObjCClassRef: {
QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first);
return MakeCXType(T, TU);
}
-
+
case CXCursor_TypeRef: {
QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first);
return MakeCXType(T, TU);
}
-
+
case CXCursor_CXXBaseSpecifier:
return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU);
@@ -210,7 +211,7 @@
default:
break;
}
-
+
return MakeCXType(QualType(), TU);
}
@@ -348,10 +349,10 @@
CXType clang_getPointeeType(CXType CT) {
QualType T = GetQualType(CT);
const Type *TP = T.getTypePtrOrNull();
-
+
if (!TP)
return MakeCXType(QualType(), GetTU(CT));
-
+
switch (TP->getTypeClass()) {
case Type::Pointer:
T = cast<PointerType>(TP)->getPointeeType();
@@ -410,7 +411,13 @@
D = cast<TemplateSpecializationType>(TP)->getTemplateName()
.getAsTemplateDecl();
break;
-
+
+ case Type::Auto:
+ TP = cast<AutoType>(TP)->getDeducedType().getTypePtrOrNull();
+ if (TP)
+ goto try_again;
+ break;
+
case Type::InjectedClassName:
D = cast<InjectedClassNameType>(TP)->getDecl();
break;
@@ -420,7 +427,7 @@
case Type::Elaborated:
TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
goto try_again;
-
+
default:
break;
}
@@ -483,6 +490,7 @@
TKIND(DependentSizedArray);
TKIND(Vector);
TKIND(MemberPointer);
+ TKIND(Auto);
}
#undef TKIND
return cxstring::createRef(s);
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 91f63b4..3e5b0c9 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -195,6 +195,7 @@
bool VisitChildren(CXCursor Parent);
// Declaration visitors
+ bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
bool VisitTypeAliasDecl(TypeAliasDecl *D);
bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B);
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index 5539971..64df4b8 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -8,19 +8,19 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-#include "clang/AST/DataRecursiveASTVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
using namespace clang;
using namespace cxindex;
namespace {
-class BodyIndexer : public DataRecursiveASTVisitor<BodyIndexer> {
+class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
IndexingContext &IndexCtx;
const NamedDecl *Parent;
const DeclContext *ParentDC;
- typedef DataRecursiveASTVisitor<BodyIndexer> base;
+ typedef RecursiveASTVisitor<BodyIndexer> base;
public:
BodyIndexer(IndexingContext &indexCtx,
const NamedDecl *Parent, const DeclContext *DC)
@@ -125,10 +125,11 @@
return true;
}
- bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,
+ DataRecursionQueue *Q = nullptr) {
if (E->getOperatorLoc().isInvalid())
return true; // implicit.
- return base::TraverseCXXOperatorCallExpr(E);
+ return base::TraverseCXXOperatorCallExpr(E, Q);
}
bool VisitDeclStmt(DeclStmt *S) {
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
index 706870e..9666052 100644
--- a/tools/libclang/IndexTypeSourceInfo.cpp
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -8,14 +8,14 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-#include "clang/AST/DataRecursiveASTVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
using namespace clang;
using namespace cxindex;
namespace {
-class TypeIndexer : public DataRecursiveASTVisitor<TypeIndexer> {
+class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
IndexingContext &IndexCtx;
const NamedDecl *Parent;
const DeclContext *ParentDC;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 2b8daeb..d6e35b0 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -601,6 +601,7 @@
bool Persistent = requestedToGetTU;
bool OnlyLocalDecls = false;
bool PrecompilePreamble = false;
+ bool CreatePreambleOnFirstParse = false;
bool CacheCodeCompletionResults = false;
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
PPOpts.AllowPCHWithCompilerErrors = true;
@@ -608,6 +609,8 @@
if (requestedToGetTU) {
OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
+ CreatePreambleOnFirstParse =
+ TU_options & CXTranslationUnit_CreatePreambleOnFirstParse;
// FIXME: Add a flag for modules.
CacheCodeCompletionResults
= TU_options & CXTranslationUnit_CacheCompletionResults;
@@ -620,11 +623,16 @@
if (!requestedToGetTU && !CInvok->getLangOpts()->Modules)
PPOpts.DetailedRecord = false;
+ // Unless the user specified that they want the preamble on the first parse
+ // set it up to be created on the first reparse. This makes the first parse
+ // faster, trading for a slower (first) reparse.
+ unsigned PrecompilePreambleAfterNParses =
+ !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
DiagnosticErrorTrap DiagTrap(*Diags);
bool Success = ASTUnit::LoadFromCompilerInvocationAction(
CInvok.get(), CXXIdx->getPCHContainerOperations(), Diags,
IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(),
- OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble,
+ OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
CacheCodeCompletionResults,
/*IncludeBriefCommentsInCodeCompletion=*/false,
/*UserFilesAreVolatile=*/true);
@@ -673,9 +681,7 @@
static bool topLevelDeclVisitor(void *context, const Decl *D) {
IndexingContext &IdxCtx = *static_cast<IndexingContext*>(context);
IdxCtx.indexTopLevelDecl(D);
- if (IdxCtx.shouldAbort())
- return false;
- return true;
+ return !IdxCtx.shouldAbort();
}
static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
@@ -911,6 +917,22 @@
unsigned num_unsaved_files,
CXTranslationUnit *out_TU,
unsigned TU_options) {
+ SmallVector<const char *, 4> Args;
+ Args.push_back("clang");
+ Args.append(command_line_args, command_line_args + num_command_line_args);
+ return clang_indexSourceFileFullArgv(
+ idxAction, client_data, index_callbacks, index_callbacks_size,
+ index_options, source_filename, Args.data(), Args.size(), unsaved_files,
+ num_unsaved_files, out_TU, TU_options);
+}
+
+int clang_indexSourceFileFullArgv(
+ CXIndexAction idxAction, CXClientData client_data,
+ IndexerCallbacks *index_callbacks, unsigned index_callbacks_size,
+ unsigned index_options, const char *source_filename,
+ const char *const *command_line_args, int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
+ CXTranslationUnit *out_TU, unsigned TU_options) {
LOG_FUNC_SECTION {
*Log << source_filename << ": ";
for (int i = 0; i != num_command_line_args; ++i)
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index bf6e172..f7640c6 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -804,10 +804,7 @@
RefFileOccurrence RefOccur(FE, D);
std::pair<llvm::DenseSet<RefFileOccurrence>::iterator, bool>
res = RefFileOccurrences.insert(RefOccur);
- if (!res.second)
- return true; // already in map.
-
- return false;
+ return !res.second; // already in map
}
const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const {
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index fd157bc..e2dffe8 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -15,6 +15,7 @@
clang_Cursor_getTemplateArgumentUnsignedValue
clang_Cursor_getBriefCommentText
clang_Cursor_getCommentRange
+clang_Cursor_getCXXManglings
clang_Cursor_getMangling
clang_Cursor_getParsedComment
clang_Cursor_getRawCommentText
@@ -120,6 +121,7 @@
clang_disposeCXPlatformAvailability
clang_disposeSourceRangeList
clang_disposeString
+clang_disposeStringSet
clang_disposeTokens
clang_disposeTranslationUnit
clang_enableStackTraces
@@ -174,6 +176,7 @@
clang_getCursorSpelling
clang_getCursorType
clang_getCursorUSR
+clang_getCursorVisibility
clang_getDeclObjCTypeEncoding
clang_getDefinitionSpellingAndExtent
clang_getDiagnostic
@@ -247,6 +250,7 @@
clang_indexLoc_getCXSourceLocation
clang_indexLoc_getFileLocation
clang_indexSourceFile
+clang_indexSourceFileFullArgv
clang_indexTranslationUnit
clang_index_getCXXClassDeclInfo
clang_index_getClientContainer
@@ -282,6 +286,7 @@
clang_Location_isFromMainFile
clang_parseTranslationUnit
clang_parseTranslationUnit2
+clang_parseTranslationUnit2FullArgv
clang_remap_dispose
clang_remap_getFilenames
clang_remap_getNumFiles
@@ -315,3 +320,14 @@
clang_VirtualFileOverlay_dispose
clang_VirtualFileOverlay_setCaseSensitivity
clang_VirtualFileOverlay_writeToBuffer
+clang_Type_getObjCEncoding
+clang_Cursor_isMacroFunctionLike
+clang_Cursor_isMacroBuiltin
+clang_Cursor_isFunctionInlined
+clang_Cursor_hasAttrs
+clang_Cursor_Evaluate
+clang_EvalResult_getKind
+clang_EvalResult_getAsInt
+clang_EvalResult_getAsDouble
+clang_EvalResult_getAsStr
+clang_EvalResult_dispose
diff --git a/tools/scan-build-py/README.md b/tools/scan-build-py/README.md
new file mode 100644
index 0000000..54bfc37
--- /dev/null
+++ b/tools/scan-build-py/README.md
@@ -0,0 +1,120 @@
+scan-build
+==========
+
+A package designed to wrap a build so that all calls to gcc/clang are
+intercepted and logged into a [compilation database][1] and/or piped to
+the clang static analyzer. Includes intercept-build tool, which logs
+the build, as well as scan-build tool, which logs the build and runs
+the clang static analyzer on it.
+
+Portability
+-----------
+
+Should be working on UNIX operating systems.
+
+- It has been tested on FreeBSD, GNU/Linux and OS X.
+- Prepared to work on windows, but need help to make it.
+
+
+Prerequisites
+-------------
+
+1. **python** interpreter (version 2.7, 3.2, 3.3, 3.4, 3.5).
+
+
+How to use
+----------
+
+To run the Clang static analyzer against a project goes like this:
+
+ $ scan-build <your build command>
+
+To generate a compilation database file goes like this:
+
+ $ intercept-build <your build command>
+
+To run the Clang static analyzer against a project with compilation database
+goes like this:
+
+ $ analyze-build
+
+Use `--help` to know more about the commands.
+
+
+Limitations
+-----------
+
+Generally speaking, the `intercept-build` and `analyze-build` tools together
+does the same job as `scan-build` does. So, you can expect the same output
+from this line as simple `scan-build` would do:
+
+ $ intercept-build <your build command> && analyze-build
+
+The major difference is how and when the analyzer is run. The `scan-build`
+tool has three distinct model to run the analyzer:
+
+1. Use compiler wrappers to make actions.
+ The compiler wrappers does run the real compiler and the analyzer.
+ This is the default behaviour, can be enforced with `--override-compiler`
+ flag.
+
+2. Use special library to intercept compiler calls durring the build process.
+ The analyzer run against each modules after the build finished.
+ Use `--intercept-first` flag to get this model.
+
+3. Use compiler wrappers to intercept compiler calls durring the build process.
+ The analyzer run against each modules after the build finished.
+ Use `--intercept-first` and `--override-compiler` flags together to get
+ this model.
+
+The 1. and 3. are using compiler wrappers, which works only if the build
+process respects the `CC` and `CXX` environment variables. (Some build
+process can override these variable as command line parameter only. This case
+you need to pass the compiler wrappers manually. eg.: `intercept-build
+--override-compiler make CC=intercept-cc CXX=intercept-c++ all` where the
+original build command would have been `make all` only.)
+
+The 1. runs the analyzer right after the real compilation. So, if the build
+process removes removes intermediate modules (generated sources) the analyzer
+output still kept.
+
+The 2. and 3. generate the compilation database first, and filters out those
+modules which are not exists. So, it's suitable for incremental analysis durring
+the development.
+
+The 2. mode is available only on FreeBSD and Linux. Where library preload
+is available from the dynamic loader. Not supported on OS X (unless System
+Integrity Protection feature is turned off).
+
+`intercept-build` command uses only the 2. and 3. mode to generate the
+compilation database. `analyze-build` does only run the analyzer against the
+captured compiler calls.
+
+
+Known problems
+--------------
+
+Because it uses `LD_PRELOAD` or `DYLD_INSERT_LIBRARIES` environment variables,
+it does not append to it, but overrides it. So builds which are using these
+variables might not work. (I don't know any build tool which does that, but
+please let me know if you do.)
+
+
+Problem reports
+---------------
+
+If you find a bug in this documentation or elsewhere in the program or would
+like to propose an improvement, please use the project's [issue tracker][3].
+Please describing the bug and where you found it. If you have a suggestion
+how to fix it, include that as well. Patches are also welcome.
+
+
+License
+-------
+
+The project is licensed under University of Illinois/NCSA Open Source License.
+See LICENSE.TXT for details.
+
+ [1]: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+ [2]: https://pypi.python.org/pypi/scan-build
+ [3]: https://llvm.org/bugs/enter_bug.cgi?product=clang
diff --git a/tools/scan-build-py/bin/analyze-build b/tools/scan-build-py/bin/analyze-build
new file mode 100644
index 0000000..2cc9676
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_main
+sys.exit(analyze_build_main(this_dir, False))
diff --git a/tools/scan-build-py/bin/analyze-c++ b/tools/scan-build-py/bin/analyze-c++
new file mode 100644
index 0000000..15186d8
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-c++
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_wrapper
+sys.exit(analyze_build_wrapper(True))
diff --git a/tools/scan-build-py/bin/analyze-cc b/tools/scan-build-py/bin/analyze-cc
new file mode 100644
index 0000000..55519fb
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-cc
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_wrapper
+sys.exit(analyze_build_wrapper(False))
diff --git a/tools/scan-build-py/bin/intercept-build b/tools/scan-build-py/bin/intercept-build
new file mode 100644
index 0000000..164f2e6
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_main
+sys.exit(intercept_build_main(this_dir))
diff --git a/tools/scan-build-py/bin/intercept-c++ b/tools/scan-build-py/bin/intercept-c++
new file mode 100644
index 0000000..fc42228
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-c++
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_wrapper
+sys.exit(intercept_build_wrapper(True))
diff --git a/tools/scan-build-py/bin/intercept-cc b/tools/scan-build-py/bin/intercept-cc
new file mode 100644
index 0000000..69d57aa
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-cc
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_wrapper
+sys.exit(intercept_build_wrapper(False))
diff --git a/tools/scan-build-py/bin/scan-build b/tools/scan-build-py/bin/scan-build
new file mode 100644
index 0000000..601fe89
--- /dev/null
+++ b/tools/scan-build-py/bin/scan-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_main
+sys.exit(analyze_build_main(this_dir, True))
diff --git a/tools/scan-build-py/libear/__init__.py b/tools/scan-build-py/libear/__init__.py
new file mode 100644
index 0000000..3e1c13c
--- /dev/null
+++ b/tools/scan-build-py/libear/__init__.py
@@ -0,0 +1,260 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module compiles the intercept library. """
+
+import sys
+import os
+import os.path
+import re
+import tempfile
+import shutil
+import contextlib
+import logging
+
+__all__ = ['build_libear']
+
+
+def build_libear(compiler, dst_dir):
+ """ Returns the full path to the 'libear' library. """
+
+ try:
+ src_dir = os.path.dirname(os.path.realpath(__file__))
+ toolset = make_toolset(src_dir)
+ toolset.set_compiler(compiler)
+ toolset.set_language_standard('c99')
+ toolset.add_definitions(['-D_GNU_SOURCE'])
+
+ configure = do_configure(toolset)
+ configure.check_function_exists('execve', 'HAVE_EXECVE')
+ configure.check_function_exists('execv', 'HAVE_EXECV')
+ configure.check_function_exists('execvpe', 'HAVE_EXECVPE')
+ configure.check_function_exists('execvp', 'HAVE_EXECVP')
+ configure.check_function_exists('execvP', 'HAVE_EXECVP2')
+ configure.check_function_exists('exect', 'HAVE_EXECT')
+ configure.check_function_exists('execl', 'HAVE_EXECL')
+ configure.check_function_exists('execlp', 'HAVE_EXECLP')
+ configure.check_function_exists('execle', 'HAVE_EXECLE')
+ configure.check_function_exists('posix_spawn', 'HAVE_POSIX_SPAWN')
+ configure.check_function_exists('posix_spawnp', 'HAVE_POSIX_SPAWNP')
+ configure.check_symbol_exists('_NSGetEnviron', 'crt_externs.h',
+ 'HAVE_NSGETENVIRON')
+ configure.write_by_template(
+ os.path.join(src_dir, 'config.h.in'),
+ os.path.join(dst_dir, 'config.h'))
+
+ target = create_shared_library('ear', toolset)
+ target.add_include(dst_dir)
+ target.add_sources('ear.c')
+ target.link_against(toolset.dl_libraries())
+ target.link_against(['pthread'])
+ target.build_release(dst_dir)
+
+ return os.path.join(dst_dir, target.name)
+
+ except Exception:
+ logging.info("Could not build interception library.", exc_info=True)
+ return None
+
+
+def execute(cmd, *args, **kwargs):
+ """ Make subprocess execution silent. """
+
+ import subprocess
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.check_call(cmd, *args, **kwargs)
+
+
+@contextlib.contextmanager
+def TemporaryDirectory(**kwargs):
+ name = tempfile.mkdtemp(**kwargs)
+ try:
+ yield name
+ finally:
+ shutil.rmtree(name)
+
+
+class Toolset(object):
+ """ Abstract class to represent different toolset. """
+
+ def __init__(self, src_dir):
+ self.src_dir = src_dir
+ self.compiler = None
+ self.c_flags = []
+
+ def set_compiler(self, compiler):
+ """ part of public interface """
+ self.compiler = compiler
+
+ def set_language_standard(self, standard):
+ """ part of public interface """
+ self.c_flags.append('-std=' + standard)
+
+ def add_definitions(self, defines):
+ """ part of public interface """
+ self.c_flags.extend(defines)
+
+ def dl_libraries(self):
+ raise NotImplementedError()
+
+ def shared_library_name(self, name):
+ raise NotImplementedError()
+
+ def shared_library_c_flags(self, release):
+ extra = ['-DNDEBUG', '-O3'] if release else []
+ return extra + ['-fPIC'] + self.c_flags
+
+ def shared_library_ld_flags(self, release, name):
+ raise NotImplementedError()
+
+
+class DarwinToolset(Toolset):
+ def __init__(self, src_dir):
+ Toolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return []
+
+ def shared_library_name(self, name):
+ return 'lib' + name + '.dylib'
+
+ def shared_library_ld_flags(self, release, name):
+ extra = ['-dead_strip'] if release else []
+ return extra + ['-dynamiclib', '-install_name', '@rpath/' + name]
+
+
+class UnixToolset(Toolset):
+ def __init__(self, src_dir):
+ Toolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return []
+
+ def shared_library_name(self, name):
+ return 'lib' + name + '.so'
+
+ def shared_library_ld_flags(self, release, name):
+ extra = [] if release else []
+ return extra + ['-shared', '-Wl,-soname,' + name]
+
+
+class LinuxToolset(UnixToolset):
+ def __init__(self, src_dir):
+ UnixToolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return ['dl']
+
+
+def make_toolset(src_dir):
+ platform = sys.platform
+ if platform in {'win32', 'cygwin'}:
+ raise RuntimeError('not implemented on this platform')
+ elif platform == 'darwin':
+ return DarwinToolset(src_dir)
+ elif platform in {'linux', 'linux2'}:
+ return LinuxToolset(src_dir)
+ else:
+ return UnixToolset(src_dir)
+
+
+class Configure(object):
+ def __init__(self, toolset):
+ self.ctx = toolset
+ self.results = {'APPLE': sys.platform == 'darwin'}
+
+ def _try_to_compile_and_link(self, source):
+ try:
+ with TemporaryDirectory() as work_dir:
+ src_file = 'check.c'
+ with open(os.path.join(work_dir, src_file), 'w') as handle:
+ handle.write(source)
+
+ execute([self.ctx.compiler, src_file] + self.ctx.c_flags,
+ cwd=work_dir)
+ return True
+ except Exception:
+ return False
+
+ def check_function_exists(self, function, name):
+ template = "int FUNCTION(); int main() { return FUNCTION(); }"
+ source = template.replace("FUNCTION", function)
+
+ logging.debug('Checking function %s', function)
+ found = self._try_to_compile_and_link(source)
+ logging.debug('Checking function %s -- %s', function,
+ 'found' if found else 'not found')
+ self.results.update({name: found})
+
+ def check_symbol_exists(self, symbol, include, name):
+ template = """#include <INCLUDE>
+ int main() { return ((int*)(&SYMBOL))[0]; }"""
+ source = template.replace('INCLUDE', include).replace("SYMBOL", symbol)
+
+ logging.debug('Checking symbol %s', symbol)
+ found = self._try_to_compile_and_link(source)
+ logging.debug('Checking symbol %s -- %s', symbol,
+ 'found' if found else 'not found')
+ self.results.update({name: found})
+
+ def write_by_template(self, template, output):
+ def transform(line, definitions):
+
+ pattern = re.compile(r'^#cmakedefine\s+(\S+)')
+ m = pattern.match(line)
+ if m:
+ key = m.group(1)
+ if key not in definitions or not definitions[key]:
+ return '/* #undef {} */\n'.format(key)
+ else:
+ return '#define {}\n'.format(key)
+ return line
+
+ with open(template, 'r') as src_handle:
+ logging.debug('Writing config to %s', output)
+ with open(output, 'w') as dst_handle:
+ for line in src_handle:
+ dst_handle.write(transform(line, self.results))
+
+
+def do_configure(toolset):
+ return Configure(toolset)
+
+
+class SharedLibrary(object):
+ def __init__(self, name, toolset):
+ self.name = toolset.shared_library_name(name)
+ self.ctx = toolset
+ self.inc = []
+ self.src = []
+ self.lib = []
+
+ def add_include(self, directory):
+ self.inc.extend(['-I', directory])
+
+ def add_sources(self, source):
+ self.src.append(source)
+
+ def link_against(self, libraries):
+ self.lib.extend(['-l' + lib for lib in libraries])
+
+ def build_release(self, directory):
+ for src in self.src:
+ logging.debug('Compiling %s', src)
+ execute(
+ [self.ctx.compiler, '-c', os.path.join(self.ctx.src_dir, src),
+ '-o', src + '.o'] + self.inc +
+ self.ctx.shared_library_c_flags(True),
+ cwd=directory)
+ logging.debug('Linking %s', self.name)
+ execute(
+ [self.ctx.compiler] + [src + '.o' for src in self.src] +
+ ['-o', self.name] + self.lib +
+ self.ctx.shared_library_ld_flags(True, self.name),
+ cwd=directory)
+
+
+def create_shared_library(name, toolset):
+ return SharedLibrary(name, toolset)
diff --git a/tools/scan-build-py/libear/config.h.in b/tools/scan-build-py/libear/config.h.in
new file mode 100644
index 0000000..6643d89
--- /dev/null
+++ b/tools/scan-build-py/libear/config.h.in
@@ -0,0 +1,23 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#pragma once
+
+#cmakedefine HAVE_EXECVE
+#cmakedefine HAVE_EXECV
+#cmakedefine HAVE_EXECVPE
+#cmakedefine HAVE_EXECVP
+#cmakedefine HAVE_EXECVP2
+#cmakedefine HAVE_EXECT
+#cmakedefine HAVE_EXECL
+#cmakedefine HAVE_EXECLP
+#cmakedefine HAVE_EXECLE
+#cmakedefine HAVE_POSIX_SPAWN
+#cmakedefine HAVE_POSIX_SPAWNP
+#cmakedefine HAVE_NSGETENVIRON
+
+#cmakedefine APPLE
diff --git a/tools/scan-build-py/libear/ear.c b/tools/scan-build-py/libear/ear.c
new file mode 100644
index 0000000..0e7093a
--- /dev/null
+++ b/tools/scan-build-py/libear/ear.c
@@ -0,0 +1,605 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+/**
+ * This file implements a shared library. This library can be pre-loaded by
+ * the dynamic linker of the Operating System (OS). It implements a few function
+ * related to process creation. By pre-load this library the executed process
+ * uses these functions instead of those from the standard library.
+ *
+ * The idea here is to inject a logic before call the real methods. The logic is
+ * to dump the call into a file. To call the real method this library is doing
+ * the job of the dynamic linker.
+ *
+ * The only input for the log writing is about the destination directory.
+ * This is passed as environment variable.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+#if defined HAVE_NSGETENVIRON
+# include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
+#ifdef APPLE
+# define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
+# define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
+# define ENV_SIZE 3
+#else
+# define ENV_PRELOAD "LD_PRELOAD"
+# define ENV_SIZE 2
+#endif
+
+#define DLSYM(TYPE_, VAR_, SYMBOL_) \
+ union { \
+ void *from; \
+ TYPE_ to; \
+ } cast; \
+ if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) { \
+ perror("bear: dlsym"); \
+ exit(EXIT_FAILURE); \
+ } \
+ TYPE_ const VAR_ = cast.to;
+
+
+typedef char const * bear_env_t[ENV_SIZE];
+
+static int bear_capture_env_t(bear_env_t *env);
+static int bear_reset_env_t(bear_env_t *env);
+static void bear_release_env_t(bear_env_t *env);
+static char const **bear_update_environment(char *const envp[], bear_env_t *env);
+static char const **bear_update_environ(char const **in, char const *key, char const *value);
+static char **bear_get_environment();
+static void bear_report_call(char const *fun, char const *const argv[]);
+static char const **bear_strings_build(char const *arg, va_list *ap);
+static char const **bear_strings_copy(char const **const in);
+static char const **bear_strings_append(char const **in, char const *e);
+static size_t bear_strings_length(char const *const *in);
+static void bear_strings_release(char const **);
+
+
+static bear_env_t env_names =
+ { ENV_OUTPUT
+ , ENV_PRELOAD
+#ifdef ENV_FLAT
+ , ENV_FLAT
+#endif
+ };
+
+static bear_env_t initial_env =
+ { 0
+ , 0
+#ifdef ENV_FLAT
+ , 0
+#endif
+ };
+
+static int initialized = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void on_load(void) __attribute__((constructor));
+static void on_unload(void) __attribute__((destructor));
+
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]);
+#endif
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+ char *const argv[]);
+#endif
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]);
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]);
+#endif
+
+
+/* Initialization method to Captures the relevant environment variables.
+ */
+
+static void on_load(void) {
+ pthread_mutex_lock(&mutex);
+ if (!initialized)
+ initialized = bear_capture_env_t(&initial_env);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void on_unload(void) {
+ pthread_mutex_lock(&mutex);
+ bear_release_env_t(&initial_env);
+ initialized = 0;
+ pthread_mutex_unlock(&mutex);
+}
+
+
+/* These are the methods we are try to hijack.
+ */
+
+#ifdef HAVE_EXECVE
+int execve(const char *path, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECV
+#ifndef HAVE_EXECVE
+#error can not implement execv without execve
+#endif
+int execv(const char *path, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ char * const * envp = bear_get_environment();
+ return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+int execvpe(const char *file, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvpe(file, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVP
+int execvp(const char *file, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvp(file, argv);
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+int execvP(const char *file, const char *search_path, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvP(file, search_path, argv);
+}
+#endif
+
+#ifdef HAVE_EXECT
+int exect(const char *path, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_exect(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECL
+# ifndef HAVE_EXECVE
+# error can not implement execl without execve
+# endif
+int execl(const char *path, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ char * const * envp = bear_get_environment();
+ int const result = call_execve(path, (char *const *)argv, envp);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECLP
+# ifndef HAVE_EXECVP
+# error can not implement execlp without execvp
+# endif
+int execlp(const char *file, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ int const result = call_execvp(file, (char *const *)argv);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECLE
+# ifndef HAVE_EXECVE
+# error can not implement execle without execve
+# endif
+// int execle(const char *path, const char *arg, ..., char * const envp[]);
+int execle(const char *path, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ char const **envp = va_arg(args, char const **);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ int const result =
+ call_execve(path, (char *const *)argv, (char *const *)envp);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+int posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict], char *const envp[restrict]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+int posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict], char *const envp[restrict]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
+}
+#endif
+
+/* These are the methods which forward the call to the standard implementation.
+ */
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "execve");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(path, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "execvpe");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(file, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]) {
+ typedef int (*func)(const char *file, char *const argv[]);
+
+ DLSYM(func, fp, "execvp");
+
+ bear_env_t current_env;
+ bear_capture_env_t(¤t_env);
+ bear_reset_env_t(&initial_env);
+ int const result = (*fp)(file, argv);
+ bear_reset_env_t(¤t_env);
+ bear_release_env_t(¤t_env);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+ char *const argv[]) {
+ typedef int (*func)(const char *, const char *, char *const *);
+
+ DLSYM(func, fp, "execvP");
+
+ bear_env_t current_env;
+ bear_capture_env_t(¤t_env);
+ bear_reset_env_t(&initial_env);
+ int const result = (*fp)(file, search_path, argv);
+ bear_reset_env_t(¤t_env);
+ bear_release_env_t(¤t_env);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "exect");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(path, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]) {
+ typedef int (*func)(pid_t *restrict, const char *restrict,
+ const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *restrict,
+ char *const *restrict, char *const *restrict);
+
+ DLSYM(func, fp, "posix_spawn");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result =
+ (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]) {
+ typedef int (*func)(pid_t *restrict, const char *restrict,
+ const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *restrict,
+ char *const *restrict, char *const *restrict);
+
+ DLSYM(func, fp, "posix_spawnp");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result =
+ (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+/* this method is to write log about the process creation. */
+
+static void bear_report_call(char const *fun, char const *const argv[]) {
+ static int const GS = 0x1d;
+ static int const RS = 0x1e;
+ static int const US = 0x1f;
+
+ if (!initialized)
+ return;
+
+ pthread_mutex_lock(&mutex);
+ const char *cwd = getcwd(NULL, 0);
+ if (0 == cwd) {
+ perror("bear: getcwd");
+ exit(EXIT_FAILURE);
+ }
+ char const * const out_dir = initial_env[0];
+ size_t const path_max_length = strlen(out_dir) + 32;
+ char filename[path_max_length];
+ if (-1 == snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
+ perror("bear: snprintf");
+ exit(EXIT_FAILURE);
+ }
+ FILE * fd = fopen(filename, "a+");
+ if (0 == fd) {
+ perror("bear: fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "%d%c", getpid(), RS);
+ fprintf(fd, "%d%c", getppid(), RS);
+ fprintf(fd, "%s%c", fun, RS);
+ fprintf(fd, "%s%c", cwd, RS);
+ size_t const argc = bear_strings_length(argv);
+ for (size_t it = 0; it < argc; ++it) {
+ fprintf(fd, "%s%c", argv[it], US);
+ }
+ fprintf(fd, "%c", GS);
+ if (fclose(fd)) {
+ perror("bear: fclose");
+ exit(EXIT_FAILURE);
+ }
+ free((void *)cwd);
+ pthread_mutex_unlock(&mutex);
+}
+
+/* update environment assure that chilren processes will copy the desired
+ * behaviour */
+
+static int bear_capture_env_t(bear_env_t *env) {
+ int status = 1;
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ char const * const env_value = getenv(env_names[it]);
+ char const * const env_copy = (env_value) ? strdup(env_value) : env_value;
+ (*env)[it] = env_copy;
+ status &= (env_copy) ? 1 : 0;
+ }
+ return status;
+}
+
+static int bear_reset_env_t(bear_env_t *env) {
+ int status = 1;
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ if ((*env)[it]) {
+ setenv(env_names[it], (*env)[it], 1);
+ } else {
+ unsetenv(env_names[it]);
+ }
+ }
+ return status;
+}
+
+static void bear_release_env_t(bear_env_t *env) {
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ free((void *)(*env)[it]);
+ (*env)[it] = 0;
+ }
+}
+
+static char const **bear_update_environment(char *const envp[], bear_env_t *env) {
+ char const **result = bear_strings_copy((char const **)envp);
+ for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
+ result = bear_update_environ(result, env_names[it], (*env)[it]);
+ return result;
+}
+
+static char const **bear_update_environ(char const *envs[], char const *key, char const * const value) {
+ // find the key if it's there
+ size_t const key_length = strlen(key);
+ char const **it = envs;
+ for (; (it) && (*it); ++it) {
+ if ((0 == strncmp(*it, key, key_length)) &&
+ (strlen(*it) > key_length) && ('=' == (*it)[key_length]))
+ break;
+ }
+ // allocate a environment entry
+ size_t const value_length = strlen(value);
+ size_t const env_length = key_length + value_length + 2;
+ char *env = malloc(env_length);
+ if (0 == env) {
+ perror("bear: malloc [in env_update]");
+ exit(EXIT_FAILURE);
+ }
+ if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
+ perror("bear: snprintf");
+ exit(EXIT_FAILURE);
+ }
+ // replace or append the environment entry
+ if (it && *it) {
+ free((void *)*it);
+ *it = env;
+ return envs;
+ }
+ return bear_strings_append(envs, env);
+}
+
+static char **bear_get_environment() {
+#if defined HAVE_NSGETENVIRON
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+}
+
+/* util methods to deal with string arrays. environment and process arguments
+ * are both represented as string arrays. */
+
+static char const **bear_strings_build(char const *const arg, va_list *args) {
+ char const **result = 0;
+ size_t size = 0;
+ for (char const *it = arg; it; it = va_arg(*args, char const *)) {
+ result = realloc(result, (size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ char const *copy = strdup(it);
+ if (0 == copy) {
+ perror("bear: strdup");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = copy;
+ }
+ result = realloc(result, (size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = 0;
+
+ return result;
+}
+
+static char const **bear_strings_copy(char const **const in) {
+ size_t const size = bear_strings_length(in);
+
+ char const **const result = malloc((size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ char const **out_it = result;
+ for (char const *const *in_it = in; (in_it) && (*in_it);
+ ++in_it, ++out_it) {
+ *out_it = strdup(*in_it);
+ if (0 == *out_it) {
+ perror("bear: strdup");
+ exit(EXIT_FAILURE);
+ }
+ }
+ *out_it = 0;
+ return result;
+}
+
+static char const **bear_strings_append(char const **const in,
+ char const *const e) {
+ size_t size = bear_strings_length(in);
+ char const **result = realloc(in, (size + 2) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = e;
+ result[size++] = 0;
+ return result;
+}
+
+static size_t bear_strings_length(char const *const *const in) {
+ size_t result = 0;
+ for (char const *const *it = in; (it) && (*it); ++it)
+ ++result;
+ return result;
+}
+
+static void bear_strings_release(char const **in) {
+ for (char const *const *it = in; (it) && (*it); ++it) {
+ free((void *)*it);
+ }
+ free((void *)in);
+}
diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py
new file mode 100644
index 0000000..c020b4e
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/__init__.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+"""
+This module responsible to run the Clang static analyzer against any build
+and generate reports.
+"""
+
+
+def duplicate_check(method):
+ """ Predicate to detect duplicated entries.
+
+ Unique hash method can be use to detect duplicates. Entries are
+ represented as dictionaries, which has no default hash method.
+ This implementation uses a set datatype to store the unique hash values.
+
+ This method returns a method which can detect the duplicate values. """
+
+ def predicate(entry):
+ entry_hash = predicate.unique(entry)
+ if entry_hash not in predicate.state:
+ predicate.state.add(entry_hash)
+ return False
+ return True
+
+ predicate.unique = method
+ predicate.state = set()
+ return predicate
+
+
+def tempdir():
+ """ Return the default temorary directory. """
+
+ from os import getenv
+ return getenv('TMPDIR', getenv('TEMP', getenv('TMP', '/tmp')))
+
+
+def initialize_logging(verbose_level):
+ """ Output content controlled by the verbosity level. """
+
+ import sys
+ import os.path
+ import logging
+ level = logging.WARNING - min(logging.WARNING, (10 * verbose_level))
+
+ if verbose_level <= 3:
+ fmt_string = '{0}: %(levelname)s: %(message)s'
+ else:
+ fmt_string = '{0}: %(levelname)s: %(funcName)s: %(message)s'
+
+ program = os.path.basename(sys.argv[0])
+ logging.basicConfig(format=fmt_string.format(program), level=level)
+
+
+def command_entry_point(function):
+ """ Decorator for command entry points. """
+
+ import functools
+ import logging
+
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+
+ exit_code = 127
+ try:
+ exit_code = function(*args, **kwargs)
+ except KeyboardInterrupt:
+ logging.warning('Keyboard interupt')
+ except Exception:
+ logging.exception('Internal error.')
+ if logging.getLogger().isEnabledFor(logging.DEBUG):
+ logging.error("Please report this bug and attach the output "
+ "to the bug report")
+ else:
+ logging.error("Please run this command again and turn on "
+ "verbose mode (add '-vvv' as argument).")
+ finally:
+ return exit_code
+
+ return wrapper
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
new file mode 100644
index 0000000..0d3547b
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -0,0 +1,502 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module implements the 'scan-build' command API.
+
+To run the static analyzer against a build is done in multiple steps:
+
+ -- Intercept: capture the compilation command during the build,
+ -- Analyze: run the analyzer against the captured commands,
+ -- Report: create a cover report from the analyzer outputs. """
+
+import sys
+import re
+import os
+import os.path
+import json
+import argparse
+import logging
+import subprocess
+import multiprocessing
+from libscanbuild import initialize_logging, tempdir, command_entry_point
+from libscanbuild.runner import run
+from libscanbuild.intercept import capture
+from libscanbuild.report import report_directory, document
+from libscanbuild.clang import get_checkers
+from libscanbuild.runner import action_check
+from libscanbuild.command import classify_parameters, classify_source
+
+__all__ = ['analyze_build_main', 'analyze_build_wrapper']
+
+COMPILER_WRAPPER_CC = 'analyze-cc'
+COMPILER_WRAPPER_CXX = 'analyze-c++'
+
+
+@command_entry_point
+def analyze_build_main(bin_dir, from_build_command):
+ """ Entry point for 'analyze-build' and 'scan-build'. """
+
+ parser = create_parser(from_build_command)
+ args = parser.parse_args()
+ validate(parser, args, from_build_command)
+
+ # setup logging
+ initialize_logging(args.verbose)
+ logging.debug('Parsed arguments: %s', args)
+
+ with report_directory(args.output, args.keep_empty) as target_dir:
+ if not from_build_command:
+ # run analyzer only and generate cover report
+ run_analyzer(args, target_dir)
+ number_of_bugs = document(args, target_dir, True)
+ return number_of_bugs if args.status_bugs else 0
+ elif args.intercept_first:
+ # run build command and capture compiler executions
+ exit_code = capture(args, bin_dir)
+ # next step to run the analyzer against the captured commands
+ if need_analyzer(args.build):
+ run_analyzer(args, target_dir)
+ # cover report generation and bug counting
+ number_of_bugs = document(args, target_dir, True)
+ # remove the compilation database when it was not requested
+ if os.path.exists(args.cdb):
+ os.unlink(args.cdb)
+ # set exit status as it was requested
+ return number_of_bugs if args.status_bugs else exit_code
+ else:
+ return exit_code
+ else:
+ # run the build command with compiler wrappers which
+ # execute the analyzer too. (interposition)
+ environment = setup_environment(args, target_dir, bin_dir)
+ logging.debug('run build in environment: %s', environment)
+ exit_code = subprocess.call(args.build, env=environment)
+ logging.debug('build finished with exit code: %d', exit_code)
+ # cover report generation and bug counting
+ number_of_bugs = document(args, target_dir, False)
+ # set exit status as it was requested
+ return number_of_bugs if args.status_bugs else exit_code
+
+
+def need_analyzer(args):
+ """ Check the intent of the build command.
+
+ When static analyzer run against project configure step, it should be
+ silent and no need to run the analyzer or generate report.
+
+ To run `scan-build` against the configure step might be neccessary,
+ when compiler wrappers are used. That's the moment when build setup
+ check the compiler and capture the location for the build process. """
+
+ return len(args) and not re.search('configure|autogen', args[0])
+
+
+def run_analyzer(args, output_dir):
+ """ Runs the analyzer against the given compilation database. """
+
+ def exclude(filename):
+ """ Return true when any excluded directory prefix the filename. """
+ return any(re.match(r'^' + directory, filename)
+ for directory in args.excludes)
+
+ consts = {
+ 'clang': args.clang,
+ 'output_dir': output_dir,
+ 'output_format': args.output_format,
+ 'output_failures': args.output_failures,
+ 'direct_args': analyzer_params(args)
+ }
+
+ logging.debug('run analyzer against compilation database')
+ with open(args.cdb, 'r') as handle:
+ generator = (dict(cmd, **consts)
+ for cmd in json.load(handle) if not exclude(cmd['file']))
+ # when verbose output requested execute sequentially
+ pool = multiprocessing.Pool(1 if args.verbose > 2 else None)
+ for current in pool.imap_unordered(run, generator):
+ if current is not None:
+ # display error message from the static analyzer
+ for line in current['error_output']:
+ logging.info(line.rstrip())
+ pool.close()
+ pool.join()
+
+
+def setup_environment(args, destination, bin_dir):
+ """ Set up environment for build command to interpose compiler wrapper. """
+
+ environment = dict(os.environ)
+ environment.update({
+ 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
+ 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
+ 'ANALYZE_BUILD_CC': args.cc,
+ 'ANALYZE_BUILD_CXX': args.cxx,
+ 'ANALYZE_BUILD_CLANG': args.clang if need_analyzer(args.build) else '',
+ 'ANALYZE_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'WARNING',
+ 'ANALYZE_BUILD_REPORT_DIR': destination,
+ 'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
+ 'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
+ 'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args))
+ })
+ return environment
+
+
+def analyze_build_wrapper(cplusplus):
+ """ Entry point for `analyze-cc` and `analyze-c++` compiler wrappers. """
+
+ # initialize wrapper logging
+ logging.basicConfig(format='analyze: %(levelname)s: %(message)s',
+ level=os.getenv('ANALYZE_BUILD_VERBOSE', 'INFO'))
+ # execute with real compiler
+ compiler = os.getenv('ANALYZE_BUILD_CXX', 'c++') if cplusplus \
+ else os.getenv('ANALYZE_BUILD_CC', 'cc')
+ compilation = [compiler] + sys.argv[1:]
+ logging.info('execute compiler: %s', compilation)
+ result = subprocess.call(compilation)
+ # exit when it fails, ...
+ if result or not os.getenv('ANALYZE_BUILD_CLANG'):
+ return result
+ # ... and run the analyzer if all went well.
+ try:
+ # collect the needed parameters from environment, crash when missing
+ consts = {
+ 'clang': os.getenv('ANALYZE_BUILD_CLANG'),
+ 'output_dir': os.getenv('ANALYZE_BUILD_REPORT_DIR'),
+ 'output_format': os.getenv('ANALYZE_BUILD_REPORT_FORMAT'),
+ 'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
+ 'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
+ '').split(' '),
+ 'directory': os.getcwd(),
+ }
+ # get relevant parameters from command line arguments
+ args = classify_parameters(sys.argv)
+ filenames = args.pop('files', [])
+ for filename in (name for name in filenames if classify_source(name)):
+ parameters = dict(args, file=filename, **consts)
+ logging.debug('analyzer parameters %s', parameters)
+ current = action_check(parameters)
+ # display error message from the static analyzer
+ if current is not None:
+ for line in current['error_output']:
+ logging.info(line.rstrip())
+ except Exception:
+ logging.exception("run analyzer inside compiler wrapper failed.")
+ return 0
+
+
+def analyzer_params(args):
+ """ A group of command line arguments can mapped to command
+ line arguments of the analyzer. This method generates those. """
+
+ def prefix_with(constant, pieces):
+ """ From a sequence create another sequence where every second element
+ is from the original sequence and the odd elements are the prefix.
+
+ eg.: prefix_with(0, [1,2,3]) creates [0, 1, 0, 2, 0, 3] """
+
+ return [elem for piece in pieces for elem in [constant, piece]]
+
+ result = []
+
+ if args.store_model:
+ result.append('-analyzer-store={0}'.format(args.store_model))
+ if args.constraints_model:
+ result.append(
+ '-analyzer-constraints={0}'.format(args.constraints_model))
+ if args.internal_stats:
+ result.append('-analyzer-stats')
+ if args.analyze_headers:
+ result.append('-analyzer-opt-analyze-headers')
+ if args.stats:
+ result.append('-analyzer-checker=debug.Stats')
+ if args.maxloop:
+ result.extend(['-analyzer-max-loop', str(args.maxloop)])
+ if args.output_format:
+ result.append('-analyzer-output={0}'.format(args.output_format))
+ if args.analyzer_config:
+ result.append(args.analyzer_config)
+ if args.verbose >= 4:
+ result.append('-analyzer-display-progress')
+ if args.plugins:
+ result.extend(prefix_with('-load', args.plugins))
+ if args.enable_checker:
+ checkers = ','.join(args.enable_checker)
+ result.extend(['-analyzer-checker', checkers])
+ if args.disable_checker:
+ checkers = ','.join(args.disable_checker)
+ result.extend(['-analyzer-disable-checker', checkers])
+ if os.getenv('UBIVIZ'):
+ result.append('-analyzer-viz-egraph-ubigraph')
+
+ return prefix_with('-Xclang', result)
+
+
+def print_active_checkers(checkers):
+ """ Print active checkers to stdout. """
+
+ for name in sorted(name for name, (_, active) in checkers.items()
+ if active):
+ print(name)
+
+
+def print_checkers(checkers):
+ """ Print verbose checker help to stdout. """
+
+ print('')
+ print('available checkers:')
+ print('')
+ for name in sorted(checkers.keys()):
+ description, active = checkers[name]
+ prefix = '+' if active else ' '
+ if len(name) > 30:
+ print(' {0} {1}'.format(prefix, name))
+ print(' ' * 35 + description)
+ else:
+ print(' {0} {1: <30} {2}'.format(prefix, name, description))
+ print('')
+ print('NOTE: "+" indicates that an analysis is enabled by default.')
+ print('')
+
+
+def validate(parser, args, from_build_command):
+ """ Validation done by the parser itself, but semantic check still
+ needs to be done. This method is doing that. """
+
+ if args.help_checkers_verbose:
+ print_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit()
+ elif args.help_checkers:
+ print_active_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit()
+
+ if from_build_command and not args.build:
+ parser.error('missing build command')
+
+
+def create_parser(from_build_command):
+ """ Command line argument parser factory method. """
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument(
+ '--verbose', '-v',
+ action='count',
+ default=0,
+ help="""Enable verbose output from '%(prog)s'. A second and third
+ flag increases verbosity.""")
+ parser.add_argument(
+ '--override-compiler',
+ action='store_true',
+ help="""Always resort to the compiler wrapper even when better
+ interposition methods are available.""")
+ parser.add_argument(
+ '--intercept-first',
+ action='store_true',
+ help="""Run the build commands only, build a compilation database,
+ then run the static analyzer afterwards.
+ Generally speaking it has better coverage on build commands.
+ With '--override-compiler' it use compiler wrapper, but does
+ not run the analyzer till the build is finished. """)
+ parser.add_argument(
+ '--cdb',
+ metavar='<file>',
+ default="compile_commands.json",
+ help="""The JSON compilation database.""")
+
+ parser.add_argument(
+ '--output', '-o',
+ metavar='<path>',
+ default=tempdir(),
+ help="""Specifies the output directory for analyzer reports.
+ Subdirectory will be created if default directory is targeted.
+ """)
+ parser.add_argument(
+ '--status-bugs',
+ action='store_true',
+ help="""By default, the exit status of '%(prog)s' is the same as the
+ executed build command. Specifying this option causes the exit
+ status of '%(prog)s' to be non zero if it found potential bugs
+ and zero otherwise.""")
+ parser.add_argument(
+ '--html-title',
+ metavar='<title>',
+ help="""Specify the title used on generated HTML pages.
+ If not specified, a default title will be used.""")
+ parser.add_argument(
+ '--analyze-headers',
+ action='store_true',
+ help="""Also analyze functions in #included files. By default, such
+ functions are skipped unless they are called by functions
+ within the main source file.""")
+ format_group = parser.add_mutually_exclusive_group()
+ format_group.add_argument(
+ '--plist', '-plist',
+ dest='output_format',
+ const='plist',
+ default='html',
+ action='store_const',
+ help="""This option outputs the results as a set of .plist files.""")
+ format_group.add_argument(
+ '--plist-html', '-plist-html',
+ dest='output_format',
+ const='plist-html',
+ default='html',
+ action='store_const',
+ help="""This option outputs the results as a set of .html and .plist
+ files.""")
+ # TODO: implement '-view '
+
+ advanced = parser.add_argument_group('advanced options')
+ advanced.add_argument(
+ '--keep-empty',
+ action='store_true',
+ help="""Don't remove the build results directory even if no issues
+ were reported.""")
+ advanced.add_argument(
+ '--no-failure-reports', '-no-failure-reports',
+ dest='output_failures',
+ action='store_false',
+ help="""Do not create a 'failures' subdirectory that includes analyzer
+ crash reports and preprocessed source files.""")
+ advanced.add_argument(
+ '--stats', '-stats',
+ action='store_true',
+ help="""Generates visitation statistics for the project being analyzed.
+ """)
+ advanced.add_argument(
+ '--internal-stats',
+ action='store_true',
+ help="""Generate internal analyzer statistics.""")
+ advanced.add_argument(
+ '--maxloop', '-maxloop',
+ metavar='<loop count>',
+ type=int,
+ help="""Specifiy the number of times a block can be visited before
+ giving up. Increase for more comprehensive coverage at a cost
+ of speed.""")
+ advanced.add_argument(
+ '--store', '-store',
+ metavar='<model>',
+ dest='store_model',
+ choices=['region', 'basic'],
+ help="""Specify the store model used by the analyzer.
+ 'region' specifies a field- sensitive store model.
+ 'basic' which is far less precise but can more quickly
+ analyze code. 'basic' was the default store model for
+ checker-0.221 and earlier.""")
+ advanced.add_argument(
+ '--constraints', '-constraints',
+ metavar='<model>',
+ dest='constraints_model',
+ choices=['range', 'basic'],
+ help="""Specify the contraint engine used by the analyzer. Specifying
+ 'basic' uses a simpler, less powerful constraint model used by
+ checker-0.160 and earlier.""")
+ advanced.add_argument(
+ '--use-analyzer',
+ metavar='<path>',
+ dest='clang',
+ default='clang',
+ help="""'%(prog)s' uses the 'clang' executable relative to itself for
+ static analysis. One can override this behavior with this
+ option by using the 'clang' packaged with Xcode (on OS X) or
+ from the PATH.""")
+ advanced.add_argument(
+ '--use-cc',
+ metavar='<path>',
+ dest='cc',
+ default='cc',
+ help="""When '%(prog)s' analyzes a project by interposing a "fake
+ compiler", which executes a real compiler for compilation and
+ do other tasks (to run the static analyzer or just record the
+ compiler invocation). Because of this interposing, '%(prog)s'
+ does not know what compiler your project normally uses.
+ Instead, it simply overrides the CC environment variable, and
+ guesses your default compiler.
+
+ If you need '%(prog)s' to use a specific compiler for
+ *compilation* then you can use this option to specify a path
+ to that compiler.""")
+ advanced.add_argument(
+ '--use-c++',
+ metavar='<path>',
+ dest='cxx',
+ default='c++',
+ help="""This is the same as "--use-cc" but for C++ code.""")
+ advanced.add_argument(
+ '--analyzer-config', '-analyzer-config',
+ metavar='<options>',
+ help="""Provide options to pass through to the analyzer's
+ -analyzer-config flag. Several options are separated with
+ comma: 'key1=val1,key2=val2'
+
+ Available options:
+ stable-report-filename=true or false (default)
+
+ Switch the page naming to:
+ report-<filename>-<function/method name>-<id>.html
+ instead of report-XXXXXX.html""")
+ advanced.add_argument(
+ '--exclude',
+ metavar='<directory>',
+ dest='excludes',
+ action='append',
+ default=[],
+ help="""Do not run static analyzer against files found in this
+ directory. (You can specify this option multiple times.)
+ Could be usefull when project contains 3rd party libraries.
+ The directory path shall be absolute path as file names in
+ the compilation database.""")
+
+ plugins = parser.add_argument_group('checker options')
+ plugins.add_argument(
+ '--load-plugin', '-load-plugin',
+ metavar='<plugin library>',
+ dest='plugins',
+ action='append',
+ help="""Loading external checkers using the clang plugin interface.""")
+ plugins.add_argument(
+ '--enable-checker', '-enable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Enable specific checker.""")
+ plugins.add_argument(
+ '--disable-checker', '-disable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Disable specific checker.""")
+ plugins.add_argument(
+ '--help-checkers',
+ action='store_true',
+ help="""A default group of checkers is run unless explicitly disabled.
+ Exactly which checkers constitute the default group is a
+ function of the operating system in use. These can be printed
+ with this flag.""")
+ plugins.add_argument(
+ '--help-checkers-verbose',
+ action='store_true',
+ help="""Print all available checkers and mark the enabled ones.""")
+
+ if from_build_command:
+ parser.add_argument(
+ dest='build',
+ nargs=argparse.REMAINDER,
+ help="""Command to run.""")
+
+ return parser
+
+
+class AppendCommaSeparated(argparse.Action):
+ """ argparse Action class to support multiple comma separated lists. """
+
+ def __call__(self, __parser, namespace, values, __option_string):
+ # getattr(obj, attr, default) does not really returns default but none
+ if getattr(namespace, self.dest, None) is None:
+ setattr(namespace, self.dest, [])
+ # once it's fixed we can use as expected
+ actual = getattr(namespace, self.dest)
+ actual.extend(values.split(','))
+ setattr(namespace, self.dest, actual)
diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py
new file mode 100644
index 0000000..0c3454b
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/clang.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible for the Clang executable.
+
+Since Clang command line interface is so rich, but this project is using only
+a subset of that, it makes sense to create a function specific wrapper. """
+
+import re
+import subprocess
+import logging
+from libscanbuild.shell import decode
+
+__all__ = ['get_version', 'get_arguments', 'get_checkers']
+
+
+def get_version(cmd):
+ """ Returns the compiler version as string. """
+
+ lines = subprocess.check_output([cmd, '-v'], stderr=subprocess.STDOUT)
+ return lines.decode('ascii').splitlines()[0]
+
+
+def get_arguments(command, cwd):
+ """ Capture Clang invocation.
+
+ This method returns the front-end invocation that would be executed as
+ a result of the given driver invocation. """
+
+ def lastline(stream):
+ last = None
+ for line in stream:
+ last = line
+ if last is None:
+ raise Exception("output not found")
+ return last
+
+ cmd = command[:]
+ cmd.insert(1, '-###')
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ cwd=cwd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ line = lastline(child.stdout)
+ child.stdout.close()
+ child.wait()
+ if child.returncode == 0:
+ if re.search(r'clang(.*): error:', line):
+ raise Exception(line)
+ return decode(line)
+ else:
+ raise Exception(line)
+
+
+def get_active_checkers(clang, plugins):
+ """ To get the default plugins we execute Clang to print how this
+ compilation would be called.
+
+ For input file we specify stdin and pass only language information. """
+
+ def checkers(language):
+ """ Returns a list of active checkers for the given language. """
+
+ load = [elem
+ for plugin in plugins
+ for elem in ['-Xclang', '-load', '-Xclang', plugin]]
+ cmd = [clang, '--analyze'] + load + ['-x', language, '-']
+ pattern = re.compile(r'^-analyzer-checker=(.*)$')
+ return [pattern.match(arg).group(1)
+ for arg in get_arguments(cmd, '.') if pattern.match(arg)]
+
+ result = set()
+ for language in ['c', 'c++', 'objective-c', 'objective-c++']:
+ result.update(checkers(language))
+ return result
+
+
+def get_checkers(clang, plugins):
+ """ Get all the available checkers from default and from the plugins.
+
+ clang -- the compiler we are using
+ plugins -- list of plugins which was requested by the user
+
+ This method returns a dictionary of all available checkers and status.
+
+ {<plugin name>: (<plugin description>, <is active by default>)} """
+
+ plugins = plugins if plugins else []
+
+ def parse_checkers(stream):
+ """ Parse clang -analyzer-checker-help output.
+
+ Below the line 'CHECKERS:' are there the name description pairs.
+ Many of them are in one line, but some long named plugins has the
+ name and the description in separate lines.
+
+ The plugin name is always prefixed with two space character. The
+ name contains no whitespaces. Then followed by newline (if it's
+ too long) or other space characters comes the description of the
+ plugin. The description ends with a newline character. """
+
+ # find checkers header
+ for line in stream:
+ if re.match(r'^CHECKERS:', line):
+ break
+ # find entries
+ state = None
+ for line in stream:
+ if state and not re.match(r'^\s\s\S', line):
+ yield (state, line.strip())
+ state = None
+ elif re.match(r'^\s\s\S+$', line.rstrip()):
+ state = line.strip()
+ else:
+ pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
+ match = pattern.match(line.rstrip())
+ if match:
+ current = match.groupdict()
+ yield (current['key'], current['value'])
+
+ def is_active(actives, entry):
+ """ Returns true if plugin name is matching the active plugin names.
+
+ actives -- set of active plugin names (or prefixes).
+ entry -- the current plugin name to judge.
+
+ The active plugin names are specific plugin names or prefix of some
+ names. One example for prefix, when it say 'unix' and it shall match
+ on 'unix.API', 'unix.Malloc' and 'unix.MallocSizeof'. """
+
+ return any(re.match(r'^' + a + r'(\.|$)', entry) for a in actives)
+
+ actives = get_active_checkers(clang, plugins)
+
+ load = [elem for plugin in plugins for elem in ['-load', plugin]]
+ cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
+
+ logging.debug('exec command: %s', ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ checkers = {
+ k: (v, is_active(actives, k))
+ for k, v in parse_checkers(child.stdout)
+ }
+ child.stdout.close()
+ child.wait()
+ if child.returncode == 0 and len(checkers):
+ return checkers
+ else:
+ raise Exception('Could not query Clang for available checkers.')
diff --git a/tools/scan-build-py/libscanbuild/command.py b/tools/scan-build-py/libscanbuild/command.py
new file mode 100644
index 0000000..69ca339
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/command.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible for to parse a compiler invocation. """
+
+import re
+import os
+
+__all__ = ['Action', 'classify_parameters', 'classify_source']
+
+
+class Action(object):
+ """ Enumeration class for compiler action. """
+
+ Link, Compile, Ignored = range(3)
+
+
+def classify_parameters(command):
+ """ Parses the command line arguments of the given invocation. """
+
+ # result value of this method.
+ # some value are preset, some will be set only when found.
+ result = {
+ 'action': Action.Link,
+ 'files': [],
+ 'output': None,
+ 'compile_options': [],
+ 'c++': is_cplusplus_compiler(command[0])
+ # archs_seen
+ # language
+ }
+
+ # data structure to ignore compiler parameters.
+ # key: parameter name, value: number of parameters to ignore afterwards.
+ ignored = {
+ '-g': 0,
+ '-fsyntax-only': 0,
+ '-save-temps': 0,
+ '-install_name': 1,
+ '-exported_symbols_list': 1,
+ '-current_version': 1,
+ '-compatibility_version': 1,
+ '-init': 1,
+ '-e': 1,
+ '-seg1addr': 1,
+ '-bundle_loader': 1,
+ '-multiply_defined': 1,
+ '-sectorder': 3,
+ '--param': 1,
+ '--serialize-diagnostics': 1
+ }
+
+ args = iter(command[1:])
+ for arg in args:
+ # compiler action parameters are the most important ones...
+ if arg in {'-E', '-S', '-cc1', '-M', '-MM', '-###'}:
+ result.update({'action': Action.Ignored})
+ elif arg == '-c':
+ result.update({'action': max(result['action'], Action.Compile)})
+ # arch flags are taken...
+ elif arg == '-arch':
+ archs = result.get('archs_seen', [])
+ result.update({'archs_seen': archs + [next(args)]})
+ # explicit language option taken...
+ elif arg == '-x':
+ result.update({'language': next(args)})
+ # output flag taken...
+ elif arg == '-o':
+ result.update({'output': next(args)})
+ # warning disable options are taken...
+ elif re.match(r'^-Wno-', arg):
+ result['compile_options'].append(arg)
+ # warning options are ignored...
+ elif re.match(r'^-[mW].+', arg):
+ pass
+ # some preprocessor parameters are ignored...
+ elif arg in {'-MD', '-MMD', '-MG', '-MP'}:
+ pass
+ elif arg in {'-MF', '-MT', '-MQ'}:
+ next(args)
+ # linker options are ignored...
+ elif arg in {'-static', '-shared', '-s', '-rdynamic'} or \
+ re.match(r'^-[lL].+', arg):
+ pass
+ elif arg in {'-l', '-L', '-u', '-z', '-T', '-Xlinker'}:
+ next(args)
+ # some other options are ignored...
+ elif arg in ignored.keys():
+ for _ in range(ignored[arg]):
+ next(args)
+ # parameters which looks source file are taken...
+ elif re.match(r'^[^-].+', arg) and classify_source(arg):
+ result['files'].append(arg)
+ # and consider everything else as compile option.
+ else:
+ result['compile_options'].append(arg)
+
+ return result
+
+
+def classify_source(filename, cplusplus=False):
+ """ Return the language from file name extension. """
+
+ mapping = {
+ '.c': 'c++' if cplusplus else 'c',
+ '.i': 'c++-cpp-output' if cplusplus else 'c-cpp-output',
+ '.ii': 'c++-cpp-output',
+ '.m': 'objective-c',
+ '.mi': 'objective-c-cpp-output',
+ '.mm': 'objective-c++',
+ '.mii': 'objective-c++-cpp-output',
+ '.C': 'c++',
+ '.cc': 'c++',
+ '.CC': 'c++',
+ '.cp': 'c++',
+ '.cpp': 'c++',
+ '.cxx': 'c++',
+ '.c++': 'c++',
+ '.C++': 'c++',
+ '.txx': 'c++'
+ }
+
+ __, extension = os.path.splitext(os.path.basename(filename))
+ return mapping.get(extension)
+
+
+def is_cplusplus_compiler(name):
+ """ Returns true when the compiler name refer to a C++ compiler. """
+
+ match = re.match(r'^([^/]*/)*(\w*-)*(\w+\+\+)(-(\d+(\.\d+){0,3}))?$', name)
+ return False if match is None else True
diff --git a/tools/scan-build-py/libscanbuild/intercept.py b/tools/scan-build-py/libscanbuild/intercept.py
new file mode 100644
index 0000000..6062e2e
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/intercept.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to capture the compiler invocation of any
+build process. The result of that should be a compilation database.
+
+This implementation is using the LD_PRELOAD or DYLD_INSERT_LIBRARIES
+mechanisms provided by the dynamic linker. The related library is implemented
+in C language and can be found under 'libear' directory.
+
+The 'libear' library is capturing all child process creation and logging the
+relevant information about it into separate files in a specified directory.
+The parameter of this process is the output directory name, where the report
+files shall be placed. This parameter is passed as an environment variable.
+
+The module also implements compiler wrappers to intercept the compiler calls.
+
+The module implements the build command execution and the post-processing of
+the output files, which will condensates into a compilation database. """
+
+import sys
+import os
+import os.path
+import re
+import itertools
+import json
+import glob
+import argparse
+import logging
+import subprocess
+from libear import build_libear, TemporaryDirectory
+from libscanbuild import duplicate_check, tempdir, initialize_logging
+from libscanbuild import command_entry_point
+from libscanbuild.command import Action, classify_parameters
+from libscanbuild.shell import encode, decode
+
+__all__ = ['capture', 'intercept_build_main', 'intercept_build_wrapper']
+
+GS = chr(0x1d)
+RS = chr(0x1e)
+US = chr(0x1f)
+
+COMPILER_WRAPPER_CC = 'intercept-cc'
+COMPILER_WRAPPER_CXX = 'intercept-c++'
+
+
+@command_entry_point
+def intercept_build_main(bin_dir):
+ """ Entry point for 'intercept-build' command. """
+
+ parser = create_parser()
+ args = parser.parse_args()
+
+ initialize_logging(args.verbose)
+ logging.debug('Parsed arguments: %s', args)
+
+ if not args.build:
+ parser.print_help()
+ return 0
+
+ return capture(args, bin_dir)
+
+
+def capture(args, bin_dir):
+ """ The entry point of build command interception. """
+
+ def post_processing(commands):
+ """ To make a compilation database, it needs to filter out commands
+ which are not compiler calls. Needs to find the source file name
+ from the arguments. And do shell escaping on the command.
+
+ To support incremental builds, it is desired to read elements from
+ an existing compilation database from a previous run. These elemets
+ shall be merged with the new elements. """
+
+ # create entries from the current run
+ current = itertools.chain.from_iterable(
+ # creates a sequence of entry generators from an exec,
+ # but filter out non compiler calls before.
+ (format_entry(x) for x in commands if is_compiler_call(x)))
+ # read entries from previous run
+ if 'append' in args and args.append and os.path.exists(args.cdb):
+ with open(args.cdb) as handle:
+ previous = iter(json.load(handle))
+ else:
+ previous = iter([])
+ # filter out duplicate entries from both
+ duplicate = duplicate_check(entry_hash)
+ return (entry for entry in itertools.chain(previous, current)
+ if os.path.exists(entry['file']) and not duplicate(entry))
+
+ with TemporaryDirectory(prefix='intercept-', dir=tempdir()) as tmp_dir:
+ # run the build command
+ environment = setup_environment(args, tmp_dir, bin_dir)
+ logging.debug('run build in environment: %s', environment)
+ exit_code = subprocess.call(args.build, env=environment)
+ logging.info('build finished with exit code: %d', exit_code)
+ # read the intercepted exec calls
+ commands = itertools.chain.from_iterable(
+ parse_exec_trace(os.path.join(tmp_dir, filename))
+ for filename in sorted(glob.iglob(os.path.join(tmp_dir, '*.cmd'))))
+ # do post processing only if that was requested
+ if 'raw_entries' not in args or not args.raw_entries:
+ entries = post_processing(commands)
+ else:
+ entries = commands
+ # dump the compilation database
+ with open(args.cdb, 'w+') as handle:
+ json.dump(list(entries), handle, sort_keys=True, indent=4)
+ return exit_code
+
+
+def setup_environment(args, destination, bin_dir):
+ """ Sets up the environment for the build command.
+
+ It sets the required environment variables and execute the given command.
+ The exec calls will be logged by the 'libear' preloaded library or by the
+ 'wrapper' programs. """
+
+ c_compiler = args.cc if 'cc' in args else 'cc'
+ cxx_compiler = args.cxx if 'cxx' in args else 'c++'
+
+ libear_path = None if args.override_compiler or is_preload_disabled(
+ sys.platform) else build_libear(c_compiler, destination)
+
+ environment = dict(os.environ)
+ environment.update({'INTERCEPT_BUILD_TARGET_DIR': destination})
+
+ if not libear_path:
+ logging.debug('intercept gonna use compiler wrappers')
+ environment.update({
+ 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
+ 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
+ 'INTERCEPT_BUILD_CC': c_compiler,
+ 'INTERCEPT_BUILD_CXX': cxx_compiler,
+ 'INTERCEPT_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'INFO'
+ })
+ elif sys.platform == 'darwin':
+ logging.debug('intercept gonna preload libear on OSX')
+ environment.update({
+ 'DYLD_INSERT_LIBRARIES': libear_path,
+ 'DYLD_FORCE_FLAT_NAMESPACE': '1'
+ })
+ else:
+ logging.debug('intercept gonna preload libear on UNIX')
+ environment.update({'LD_PRELOAD': libear_path})
+
+ return environment
+
+
+def intercept_build_wrapper(cplusplus):
+ """ Entry point for `intercept-cc` and `intercept-c++` compiler wrappers.
+
+ It does generate execution report into target directory. And execute
+ the wrapped compilation with the real compiler. The parameters for
+ report and execution are from environment variables.
+
+ Those parameters which for 'libear' library can't have meaningful
+ values are faked. """
+
+ # initialize wrapper logging
+ logging.basicConfig(format='intercept: %(levelname)s: %(message)s',
+ level=os.getenv('INTERCEPT_BUILD_VERBOSE', 'INFO'))
+ # write report
+ try:
+ target_dir = os.getenv('INTERCEPT_BUILD_TARGET_DIR')
+ if not target_dir:
+ raise UserWarning('exec report target directory not found')
+ pid = str(os.getpid())
+ target_file = os.path.join(target_dir, pid + '.cmd')
+ logging.debug('writing exec report to: %s', target_file)
+ with open(target_file, 'ab') as handler:
+ working_dir = os.getcwd()
+ command = US.join(sys.argv) + US
+ content = RS.join([pid, pid, 'wrapper', working_dir, command]) + GS
+ handler.write(content.encode('utf-8'))
+ except IOError:
+ logging.exception('writing exec report failed')
+ except UserWarning as warning:
+ logging.warning(warning)
+ # execute with real compiler
+ compiler = os.getenv('INTERCEPT_BUILD_CXX', 'c++') if cplusplus \
+ else os.getenv('INTERCEPT_BUILD_CC', 'cc')
+ compilation = [compiler] + sys.argv[1:]
+ logging.debug('execute compiler: %s', compilation)
+ return subprocess.call(compilation)
+
+
+def parse_exec_trace(filename):
+ """ Parse the file generated by the 'libear' preloaded library.
+
+ Given filename points to a file which contains the basic report
+ generated by the interception library or wrapper command. A single
+ report file _might_ contain multiple process creation info. """
+
+ logging.debug('parse exec trace file: %s', filename)
+ with open(filename, 'r') as handler:
+ content = handler.read()
+ for group in filter(bool, content.split(GS)):
+ records = group.split(RS)
+ yield {
+ 'pid': records[0],
+ 'ppid': records[1],
+ 'function': records[2],
+ 'directory': records[3],
+ 'command': records[4].split(US)[:-1]
+ }
+
+
+def format_entry(entry):
+ """ Generate the desired fields for compilation database entries. """
+
+ def abspath(cwd, name):
+ """ Create normalized absolute path from input filename. """
+ fullname = name if os.path.isabs(name) else os.path.join(cwd, name)
+ return os.path.normpath(fullname)
+
+ logging.debug('format this command: %s', entry['command'])
+ atoms = classify_parameters(entry['command'])
+ if atoms['action'] <= Action.Compile:
+ for source in atoms['files']:
+ compiler = 'c++' if atoms['c++'] else 'cc'
+ flags = atoms['compile_options']
+ flags += ['-o', atoms['output']] if atoms['output'] else []
+ flags += ['-x', atoms['language']] if 'language' in atoms else []
+ flags += [elem
+ for arch in atoms.get('archs_seen', [])
+ for elem in ['-arch', arch]]
+ command = [compiler, '-c'] + flags + [source]
+ logging.debug('formated as: %s', command)
+ yield {
+ 'directory': entry['directory'],
+ 'command': encode(command),
+ 'file': abspath(entry['directory'], source)
+ }
+
+
+def is_compiler_call(entry):
+ """ A predicate to decide the entry is a compiler call or not. """
+
+ patterns = [
+ re.compile(r'^([^/]*/)*intercept-c(c|\+\+)$'),
+ re.compile(r'^([^/]*/)*c(c|\+\+)$'),
+ re.compile(r'^([^/]*/)*([^-]*-)*[mg](cc|\+\+)(-\d+(\.\d+){0,2})?$'),
+ re.compile(r'^([^/]*/)*([^-]*-)*clang(\+\+)?(-\d+(\.\d+){0,2})?$'),
+ re.compile(r'^([^/]*/)*llvm-g(cc|\+\+)$'),
+ ]
+ executable = entry['command'][0]
+ return any((pattern.match(executable) for pattern in patterns))
+
+
+def is_preload_disabled(platform):
+ """ Library-based interposition will fail silently if SIP is enabled,
+ so this should be detected. You can detect whether SIP is enabled on
+ Darwin by checking whether (1) there is a binary called 'csrutil' in
+ the path and, if so, (2) whether the output of executing 'csrutil status'
+ contains 'System Integrity Protection status: enabled'.
+
+ Same problem on linux when SELinux is enabled. The status query program
+ 'sestatus' and the output when it's enabled 'SELinux status: enabled'. """
+
+ if platform == 'darwin':
+ pattern = re.compile(r'System Integrity Protection status:\s+enabled')
+ command = ['csrutil', 'status']
+ elif platform in {'linux', 'linux2'}:
+ pattern = re.compile(r'SELinux status:\s+enabled')
+ command = ['sestatus']
+ else:
+ return False
+
+ try:
+ lines = subprocess.check_output(command).decode('utf-8')
+ return any((pattern.match(line) for line in lines.splitlines()))
+ except:
+ return False
+
+
+def entry_hash(entry):
+ """ Implement unique hash method for compilation database entries. """
+
+ # For faster lookup in set filename is reverted
+ filename = entry['file'][::-1]
+ # For faster lookup in set directory is reverted
+ directory = entry['directory'][::-1]
+ # On OS X the 'cc' and 'c++' compilers are wrappers for
+ # 'clang' therefore both call would be logged. To avoid
+ # this the hash does not contain the first word of the
+ # command.
+ command = ' '.join(decode(entry['command'])[1:])
+
+ return '<>'.join([filename, directory, command])
+
+
+def create_parser():
+ """ Command line argument parser factory method. """
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument(
+ '--verbose', '-v',
+ action='count',
+ default=0,
+ help="""Enable verbose output from '%(prog)s'. A second and third
+ flag increases verbosity.""")
+ parser.add_argument(
+ '--cdb',
+ metavar='<file>',
+ default="compile_commands.json",
+ help="""The JSON compilation database.""")
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument(
+ '--append',
+ action='store_true',
+ help="""Append new entries to existing compilation database.""")
+ group.add_argument(
+ '--disable-filter', '-n',
+ dest='raw_entries',
+ action='store_true',
+ help="""Intercepted child process creation calls (exec calls) are all
+ logged to the output. The output is not a compilation database.
+ This flag is for debug purposes.""")
+
+ advanced = parser.add_argument_group('advanced options')
+ advanced.add_argument(
+ '--override-compiler',
+ action='store_true',
+ help="""Always resort to the compiler wrapper even when better
+ intercept methods are available.""")
+ advanced.add_argument(
+ '--use-cc',
+ metavar='<path>',
+ dest='cc',
+ default='cc',
+ help="""When '%(prog)s' analyzes a project by interposing a compiler
+ wrapper, which executes a real compiler for compilation and
+ do other tasks (record the compiler invocation). Because of
+ this interposing, '%(prog)s' does not know what compiler your
+ project normally uses. Instead, it simply overrides the CC
+ environment variable, and guesses your default compiler.
+
+ If you need '%(prog)s' to use a specific compiler for
+ *compilation* then you can use this option to specify a path
+ to that compiler.""")
+ advanced.add_argument(
+ '--use-c++',
+ metavar='<path>',
+ dest='cxx',
+ default='c++',
+ help="""This is the same as "--use-cc" but for C++ code.""")
+
+ parser.add_argument(
+ dest='build',
+ nargs=argparse.REMAINDER,
+ help="""Command to run.""")
+
+ return parser
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
new file mode 100644
index 0000000..efc0a55
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -0,0 +1,530 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to generate 'index.html' for the report.
+
+The input for this step is the output directory, where individual reports
+could be found. It parses those reports and generates 'index.html'. """
+
+import re
+import os
+import os.path
+import sys
+import shutil
+import time
+import tempfile
+import itertools
+import plistlib
+import glob
+import json
+import logging
+import contextlib
+from libscanbuild import duplicate_check
+from libscanbuild.clang import get_version
+
+__all__ = ['report_directory', 'document']
+
+
+@contextlib.contextmanager
+def report_directory(hint, keep):
+ """ Responsible for the report directory.
+
+ hint -- could specify the parent directory of the output directory.
+ keep -- a boolean value to keep or delete the empty report directory. """
+
+ stamp = time.strftime('scan-build-%Y-%m-%d-%H%M%S-', time.localtime())
+ name = tempfile.mkdtemp(prefix=stamp, dir=hint)
+
+ logging.info('Report directory created: %s', name)
+
+ try:
+ yield name
+ finally:
+ if os.listdir(name):
+ msg = "Run 'scan-view %s' to examine bug reports."
+ keep = True
+ else:
+ if keep:
+ msg = "Report directory '%s' contans no report, but kept."
+ else:
+ msg = "Removing directory '%s' because it contains no report."
+ logging.warning(msg, name)
+
+ if not keep:
+ os.rmdir(name)
+
+
+def document(args, output_dir, use_cdb):
+ """ Generates cover report and returns the number of bugs/crashes. """
+
+ html_reports_available = args.output_format in {'html', 'plist-html'}
+
+ logging.debug('count crashes and bugs')
+ crash_count = sum(1 for _ in read_crashes(output_dir))
+ bug_counter = create_counters()
+ for bug in read_bugs(output_dir, html_reports_available):
+ bug_counter(bug)
+ result = crash_count + bug_counter.total
+
+ if html_reports_available and result:
+ logging.debug('generate index.html file')
+ # common prefix for source files to have sort filenames
+ prefix = commonprefix_from(args.cdb) if use_cdb else os.getcwd()
+ # assemble the cover from multiple fragments
+ try:
+ fragments = []
+ if bug_counter.total:
+ fragments.append(bug_summary(output_dir, bug_counter))
+ fragments.append(bug_report(output_dir, prefix))
+ if crash_count:
+ fragments.append(crash_report(output_dir, prefix))
+ assemble_cover(output_dir, prefix, args, fragments)
+ # copy additinal files to the report
+ copy_resource_files(output_dir)
+ if use_cdb:
+ shutil.copy(args.cdb, output_dir)
+ finally:
+ for fragment in fragments:
+ os.remove(fragment)
+ return result
+
+
+def assemble_cover(output_dir, prefix, args, fragments):
+ """ Put together the fragments into a final report. """
+
+ import getpass
+ import socket
+ import datetime
+
+ if args.html_title is None:
+ args.html_title = os.path.basename(prefix) + ' - analyzer results'
+
+ with open(os.path.join(output_dir, 'index.html'), 'w') as handle:
+ indent = 0
+ handle.write(reindent("""
+ |<!DOCTYPE html>
+ |<html>
+ | <head>
+ | <title>{html_title}</title>
+ | <link type="text/css" rel="stylesheet" href="scanview.css"/>
+ | <script type='text/javascript' src="sorttable.js"></script>
+ | <script type='text/javascript' src='selectable.js'></script>
+ | </head>""", indent).format(html_title=args.html_title))
+ handle.write(comment('SUMMARYENDHEAD'))
+ handle.write(reindent("""
+ | <body>
+ | <h1>{html_title}</h1>
+ | <table>
+ | <tr><th>User:</th><td>{user_name}@{host_name}</td></tr>
+ | <tr><th>Working Directory:</th><td>{current_dir}</td></tr>
+ | <tr><th>Command Line:</th><td>{cmd_args}</td></tr>
+ | <tr><th>Clang Version:</th><td>{clang_version}</td></tr>
+ | <tr><th>Date:</th><td>{date}</td></tr>
+ | </table>""", indent).format(html_title=args.html_title,
+ user_name=getpass.getuser(),
+ host_name=socket.gethostname(),
+ current_dir=prefix,
+ cmd_args=' '.join(sys.argv),
+ clang_version=get_version(args.clang),
+ date=datetime.datetime.today(
+ ).strftime('%c')))
+ for fragment in fragments:
+ # copy the content of fragments
+ with open(fragment, 'r') as input_handle:
+ shutil.copyfileobj(input_handle, handle)
+ handle.write(reindent("""
+ | </body>
+ |</html>""", indent))
+
+
+def bug_summary(output_dir, bug_counter):
+ """ Bug summary is a HTML table to give a better overview of the bugs. """
+
+ name = os.path.join(output_dir, 'summary.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Bug Summary</h2>
+ |<table>
+ | <thead>
+ | <tr>
+ | <td>Bug Type</td>
+ | <td>Quantity</td>
+ | <td class="sorttable_nosort">Display?</td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ handle.write(reindent("""
+ | <tr style="font-weight:bold">
+ | <td class="SUMM_DESC">All Bugs</td>
+ | <td class="Q">{0}</td>
+ | <td>
+ | <center>
+ | <input checked type="checkbox" id="AllBugsCheck"
+ | onClick="CopyCheckedStateToCheckButtons(this);"/>
+ | </center>
+ | </td>
+ | </tr>""", indent).format(bug_counter.total))
+ for category, types in bug_counter.categories.items():
+ handle.write(reindent("""
+ | <tr>
+ | <th>{0}</th><th colspan=2></th>
+ | </tr>""", indent).format(category))
+ for bug_type in types.values():
+ handle.write(reindent("""
+ | <tr>
+ | <td class="SUMM_DESC">{bug_type}</td>
+ | <td class="Q">{bug_count}</td>
+ | <td>
+ | <center>
+ | <input checked type="checkbox"
+ | onClick="ToggleDisplay(this,'{bug_type_class}');"/>
+ | </center>
+ | </td>
+ | </tr>""", indent).format(**bug_type))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('SUMMARYBUGEND'))
+ return name
+
+
+def bug_report(output_dir, prefix):
+ """ Creates a fragment from the analyzer reports. """
+
+ pretty = prettify_bug(prefix, output_dir)
+ bugs = (pretty(bug) for bug in read_bugs(output_dir, True))
+
+ name = os.path.join(output_dir, 'bugs.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Reports</h2>
+ |<table class="sortable" style="table-layout:automatic">
+ | <thead>
+ | <tr>
+ | <td>Bug Group</td>
+ | <td class="sorttable_sorted">
+ | Bug Type
+ | <span id="sorttable_sortfwdind"> ▾</span>
+ | </td>
+ | <td>File</td>
+ | <td>Function/Method</td>
+ | <td class="Q">Line</td>
+ | <td class="Q">Path Length</td>
+ | <td class="sorttable_nosort"></td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ handle.write(comment('REPORTBUGCOL'))
+ for current in bugs:
+ handle.write(reindent("""
+ | <tr class="{bug_type_class}">
+ | <td class="DESC">{bug_category}</td>
+ | <td class="DESC">{bug_type}</td>
+ | <td>{bug_file}</td>
+ | <td class="DESC">{bug_function}</td>
+ | <td class="Q">{bug_line}</td>
+ | <td class="Q">{bug_path_length}</td>
+ | <td><a href="{report_file}#EndPath">View Report</a></td>
+ | </tr>""", indent).format(**current))
+ handle.write(comment('REPORTBUG', {'id': current['report_file']}))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('REPORTBUGEND'))
+ return name
+
+
+def crash_report(output_dir, prefix):
+ """ Creates a fragment from the compiler crashes. """
+
+ pretty = prettify_crash(prefix, output_dir)
+ crashes = (pretty(crash) for crash in read_crashes(output_dir))
+
+ name = os.path.join(output_dir, 'crashes.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Analyzer Failures</h2>
+ |<p>The analyzer had problems processing the following files:</p>
+ |<table>
+ | <thead>
+ | <tr>
+ | <td>Problem</td>
+ | <td>Source File</td>
+ | <td>Preprocessed File</td>
+ | <td>STDERR Output</td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ for current in crashes:
+ handle.write(reindent("""
+ | <tr>
+ | <td>{problem}</td>
+ | <td>{source}</td>
+ | <td><a href="{file}">preprocessor output</a></td>
+ | <td><a href="{stderr}">analyzer std err</a></td>
+ | </tr>""", indent).format(**current))
+ handle.write(comment('REPORTPROBLEM', current))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('REPORTCRASHES'))
+ return name
+
+
+def read_crashes(output_dir):
+ """ Generate a unique sequence of crashes from given output directory. """
+
+ return (parse_crash(filename)
+ for filename in glob.iglob(os.path.join(output_dir, 'failures',
+ '*.info.txt')))
+
+
+def read_bugs(output_dir, html):
+ """ Generate a unique sequence of bugs from given output directory.
+
+ Duplicates can be in a project if the same module was compiled multiple
+ times with different compiler options. These would be better to show in
+ the final report (cover) only once. """
+
+ parser = parse_bug_html if html else parse_bug_plist
+ pattern = '*.html' if html else '*.plist'
+
+ duplicate = duplicate_check(
+ lambda bug: '{bug_line}.{bug_path_length}:{bug_file}'.format(**bug))
+
+ bugs = itertools.chain.from_iterable(
+ # parser creates a bug generator not the bug itself
+ parser(filename)
+ for filename in glob.iglob(os.path.join(output_dir, pattern)))
+
+ return (bug for bug in bugs if not duplicate(bug))
+
+
+def parse_bug_plist(filename):
+ """ Returns the generator of bugs from a single .plist file. """
+
+ content = plistlib.readPlist(filename)
+ files = content.get('files')
+ for bug in content.get('diagnostics', []):
+ if len(files) <= int(bug['location']['file']):
+ logging.warning('Parsing bug from "%s" failed', filename)
+ continue
+
+ yield {
+ 'result': filename,
+ 'bug_type': bug['type'],
+ 'bug_category': bug['category'],
+ 'bug_line': int(bug['location']['line']),
+ 'bug_path_length': int(bug['location']['col']),
+ 'bug_file': files[int(bug['location']['file'])]
+ }
+
+
+def parse_bug_html(filename):
+ """ Parse out the bug information from HTML output. """
+
+ patterns = [re.compile(r'<!-- BUGTYPE (?P<bug_type>.*) -->$'),
+ re.compile(r'<!-- BUGFILE (?P<bug_file>.*) -->$'),
+ re.compile(r'<!-- BUGPATHLENGTH (?P<bug_path_length>.*) -->$'),
+ re.compile(r'<!-- BUGLINE (?P<bug_line>.*) -->$'),
+ re.compile(r'<!-- BUGCATEGORY (?P<bug_category>.*) -->$'),
+ re.compile(r'<!-- BUGDESC (?P<bug_description>.*) -->$'),
+ re.compile(r'<!-- FUNCTIONNAME (?P<bug_function>.*) -->$')]
+ endsign = re.compile(r'<!-- BUGMETAEND -->')
+
+ bug = {
+ 'report_file': filename,
+ 'bug_function': 'n/a', # compatibility with < clang-3.5
+ 'bug_category': 'Other',
+ 'bug_line': 0,
+ 'bug_path_length': 1
+ }
+
+ with open(filename) as handler:
+ for line in handler.readlines():
+ # do not read the file further
+ if endsign.match(line):
+ break
+ # search for the right lines
+ for regex in patterns:
+ match = regex.match(line.strip())
+ if match:
+ bug.update(match.groupdict())
+ break
+
+ encode_value(bug, 'bug_line', int)
+ encode_value(bug, 'bug_path_length', int)
+
+ yield bug
+
+
+def parse_crash(filename):
+ """ Parse out the crash information from the report file. """
+
+ match = re.match(r'(.*)\.info\.txt', filename)
+ name = match.group(1) if match else None
+ with open(filename) as handler:
+ lines = handler.readlines()
+ return {
+ 'source': lines[0].rstrip(),
+ 'problem': lines[1].rstrip(),
+ 'file': name,
+ 'info': name + '.info.txt',
+ 'stderr': name + '.stderr.txt'
+ }
+
+
+def category_type_name(bug):
+ """ Create a new bug attribute from bug by category and type.
+
+ The result will be used as CSS class selector in the final report. """
+
+ def smash(key):
+ """ Make value ready to be HTML attribute value. """
+
+ return bug.get(key, '').lower().replace(' ', '_').replace("'", '')
+
+ return escape('bt_' + smash('bug_category') + '_' + smash('bug_type'))
+
+
+def create_counters():
+ """ Create counters for bug statistics.
+
+ Two entries are maintained: 'total' is an integer, represents the
+ number of bugs. The 'categories' is a two level categorisation of bug
+ counters. The first level is 'bug category' the second is 'bug type'.
+ Each entry in this classification is a dictionary of 'count', 'type'
+ and 'label'. """
+
+ def predicate(bug):
+ bug_category = bug['bug_category']
+ bug_type = bug['bug_type']
+ current_category = predicate.categories.get(bug_category, dict())
+ current_type = current_category.get(bug_type, {
+ 'bug_type': bug_type,
+ 'bug_type_class': category_type_name(bug),
+ 'bug_count': 0
+ })
+ current_type.update({'bug_count': current_type['bug_count'] + 1})
+ current_category.update({bug_type: current_type})
+ predicate.categories.update({bug_category: current_category})
+ predicate.total += 1
+
+ predicate.total = 0
+ predicate.categories = dict()
+ return predicate
+
+
+def prettify_bug(prefix, output_dir):
+ def predicate(bug):
+ """ Make safe this values to embed into HTML. """
+
+ bug['bug_type_class'] = category_type_name(bug)
+
+ encode_value(bug, 'bug_file', lambda x: escape(chop(prefix, x)))
+ encode_value(bug, 'bug_category', escape)
+ encode_value(bug, 'bug_type', escape)
+ encode_value(bug, 'report_file', lambda x: escape(chop(output_dir, x)))
+ return bug
+
+ return predicate
+
+
+def prettify_crash(prefix, output_dir):
+ def predicate(crash):
+ """ Make safe this values to embed into HTML. """
+
+ encode_value(crash, 'source', lambda x: escape(chop(prefix, x)))
+ encode_value(crash, 'problem', escape)
+ encode_value(crash, 'file', lambda x: escape(chop(output_dir, x)))
+ encode_value(crash, 'info', lambda x: escape(chop(output_dir, x)))
+ encode_value(crash, 'stderr', lambda x: escape(chop(output_dir, x)))
+ return crash
+
+ return predicate
+
+
+def copy_resource_files(output_dir):
+ """ Copy the javascript and css files to the report directory. """
+
+ this_dir = os.path.dirname(os.path.realpath(__file__))
+ for resource in os.listdir(os.path.join(this_dir, 'resources')):
+ shutil.copy(os.path.join(this_dir, 'resources', resource), output_dir)
+
+
+def encode_value(container, key, encode):
+ """ Run 'encode' on 'container[key]' value and update it. """
+
+ if key in container:
+ value = encode(container[key])
+ container.update({key: value})
+
+
+def chop(prefix, filename):
+ """ Create 'filename' from '/prefix/filename' """
+
+ return filename if not len(prefix) else os.path.relpath(filename, prefix)
+
+
+def escape(text):
+ """ Paranoid HTML escape method. (Python version independent) """
+
+ escape_table = {
+ '&': '&',
+ '"': '"',
+ "'": ''',
+ '>': '>',
+ '<': '<'
+ }
+ return ''.join(escape_table.get(c, c) for c in text)
+
+
+def reindent(text, indent):
+ """ Utility function to format html output and keep indentation. """
+
+ result = ''
+ for line in text.splitlines():
+ if len(line.strip()):
+ result += ' ' * indent + line.split('|')[1] + os.linesep
+ return result
+
+
+def comment(name, opts=dict()):
+ """ Utility function to format meta information as comment. """
+
+ attributes = ''
+ for key, value in opts.items():
+ attributes += ' {0}="{1}"'.format(key, value)
+
+ return '<!-- {0}{1} -->{2}'.format(name, attributes, os.linesep)
+
+
+def commonprefix_from(filename):
+ """ Create file prefix from a compilation database entries. """
+
+ with open(filename, 'r') as handle:
+ return commonprefix(item['file'] for item in json.load(handle))
+
+
+def commonprefix(files):
+ """ Fixed version of os.path.commonprefix. Return the longest path prefix
+ that is a prefix of all paths in filenames. """
+
+ result = None
+ for current in files:
+ if result is not None:
+ result = os.path.commonprefix([result, current])
+ else:
+ result = current
+
+ if result is None:
+ return ''
+ elif not os.path.isdir(result):
+ return os.path.dirname(result)
+ else:
+ return os.path.abspath(result)
diff --git a/tools/scan-build/scanview.css b/tools/scan-build-py/libscanbuild/resources/scanview.css
similarity index 100%
copy from tools/scan-build/scanview.css
copy to tools/scan-build-py/libscanbuild/resources/scanview.css
diff --git a/tools/scan-build-py/libscanbuild/resources/selectable.js b/tools/scan-build-py/libscanbuild/resources/selectable.js
new file mode 100644
index 0000000..53f6a8d
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/resources/selectable.js
@@ -0,0 +1,47 @@
+function SetDisplay(RowClass, DisplayVal)
+{
+ var Rows = document.getElementsByTagName("tr");
+ for ( var i = 0 ; i < Rows.length; ++i ) {
+ if (Rows[i].className == RowClass) {
+ Rows[i].style.display = DisplayVal;
+ }
+ }
+}
+
+function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
+ var Inputs = document.getElementsByTagName("input");
+ for ( var i = 0 ; i < Inputs.length; ++i ) {
+ if (Inputs[i].type == "checkbox") {
+ if(Inputs[i] != SummaryCheckButton) {
+ Inputs[i].checked = SummaryCheckButton.checked;
+ Inputs[i].onclick();
+ }
+ }
+ }
+}
+
+function returnObjById( id ) {
+ if (document.getElementById)
+ var returnVar = document.getElementById(id);
+ else if (document.all)
+ var returnVar = document.all[id];
+ else if (document.layers)
+ var returnVar = document.layers[id];
+ return returnVar;
+}
+
+var NumUnchecked = 0;
+
+function ToggleDisplay(CheckButton, ClassName) {
+ if (CheckButton.checked) {
+ SetDisplay(ClassName, "");
+ if (--NumUnchecked == 0) {
+ returnObjById("AllBugsCheck").checked = true;
+ }
+ }
+ else {
+ SetDisplay(ClassName, "none");
+ NumUnchecked++;
+ returnObjById("AllBugsCheck").checked = false;
+ }
+}
diff --git a/tools/scan-build/sorttable.js b/tools/scan-build-py/libscanbuild/resources/sorttable.js
similarity index 100%
copy from tools/scan-build/sorttable.js
copy to tools/scan-build-py/libscanbuild/resources/sorttable.js
diff --git a/tools/scan-build-py/libscanbuild/runner.py b/tools/scan-build-py/libscanbuild/runner.py
new file mode 100644
index 0000000..248ca90
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/runner.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to run the analyzer commands. """
+
+import os
+import os.path
+import tempfile
+import functools
+import subprocess
+import logging
+from libscanbuild.command import classify_parameters, Action, classify_source
+from libscanbuild.clang import get_arguments, get_version
+from libscanbuild.shell import decode
+
+__all__ = ['run']
+
+
+def require(required):
+ """ Decorator for checking the required values in state.
+
+ It checks the required attributes in the passed state and stop when
+ any of those is missing. """
+
+ def decorator(function):
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+ for key in required:
+ if key not in args[0]:
+ raise KeyError(
+ '{0} not passed to {1}'.format(key, function.__name__))
+
+ return function(*args, **kwargs)
+
+ return wrapper
+
+ return decorator
+
+
+@require(['command', 'directory', 'file', # an entry from compilation database
+ 'clang', 'direct_args', # compiler name, and arguments from command
+ 'output_dir', 'output_format', 'output_failures'])
+def run(opts):
+ """ Entry point to run (or not) static analyzer against a single entry
+ of the compilation database.
+
+ This complex task is decomposed into smaller methods which are calling
+ each other in chain. If the analyzis is not possibe the given method
+ just return and break the chain.
+
+ The passed parameter is a python dictionary. Each method first check
+ that the needed parameters received. (This is done by the 'require'
+ decorator. It's like an 'assert' to check the contract between the
+ caller and the called method.) """
+
+ try:
+ command = opts.pop('command')
+ logging.debug("Run analyzer against '%s'", command)
+ opts.update(classify_parameters(decode(command)))
+
+ return action_check(opts)
+ except Exception:
+ logging.error("Problem occured during analyzis.", exc_info=1)
+ return None
+
+
+@require(['report', 'directory', 'clang', 'output_dir', 'language', 'file',
+ 'error_type', 'error_output', 'exit_code'])
+def report_failure(opts):
+ """ Create report when analyzer failed.
+
+ The major report is the preprocessor output. The output filename generated
+ randomly. The compiler output also captured into '.stderr.txt' file.
+ And some more execution context also saved into '.info.txt' file. """
+
+ def extension(opts):
+ """ Generate preprocessor file extension. """
+
+ mapping = {'objective-c++': '.mii', 'objective-c': '.mi', 'c++': '.ii'}
+ return mapping.get(opts['language'], '.i')
+
+ def destination(opts):
+ """ Creates failures directory if not exits yet. """
+
+ name = os.path.join(opts['output_dir'], 'failures')
+ if not os.path.isdir(name):
+ os.makedirs(name)
+ return name
+
+ error = opts['error_type']
+ (handle, name) = tempfile.mkstemp(suffix=extension(opts),
+ prefix='clang_' + error + '_',
+ dir=destination(opts))
+ os.close(handle)
+ cwd = opts['directory']
+ cmd = get_arguments([opts['clang']] + opts['report'] + ['-o', name], cwd)
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ subprocess.call(cmd, cwd=cwd)
+
+ with open(name + '.info.txt', 'w') as handle:
+ handle.write(opts['file'] + os.linesep)
+ handle.write(error.title().replace('_', ' ') + os.linesep)
+ handle.write(' '.join(cmd) + os.linesep)
+ handle.write(' '.join(os.uname()) + os.linesep)
+ handle.write(get_version(cmd[0]))
+ handle.close()
+
+ with open(name + '.stderr.txt', 'w') as handle:
+ handle.writelines(opts['error_output'])
+ handle.close()
+
+ return {
+ 'error_output': opts['error_output'],
+ 'exit_code': opts['exit_code']
+ }
+
+
+@require(['clang', 'analyze', 'directory', 'output'])
+def run_analyzer(opts, continuation=report_failure):
+ """ It assembles the analysis command line and executes it. Capture the
+ output of the analysis and returns with it. If failure reports are
+ requested, it calls the continuation to generate it. """
+
+ cwd = opts['directory']
+ cmd = get_arguments([opts['clang']] + opts['analyze'] + opts['output'],
+ cwd)
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ cwd=cwd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ output = child.stdout.readlines()
+ child.stdout.close()
+ # do report details if it were asked
+ child.wait()
+ if opts.get('output_failures', False) and child.returncode:
+ error_type = 'crash' if child.returncode & 127 else 'other_error'
+ opts.update({
+ 'error_type': error_type,
+ 'error_output': output,
+ 'exit_code': child.returncode
+ })
+ return continuation(opts)
+ return {'error_output': output, 'exit_code': child.returncode}
+
+
+@require(['output_dir'])
+def set_analyzer_output(opts, continuation=run_analyzer):
+ """ Create output file if was requested.
+
+ This plays a role only if .plist files are requested. """
+
+ if opts.get('output_format') in {'plist', 'plist-html'}:
+ with tempfile.NamedTemporaryFile(prefix='report-',
+ suffix='.plist',
+ delete=False,
+ dir=opts['output_dir']) as output:
+ opts.update({'output': ['-o', output.name]})
+ return continuation(opts)
+ else:
+ opts.update({'output': ['-o', opts['output_dir']]})
+ return continuation(opts)
+
+
+@require(['file', 'directory', 'clang', 'direct_args', 'language',
+ 'output_dir', 'output_format', 'output_failures'])
+def create_commands(opts, continuation=set_analyzer_output):
+ """ Create command to run analyzer or failure report generation.
+
+ It generates commands (from compilation database entries) which contains
+ enough information to run the analyzer (and the crash report generation
+ if that was requested). """
+
+ common = []
+ if 'arch' in opts:
+ common.extend(['-arch', opts.pop('arch')])
+ common.extend(opts.pop('compile_options', []))
+ common.extend(['-x', opts['language']])
+ common.append(os.path.relpath(opts['file'], opts['directory']))
+
+ opts.update({
+ 'analyze': ['--analyze'] + opts['direct_args'] + common,
+ 'report': ['-fsyntax-only', '-E'] + common
+ })
+
+ return continuation(opts)
+
+
+@require(['file', 'c++'])
+def language_check(opts, continuation=create_commands):
+ """ Find out the language from command line parameters or file name
+ extension. The decision also influenced by the compiler invocation. """
+
+ accepteds = {
+ 'c', 'c++', 'objective-c', 'objective-c++', 'c-cpp-output',
+ 'c++-cpp-output', 'objective-c-cpp-output'
+ }
+
+ key = 'language'
+ language = opts[key] if key in opts else \
+ classify_source(opts['file'], opts['c++'])
+
+ if language is None:
+ logging.debug('skip analysis, language not known')
+ return None
+ elif language not in accepteds:
+ logging.debug('skip analysis, language not supported')
+ return None
+ else:
+ logging.debug('analysis, language: %s', language)
+ opts.update({key: language})
+ return continuation(opts)
+
+
+@require([])
+def arch_check(opts, continuation=language_check):
+ """ Do run analyzer through one of the given architectures. """
+
+ disableds = {'ppc', 'ppc64'}
+
+ key = 'archs_seen'
+ if key in opts:
+ # filter out disabled architectures and -arch switches
+ archs = [a for a in opts[key] if a not in disableds]
+
+ if not archs:
+ logging.debug('skip analysis, found not supported arch')
+ return None
+ else:
+ # There should be only one arch given (or the same multiple
+ # times). If there are multiple arch are given and are not
+ # the same, those should not change the pre-processing step.
+ # But that's the only pass we have before run the analyzer.
+ arch = archs.pop()
+ logging.debug('analysis, on arch: %s', arch)
+
+ opts.update({'arch': arch})
+ del opts[key]
+ return continuation(opts)
+ else:
+ logging.debug('analysis, on default arch')
+ return continuation(opts)
+
+
+@require(['action'])
+def action_check(opts, continuation=arch_check):
+ """ Continue analysis only if it compilation or link. """
+
+ if opts.pop('action') <= Action.Compile:
+ return continuation(opts)
+ else:
+ logging.debug('skip analysis, not compilation nor link')
+ return None
diff --git a/tools/scan-build-py/libscanbuild/shell.py b/tools/scan-build-py/libscanbuild/shell.py
new file mode 100644
index 0000000..a575946
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/shell.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module implements basic shell escaping/unescaping methods. """
+
+import re
+import shlex
+
+__all__ = ['encode', 'decode']
+
+
+def encode(command):
+ """ Takes a command as list and returns a string. """
+
+ def needs_quote(word):
+ """ Returns true if arguments needs to be protected by quotes.
+
+ Previous implementation was shlex.split method, but that's not good
+ for this job. Currently is running through the string with a basic
+ state checking. """
+
+ reserved = {' ', '$', '%', '&', '(', ')', '[', ']', '{', '}', '*', '|',
+ '<', '>', '@', '?', '!'}
+ state = 0
+ for current in word:
+ if state == 0 and current in reserved:
+ return True
+ elif state == 0 and current == '\\':
+ state = 1
+ elif state == 1 and current in reserved | {'\\'}:
+ state = 0
+ elif state == 0 and current == '"':
+ state = 2
+ elif state == 2 and current == '"':
+ state = 0
+ elif state == 0 and current == "'":
+ state = 3
+ elif state == 3 and current == "'":
+ state = 0
+ return state != 0
+
+ def escape(word):
+ """ Do protect argument if that's needed. """
+
+ table = {'\\': '\\\\', '"': '\\"'}
+ escaped = ''.join([table.get(c, c) for c in word])
+
+ return '"' + escaped + '"' if needs_quote(word) else escaped
+
+ return " ".join([escape(arg) for arg in command])
+
+
+def decode(string):
+ """ Takes a command string and returns as a list. """
+
+ def unescape(arg):
+ """ Gets rid of the escaping characters. """
+
+ if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"':
+ arg = arg[1:-1]
+ return re.sub(r'\\(["\\])', r'\1', arg)
+ return re.sub(r'\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])', r'\1', arg)
+
+ return [unescape(arg) for arg in shlex.split(string)]
diff --git a/tools/scan-build-py/tests/__init__.py b/tools/scan-build-py/tests/__init__.py
new file mode 100644
index 0000000..bde2376
--- /dev/null
+++ b/tools/scan-build-py/tests/__init__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import unittest
+
+import tests.unit
+import tests.functional.cases
+
+
+def suite():
+ loader = unittest.TestLoader()
+ suite = unittest.TestSuite()
+ suite.addTests(loader.loadTestsFromModule(tests.unit))
+ suite.addTests(loader.loadTestsFromModule(tests.functional.cases))
+ return suite
diff --git a/tools/scan-view/Resources/GetRadarVersion.scpt b/tools/scan-build-py/tests/functional/__init__.py
similarity index 100%
copy from tools/scan-view/Resources/GetRadarVersion.scpt
copy to tools/scan-build-py/tests/functional/__init__.py
diff --git a/tools/scan-build-py/tests/functional/cases/__init__.py b/tools/scan-build-py/tests/functional/cases/__init__.py
new file mode 100644
index 0000000..8fb8465
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/__init__.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import re
+import os.path
+import subprocess
+
+
+def load_tests(loader, suite, pattern):
+ from . import test_from_cdb
+ suite.addTests(loader.loadTestsFromModule(test_from_cdb))
+ from . import test_from_cmd
+ suite.addTests(loader.loadTestsFromModule(test_from_cmd))
+ from . import test_create_cdb
+ suite.addTests(loader.loadTestsFromModule(test_create_cdb))
+ from . import test_exec_anatomy
+ suite.addTests(loader.loadTestsFromModule(test_exec_anatomy))
+ return suite
+
+
+def make_args(target):
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
+ os.path.join(path, 'build', 'Makefile')]
+
+
+def silent_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.call(cmd, *args, **kwargs)
+
+
+def silent_check_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.check_call(cmd, *args, **kwargs)
+
+
+def call_and_report(analyzer_cmd, build_cmd):
+ child = subprocess.Popen(analyzer_cmd + ['-v'] + build_cmd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ pattern = re.compile('Report directory created: (.+)')
+ directory = None
+ for line in child.stdout.readlines():
+ match = pattern.search(line)
+ if match and match.lastindex == 1:
+ directory = match.group(1)
+ break
+ child.stdout.close()
+ child.wait()
+
+ return (child.returncode, directory)
+
+
+def check_call_and_report(analyzer_cmd, build_cmd):
+ exit_code, result = call_and_report(analyzer_cmd, build_cmd)
+ if exit_code != 0:
+ raise subprocess.CalledProcessError(
+ exit_code, analyzer_cmd + build_cmd, None)
+ else:
+ return result
+
+
+def create_empty_file(filename):
+ with open(filename, 'a') as handle:
+ pass
diff --git a/tools/scan-build-py/tests/functional/cases/test_create_cdb.py b/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
new file mode 100644
index 0000000..6d449ba
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import make_args, silent_check_call, silent_call, create_empty_file
+import unittest
+
+import os.path
+import json
+
+
+class CompilationDatabaseTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + args
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_with_wrapper(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ '--override-compiler'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu make return -11')
+ def test_successful_build_parallel(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['-j', '4', 'build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu env remove clang from path')
+ def test_successful_build_on_empty_env(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['CC=clang', 'build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ 'env', '-'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_all_in_one(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_all_in_one'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_not_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_broken']
+ silent_call(
+ ['intercept-build', '--cdb', result] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+
+class ExitCodeTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ return silent_call(
+ ['intercept-build', '--cdb', result] + make)
+
+ def test_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_clean')
+ self.assertFalse(exitcode)
+
+ def test_not_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_broken')
+ self.assertTrue(exitcode)
+
+
+class ResumeFeatureTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + args + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_overwrite_existing_cdb(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', [])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+ def test_append_to_existing_cdb(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', ['--append'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+
+class ResultFormatingTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, command):
+ result = os.path.join(tmpdir, 'cdb.json')
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + command,
+ cwd=tmpdir)
+ with open(result, 'r') as handler:
+ content = json.load(handler)
+ return content
+
+ def assert_creates_number_of_entries(self, command, count):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ create_empty_file(filename)
+ command.append(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(count, len(cdb))
+
+ def test_filter_preprocessor_only_calls(self):
+ self.assert_creates_number_of_entries(['cc', '-c'], 1)
+ self.assert_creates_number_of_entries(['cc', '-c', '-E'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-M'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-MM'], 0)
+
+ def assert_command_creates_entry(self, command, expected):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, command[-1])
+ create_empty_file(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(' '.join(expected), cdb[0]['command'])
+
+ def test_filter_preprocessor_flags(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MMD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', '-MF', 'test.d', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_language_flag(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-x', 'c', 'test.c'],
+ ['cc', '-c', '-x', 'c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_arch_flags(self):
+ self.assert_command_creates_entry(
+ ['clang', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'])
diff --git a/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py b/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
new file mode 100644
index 0000000..329a477
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+import unittest
+
+import os.path
+import subprocess
+import json
+
+
+def run(source_dir, target_dir):
+ def execute(cmd):
+ return subprocess.check_call(cmd,
+ cwd=target_dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ execute(['cmake', source_dir])
+ execute(['make'])
+
+ result_file = os.path.join(target_dir, 'result.json')
+ expected_file = os.path.join(target_dir, 'expected.json')
+ execute(['intercept-build', '--cdb', result_file, './exec',
+ expected_file])
+ return (expected_file, result_file)
+
+
+class ExecAnatomyTest(unittest.TestCase):
+ def assertEqualJson(self, expected, result):
+ def read_json(filename):
+ with open(filename) as handler:
+ return json.load(handler)
+
+ lhs = read_json(expected)
+ rhs = read_json(result)
+ for item in lhs:
+ self.assertTrue(rhs.count(item))
+ for item in rhs:
+ self.assertTrue(lhs.count(item))
+
+ def test_all_exec_calls(self):
+ this_dir, _ = os.path.split(__file__)
+ source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
+ with fixtures.TempDir() as tmp_dir:
+ expected, result = run(source_dir, tmp_dir)
+ self.assertEqualJson(expected, result)
diff --git a/tools/scan-build-py/tests/functional/cases/test_from_cdb.py b/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
new file mode 100644
index 0000000..c579020
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import call_and_report
+import unittest
+
+import os.path
+import string
+import subprocess
+import glob
+
+
+def prepare_cdb(name, target_dir):
+ target_file = 'build_{0}.json'.format(name)
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ source_dir = os.path.join(path, 'compilation_database')
+ source_file = os.path.join(source_dir, target_file + '.in')
+ target_file = os.path.join(target_dir, 'compile_commands.json')
+ with open(source_file, 'r') as in_handle:
+ with open(target_file, 'w') as out_handle:
+ for line in in_handle:
+ temp = string.Template(line)
+ out_handle.write(temp.substitute(path=path))
+ return target_file
+
+
+def run_analyzer(directory, cdb, args):
+ cmd = ['analyze-build', '--cdb', cdb, '--output', directory] \
+ + args
+ return call_and_report(cmd, [])
+
+
+class OutputDirectoryTest(unittest.TestCase):
+ def test_regular_keeps_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(os.path.isdir(reportdir))
+
+ def test_clear_deletes_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(os.path.isdir(reportdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--keep-empty'])
+ self.assertTrue(os.path.isdir(reportdir))
+
+
+class ExitCodeTest(unittest.TestCase):
+ def test_regular_does_not_set_exit_code(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_clear_does_not_set_exit_code(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked_from_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked_from_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertFalse(exit_code)
+
+
+class OutputFormatTest(unittest.TestCase):
+ @staticmethod
+ def get_html_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.html')))
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_default_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 0)
+
+ def test_plist_and_html_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist-html'])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+ def test_plist_does_not_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist'])
+ self.assertFalse(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 0)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+
+class FailureReportTest(unittest.TestCase):
+ def test_broken_creates_failure_reports(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+ def test_broken_does_not_creates_failure_reports(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--no-failure-reports'])
+ self.assertFalse(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+
+class TitleTest(unittest.TestCase):
+ def assertTitleEqual(self, directory, expected):
+ import re
+ patterns = [
+ re.compile(r'<title>(?P<page>.*)</title>'),
+ re.compile(r'<h1>(?P<head>.*)</h1>')
+ ]
+ result = dict()
+
+ index = os.path.join(directory, 'index.html')
+ with open(index, 'r') as handler:
+ for line in handler.readlines():
+ for regex in patterns:
+ match = regex.match(line.strip())
+ if match:
+ result.update(match.groupdict())
+ break
+ self.assertEqual(result['page'], result['head'])
+ self.assertEqual(result['page'], expected)
+
+ def test_default_title_in_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTitleEqual(reportdir, 'src - analyzer results')
+
+ def test_given_title_in_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--html-title', 'this is the title'])
+ self.assertTitleEqual(reportdir, 'this is the title')
diff --git a/tools/scan-build-py/tests/functional/cases/test_from_cmd.py b/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
new file mode 100644
index 0000000..fe7ecf6
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
@@ -0,0 +1,118 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import make_args, check_call_and_report, create_empty_file
+import unittest
+
+import os
+import os.path
+import glob
+
+
+class OutputDirectoryTest(unittest.TestCase):
+
+ @staticmethod
+ def run_analyzer(outdir, args, cmd):
+ return check_call_and_report(
+ ['scan-build', '--intercept-first', '-o', outdir] + args,
+ cmd)
+
+ def test_regular_keeps_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+ def test_clear_deletes_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertFalse(os.path.isdir(outdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, ['--keep-empty'], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_interposition_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_wrapper_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
+ '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_library_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ @staticmethod
+ def compile_empty_source_file(target_dir, is_cxx):
+ compiler = '$CXX' if is_cxx else '$CC'
+ src_file_name = 'test.cxx' if is_cxx else 'test.c'
+ src_file = os.path.join(target_dir, src_file_name)
+ obj_file = os.path.join(target_dir, 'test.o')
+ create_empty_file(src_file)
+ command = ' '.join([compiler, '-c', src_file, '-o', obj_file])
+ return ['sh', '-c', command]
+
+ def test_interposition_cc_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_interposition_cxx_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cc_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cxx_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
diff --git a/tools/scan-build-py/tests/functional/exec/CMakeLists.txt b/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
new file mode 100644
index 0000000..6e5d2e9
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
@@ -0,0 +1,32 @@
+project(exec C)
+
+cmake_minimum_required(VERSION 2.8)
+
+include(CheckCCompilerFlag)
+check_c_compiler_flag("-std=c99" C99_SUPPORTED)
+if (C99_SUPPORTED)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+endif()
+
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+
+add_definitions(-D_GNU_SOURCE)
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+
+check_function_exists(execve HAVE_EXECVE)
+check_function_exists(execv HAVE_EXECV)
+check_function_exists(execvpe HAVE_EXECVPE)
+check_function_exists(execvp HAVE_EXECVP)
+check_function_exists(execvP HAVE_EXECVP2)
+check_function_exists(exect HAVE_EXECT)
+check_function_exists(execl HAVE_EXECL)
+check_function_exists(execlp HAVE_EXECLP)
+check_function_exists(execle HAVE_EXECLE)
+check_function_exists(posix_spawn HAVE_POSIX_SPAWN)
+check_function_exists(posix_spawnp HAVE_POSIX_SPAWNP)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_executable(exec main.c)
diff --git a/tools/scan-build-py/tests/functional/exec/config.h.in b/tools/scan-build-py/tests/functional/exec/config.h.in
new file mode 100644
index 0000000..6221083
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/config.h.in
@@ -0,0 +1,20 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#pragma once
+
+#cmakedefine HAVE_EXECVE
+#cmakedefine HAVE_EXECV
+#cmakedefine HAVE_EXECVPE
+#cmakedefine HAVE_EXECVP
+#cmakedefine HAVE_EXECVP2
+#cmakedefine HAVE_EXECT
+#cmakedefine HAVE_EXECL
+#cmakedefine HAVE_EXECLP
+#cmakedefine HAVE_EXECLE
+#cmakedefine HAVE_POSIX_SPAWN
+#cmakedefine HAVE_POSIX_SPAWNP
diff --git a/tools/scan-build-py/tests/functional/exec/main.c b/tools/scan-build-py/tests/functional/exec/main.c
new file mode 100644
index 0000000..830cf37
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/main.c
@@ -0,0 +1,307 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#include "config.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+// ..:: environment access fixer - begin ::..
+#ifdef HAVE_NSGETENVIRON
+#include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+char **get_environ() {
+#ifdef HAVE_NSGETENVIRON
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+}
+// ..:: environment access fixer - end ::..
+
+// ..:: test fixtures - begin ::..
+static char const *cwd = NULL;
+static FILE *fd = NULL;
+static int need_comma = 0;
+
+void expected_out_open(const char *expected) {
+ cwd = getcwd(NULL, 0);
+ fd = fopen(expected, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "[\n");
+ need_comma = 0;
+}
+
+void expected_out_close() {
+ fprintf(fd, "]\n");
+ fclose(fd);
+ fd = NULL;
+
+ free((void *)cwd);
+ cwd = NULL;
+}
+
+void expected_out(const char *file) {
+ if (need_comma)
+ fprintf(fd, ",\n");
+ else
+ need_comma = 1;
+
+ fprintf(fd, "{\n");
+ fprintf(fd, " \"directory\": \"%s\",\n", cwd);
+ fprintf(fd, " \"command\": \"cc -c %s\",\n", file);
+ fprintf(fd, " \"file\": \"%s/%s\"\n", cwd, file);
+ fprintf(fd, "}\n");
+}
+
+void create_source(char *file) {
+ FILE *fd = fopen(file, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "typedef int score;\n");
+ fclose(fd);
+}
+
+typedef void (*exec_fun)();
+
+void wait_for(pid_t child) {
+ int status;
+ if (-1 == waitpid(child, &status, 0)) {
+ perror("wait");
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE) {
+ fprintf(stderr, "children process has non zero exit code\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+#define FORK(FUNC) \
+ { \
+ pid_t child = fork(); \
+ if (-1 == child) { \
+ perror("fork"); \
+ exit(EXIT_FAILURE); \
+ } else if (0 == child) { \
+ FUNC fprintf(stderr, "children process failed to exec\n"); \
+ exit(EXIT_FAILURE); \
+ } else { \
+ wait_for(child); \
+ } \
+ }
+// ..:: test fixtures - end ::..
+
+#ifdef HAVE_EXECV
+void call_execv() {
+ char *const file = "execv.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {"cc", "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execv(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVE
+void call_execve() {
+ char *const file = "execve.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execve(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECVP
+void call_execvp() {
+ char *const file = "execvp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvp(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+void call_execvP() {
+ char *const file = "execv_p.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvP(compiler, _PATH_DEFPATH, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+void call_execvpe() {
+ char *const file = "execvpe.c";
+ char *const compiler = "cc";
+ char *const argv[] = {"/usr/bin/cc", "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvpe(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECT
+void call_exect() {
+ char *const file = "exect.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(exect(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECL
+void call_execl() {
+ char *const file = "execl.c";
+ char *const compiler = "/usr/bin/cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execl(compiler, "cc", "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLP
+void call_execlp() {
+ char *const file = "execlp.c";
+ char *const compiler = "cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execlp(compiler, compiler, "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLE
+void call_execle() {
+ char *const file = "execle.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execle(compiler, compiler, "-c", file, (char *)0, envp);)
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+void call_posix_spawn() {
+ char *const file = "posix_spawn.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawn(&child, "/usr/bin/cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawn");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+void call_posix_spawnp() {
+ char *const file = "posix_spawnp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawnp(&child, "cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawnp");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+int main(int argc, char *const argv[]) {
+ if (argc != 2)
+ exit(EXIT_FAILURE);
+
+ expected_out_open(argv[1]);
+#ifdef HAVE_EXECV
+ call_execv();
+#endif
+#ifdef HAVE_EXECVE
+ call_execve();
+#endif
+#ifdef HAVE_EXECVP
+ call_execvp();
+#endif
+#ifdef HAVE_EXECVP2
+ call_execvP();
+#endif
+#ifdef HAVE_EXECVPE
+ call_execvpe();
+#endif
+#ifdef HAVE_EXECT
+ call_exect();
+#endif
+#ifdef HAVE_EXECL
+ call_execl();
+#endif
+#ifdef HAVE_EXECLP
+ call_execlp();
+#endif
+#ifdef HAVE_EXECLE
+ call_execle();
+#endif
+#ifdef HAVE_POSIX_SPAWN
+ call_posix_spawn();
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+ call_posix_spawnp();
+#endif
+ expected_out_close();
+ return 0;
+}
diff --git a/tools/scan-build-py/tests/functional/src/broken-one.c b/tools/scan-build-py/tests/functional/src/broken-one.c
new file mode 100644
index 0000000..f055023
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/broken-one.c
@@ -0,0 +1,6 @@
+#include <notexisting.hpp>
+
+int value(int in)
+{
+ return 2 * in;
+}
diff --git a/tools/scan-build-py/tests/functional/src/broken-two.c b/tools/scan-build-py/tests/functional/src/broken-two.c
new file mode 100644
index 0000000..7b4c12f
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/broken-two.c
@@ -0,0 +1 @@
+int test() { ;
diff --git a/tools/scan-build-py/tests/functional/src/build/Makefile b/tools/scan-build-py/tests/functional/src/build/Makefile
new file mode 100644
index 0000000..a8c0aaf
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/build/Makefile
@@ -0,0 +1,42 @@
+SRCDIR := ..
+OBJDIR := .
+
+CFLAGS = -Wall -DDEBUG -Dvariable="value with space" -I $(SRCDIR)/include
+LDFLAGS =
+PROGRAM = $(OBJDIR)/prg
+
+$(OBJDIR)/main.o: $(SRCDIR)/main.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/main.c
+
+$(OBJDIR)/clean-one.o: $(SRCDIR)/clean-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-one.c
+
+$(OBJDIR)/clean-two.o: $(SRCDIR)/clean-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-two.c
+
+$(OBJDIR)/emit-one.o: $(SRCDIR)/emit-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-one.c
+
+$(OBJDIR)/emit-two.o: $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-two.c
+
+$(OBJDIR)/broken-one.o: $(SRCDIR)/broken-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-one.c
+
+$(OBJDIR)/broken-two.o: $(SRCDIR)/broken-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-two.c
+
+$(PROGRAM): $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+ $(CC) $(LDFLAGS) -o $@ $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+
+build_regular: $(PROGRAM)
+
+build_clean: $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o
+
+build_broken: $(OBJDIR)/main.o $(OBJDIR)/broken-one.o $(OBJDIR)/broken-two.o
+
+build_all_in_one: $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+
+clean:
+ rm -f $(PROGRAM) $(OBJDIR)/*.o
diff --git a/tools/scan-build-py/tests/functional/src/clean-one.c b/tools/scan-build-py/tests/functional/src/clean-one.c
new file mode 100644
index 0000000..08c5f33
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/clean-one.c
@@ -0,0 +1,13 @@
+#include <clean-one.h>
+
+int do_nothing_loop()
+{
+ int i = 32;
+ int idx = 0;
+
+ for (idx = i; idx > 0; --idx)
+ {
+ i += idx;
+ }
+ return i;
+}
diff --git a/tools/scan-build-py/tests/functional/src/clean-two.c b/tools/scan-build-py/tests/functional/src/clean-two.c
new file mode 100644
index 0000000..73bc288
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/clean-two.c
@@ -0,0 +1,11 @@
+#include <clean-one.h>
+
+#include <stdlib.h>
+
+unsigned int another_method()
+{
+ unsigned int const size = do_nothing_loop();
+ unsigned int const square = size * size;
+
+ return square;
+}
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
new file mode 100644
index 0000000..104a419
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
@@ -0,0 +1,43 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o broken-one.o broken-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/broken-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o broken-two.o broken-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/broken-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
new file mode 100644
index 0000000..aa4dcde
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
@@ -0,0 +1,19 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
new file mode 100644
index 0000000..0200c1d
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
@@ -0,0 +1,31 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/emit-one.c b/tools/scan-build-py/tests/functional/src/emit-one.c
new file mode 100644
index 0000000..6cbd9ce
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/emit-one.c
@@ -0,0 +1,23 @@
+#include <assert.h>
+
+int div(int numerator, int denominator)
+{
+ return numerator / denominator;
+}
+
+void div_test()
+{
+ int i = 0;
+ for (i = 0; i < 2; ++i)
+ assert(div(2 * i, i) == 2);
+}
+
+int do_nothing()
+{
+ unsigned int i = 0;
+
+ int k = 100;
+ int j = k + 1;
+
+ return j;
+}
diff --git a/tools/scan-build-py/tests/functional/src/emit-two.c b/tools/scan-build-py/tests/functional/src/emit-two.c
new file mode 100644
index 0000000..faea771
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/emit-two.c
@@ -0,0 +1,13 @@
+
+int bad_guy(int * i)
+{
+ *i = 9;
+ return *i;
+}
+
+void bad_guy_test()
+{
+ int * ptr = 0;
+
+ bad_guy(ptr);
+}
diff --git a/tools/scan-build-py/tests/functional/src/include/clean-one.h b/tools/scan-build-py/tests/functional/src/include/clean-one.h
new file mode 100644
index 0000000..695dbd0
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/include/clean-one.h
@@ -0,0 +1,6 @@
+#ifndef CLEAN_ONE_H
+#define CLEAN_ONE_H
+
+int do_nothing_loop();
+
+#endif
diff --git a/tools/scan-build-py/tests/functional/src/main.c b/tools/scan-build-py/tests/functional/src/main.c
new file mode 100644
index 0000000..905869d
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/tools/scan-build-py/tests/unit/__init__.py b/tools/scan-build-py/tests/unit/__init__.py
new file mode 100644
index 0000000..4fa9edc
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from . import test_command
+from . import test_clang
+from . import test_runner
+from . import test_report
+from . import test_analyze
+from . import test_intercept
+from . import test_shell
+
+
+def load_tests(loader, suite, pattern):
+ suite.addTests(loader.loadTestsFromModule(test_command))
+ suite.addTests(loader.loadTestsFromModule(test_clang))
+ suite.addTests(loader.loadTestsFromModule(test_runner))
+ suite.addTests(loader.loadTestsFromModule(test_report))
+ suite.addTests(loader.loadTestsFromModule(test_analyze))
+ suite.addTests(loader.loadTestsFromModule(test_intercept))
+ suite.addTests(loader.loadTestsFromModule(test_shell))
+ return suite
diff --git a/tools/scan-build-py/tests/unit/fixtures.py b/tools/scan-build-py/tests/unit/fixtures.py
new file mode 100644
index 0000000..d80f5e6
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/fixtures.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import contextlib
+import tempfile
+import shutil
+import unittest
+
+
+class Spy(object):
+ def __init__(self):
+ self.arg = None
+ self.success = 0
+
+ def call(self, params):
+ self.arg = params
+ return self.success
+
+
+@contextlib.contextmanager
+def TempDir():
+ name = tempfile.mkdtemp(prefix='scan-build-test-')
+ try:
+ yield name
+ finally:
+ shutil.rmtree(name)
+
+
+class TestCase(unittest.TestCase):
+ def assertIn(self, element, collection):
+ found = False
+ for it in collection:
+ if element == it:
+ found = True
+
+ self.assertTrue(found, '{0} does not have {1}'.format(collection,
+ element))
diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py
new file mode 100644
index 0000000..b77db48
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_analyze.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.analyze as sut
+from . import fixtures
diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py
new file mode 100644
index 0000000..2f1fd79
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_clang.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.clang as sut
+from . import fixtures
+import os.path
+
+
+class GetClangArgumentsTest(fixtures.TestCase):
+ def test_get_clang_arguments(self):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('')
+
+ result = sut.get_arguments(
+ ['clang', '-c', filename, '-DNDEBUG', '-Dvar="this is it"'],
+ tmpdir)
+
+ self.assertIn('NDEBUG', result)
+ self.assertIn('var="this is it"', result)
+
+ def test_get_clang_arguments_fails(self):
+ self.assertRaises(
+ Exception, sut.get_arguments,
+ ['clang', '-###', '-fsyntax-only', '-x', 'c', 'notexist.c'], '.')
+
+
+class GetCheckersTest(fixtures.TestCase):
+ def test_get_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_checkers('clang', [])
+ self.assertTrue(len(result))
+
+ def test_get_active_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_active_checkers('clang', [])
+ self.assertTrue(len(result))
diff --git a/tools/scan-build-py/tests/unit/test_command.py b/tools/scan-build-py/tests/unit/test_command.py
new file mode 100644
index 0000000..9a6aae6
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_command.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.command as sut
+from . import fixtures
+import unittest
+
+
+class ParseTest(unittest.TestCase):
+
+ def test_action(self):
+ def test(expected, cmd):
+ opts = sut.classify_parameters(cmd)
+ self.assertEqual(expected, opts['action'])
+
+ Link = sut.Action.Link
+ test(Link, ['clang', 'source.c'])
+
+ Compile = sut.Action.Compile
+ test(Compile, ['clang', '-c', 'source.c'])
+ test(Compile, ['clang', '-c', 'source.c', '-MF', 'source.d'])
+
+ Preprocess = sut.Action.Ignored
+ test(Preprocess, ['clang', '-E', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-E', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-M', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-MM', 'source.c'])
+
+ def test_optimalizations(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ self.assertEqual(['-O'], test(['clang', '-c', 'source.c', '-O']))
+ self.assertEqual(['-O1'], test(['clang', '-c', 'source.c', '-O1']))
+ self.assertEqual(['-Os'], test(['clang', '-c', 'source.c', '-Os']))
+ self.assertEqual(['-O2'], test(['clang', '-c', 'source.c', '-O2']))
+ self.assertEqual(['-O3'], test(['clang', '-c', 'source.c', '-O3']))
+
+ def test_language(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('language')
+
+ self.assertEqual(None, test(['clang', '-c', 'source.c']))
+ self.assertEqual('c', test(['clang', '-c', 'source.c', '-x', 'c']))
+ self.assertEqual('cpp', test(['clang', '-c', 'source.c', '-x', 'cpp']))
+
+ def test_output(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('output')
+
+ self.assertEqual(None, test(['clang', '-c', 'source.c']))
+ self.assertEqual('source.o',
+ test(['clang', '-c', '-o', 'source.o', 'source.c']))
+
+ def test_arch(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('archs_seen', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'source.c']))
+ eq(['mips'],
+ test(['clang', '-c', 'source.c', '-arch', 'mips']))
+ eq(['mips', 'i386'],
+ test(['clang', '-c', 'source.c', '-arch', 'mips', '-arch', 'i386']))
+
+ def test_input_file(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('files', [])
+
+ eq = self.assertEqual
+
+ eq(['src.c'], test(['clang', 'src.c']))
+ eq(['src.c'], test(['clang', '-c', 'src.c']))
+ eq(['s1.c', 's2.c'], test(['clang', '-c', 's1.c', 's2.c']))
+
+ def test_include(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'src.c']))
+ eq(['-include', '/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-include', '/usr/local/include']))
+ eq(['-I.'],
+ test(['clang', '-c', 'src.c', '-I.']))
+ eq(['-I', '.'],
+ test(['clang', '-c', 'src.c', '-I', '.']))
+ eq(['-I/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-I/usr/local/include']))
+ eq(['-I', '/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-I', '/usr/local/include']))
+ eq(['-I/opt', '-I', '/opt/otp/include'],
+ test(['clang', '-c', 'src.c', '-I/opt', '-I', '/opt/otp/include']))
+ eq(['-isystem', '/path'],
+ test(['clang', '-c', 'src.c', '-isystem', '/path']))
+ eq(['-isystem=/path'],
+ test(['clang', '-c', 'src.c', '-isystem=/path']))
+
+ def test_define(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'src.c']))
+ eq(['-DNDEBUG'],
+ test(['clang', '-c', 'src.c', '-DNDEBUG']))
+ eq(['-UNDEBUG'],
+ test(['clang', '-c', 'src.c', '-UNDEBUG']))
+ eq(['-Dvar1=val1', '-Dvar2=val2'],
+ test(['clang', '-c', 'src.c', '-Dvar1=val1', '-Dvar2=val2']))
+ eq(['-Dvar="val ues"'],
+ test(['clang', '-c', 'src.c', '-Dvar="val ues"']))
+
+ def test_ignored_flags(self):
+ def test(flags):
+ cmd = ['clang', 'src.o']
+ opts = sut.classify_parameters(cmd + flags)
+ self.assertEqual(['src.o'], opts.get('compile_options'))
+
+ test([])
+ test(['-lrt', '-L/opt/company/lib'])
+ test(['-static'])
+ test(['-Wnoexcept', '-Wall'])
+ test(['-mtune=i386', '-mcpu=i386'])
+
+ def test_compile_only_flags(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq(['-std=C99'],
+ test(['clang', '-c', 'src.c', '-std=C99']))
+ eq(['-nostdinc'],
+ test(['clang', '-c', 'src.c', '-nostdinc']))
+ eq(['-isystem', '/image/debian'],
+ test(['clang', '-c', 'src.c', '-isystem', '/image/debian']))
+ eq(['-iprefix', '/usr/local'],
+ test(['clang', '-c', 'src.c', '-iprefix', '/usr/local']))
+ eq(['-iquote=me'],
+ test(['clang', '-c', 'src.c', '-iquote=me']))
+ eq(['-iquote', 'me'],
+ test(['clang', '-c', 'src.c', '-iquote', 'me']))
+
+ def test_compile_and_link_flags(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq(['-fsinged-char'],
+ test(['clang', '-c', 'src.c', '-fsinged-char']))
+ eq(['-fPIC'],
+ test(['clang', '-c', 'src.c', '-fPIC']))
+ eq(['-stdlib=libc++'],
+ test(['clang', '-c', 'src.c', '-stdlib=libc++']))
+ eq(['--sysroot', '/'],
+ test(['clang', '-c', 'src.c', '--sysroot', '/']))
+ eq(['-isysroot', '/'],
+ test(['clang', '-c', 'src.c', '-isysroot', '/']))
+ eq([],
+ test(['clang', '-c', 'src.c', '-fsyntax-only']))
+ eq([],
+ test(['clang', '-c', 'src.c', '-sectorder', 'a', 'b', 'c']))
+
+ def test_detect_cxx_from_compiler_name(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('c++')
+
+ eq = self.assertEqual
+
+ eq(False, test(['cc', '-c', 'src.c']))
+ eq(True, test(['c++', '-c', 'src.c']))
+ eq(False, test(['clang', '-c', 'src.c']))
+ eq(True, test(['clang++', '-c', 'src.c']))
+ eq(False, test(['gcc', '-c', 'src.c']))
+ eq(True, test(['g++', '-c', 'src.c']))
diff --git a/tools/scan-build-py/tests/unit/test_intercept.py b/tools/scan-build-py/tests/unit/test_intercept.py
new file mode 100644
index 0000000..b6f01f3
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_intercept.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.intercept as sut
+from . import fixtures
+import os.path
+
+
+class InterceptUtilTest(fixtures.TestCase):
+
+ def test_is_compiler_call_filter(self):
+ def test(command):
+ return sut.is_compiler_call({'command': [command]})
+
+ self.assertTrue(test('clang'))
+ self.assertTrue(test('clang-3.6'))
+ self.assertTrue(test('clang++'))
+ self.assertTrue(test('clang++-3.5.1'))
+ self.assertTrue(test('cc'))
+ self.assertTrue(test('c++'))
+ self.assertTrue(test('gcc'))
+ self.assertTrue(test('g++'))
+ self.assertTrue(test('/usr/local/bin/gcc'))
+ self.assertTrue(test('/usr/local/bin/g++'))
+ self.assertTrue(test('/usr/local/bin/clang'))
+ self.assertTrue(test('armv7_neno-linux-gnueabi-g++'))
+
+ self.assertFalse(test(''))
+ self.assertFalse(test('ld'))
+ self.assertFalse(test('as'))
+ self.assertFalse(test('/usr/local/bin/compiler'))
+
+ def test_format_entry_filters_action(self):
+ def test(command):
+ return list(sut.format_entry(
+ {'command': command, 'directory': '/opt/src/project'}))
+
+ self.assertTrue(test(['cc', '-c', 'file.c', '-o', 'file.o']))
+ self.assertFalse(test(['cc', '-E', 'file.c']))
+ self.assertFalse(test(['cc', '-MM', 'file.c']))
+ self.assertFalse(test(['cc', 'this.o', 'that.o', '-o', 'a.out']))
+ self.assertFalse(test(['cc', '-print-prog-name']))
+
+ def test_format_entry_normalize_filename(self):
+ directory = os.path.join(os.sep, 'home', 'me', 'project')
+
+ def test(command):
+ result = list(sut.format_entry(
+ {'command': command, 'directory': directory}))
+ return result[0]['file']
+
+ self.assertEqual(test(['cc', '-c', 'file.c']),
+ os.path.join(directory, 'file.c'))
+ self.assertEqual(test(['cc', '-c', './file.c']),
+ os.path.join(directory, 'file.c'))
+ self.assertEqual(test(['cc', '-c', '../file.c']),
+ os.path.join(os.path.dirname(directory), 'file.c'))
+ self.assertEqual(test(['cc', '-c', '/opt/file.c']),
+ '/opt/file.c')
+
+ def test_sip(self):
+ def create_status_report(filename, message):
+ content = """#!/usr/bin/env sh
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ echo '{0}'
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ """.format(message)
+ lines = [line.strip() for line in content.split('\n')]
+ with open(filename, 'w') as handle:
+ handle.write('\n'.join(lines))
+ handle.close()
+ os.chmod(filename, 0x1ff)
+
+ def create_csrutil(dest_dir, status):
+ filename = os.path.join(dest_dir, 'csrutil')
+ message = 'System Integrity Protection status: {0}'.format(status)
+ return create_status_report(filename, message)
+
+ def create_sestatus(dest_dir, status):
+ filename = os.path.join(dest_dir, 'sestatus')
+ message = 'SELinux status:\t{0}'.format(status)
+ return create_status_report(filename, message)
+
+ ENABLED = 'enabled'
+ DISABLED = 'disabled'
+
+ OSX = 'darwin'
+ LINUX = 'linux'
+
+ with fixtures.TempDir() as tmpdir:
+ try:
+ saved = os.environ['PATH']
+ os.environ['PATH'] = tmpdir + ':' + saved
+
+ create_csrutil(tmpdir, ENABLED)
+ self.assertTrue(sut.is_preload_disabled(OSX))
+
+ create_csrutil(tmpdir, DISABLED)
+ self.assertFalse(sut.is_preload_disabled(OSX))
+
+ create_sestatus(tmpdir, ENABLED)
+ self.assertTrue(sut.is_preload_disabled(LINUX))
+
+ create_sestatus(tmpdir, DISABLED)
+ self.assertFalse(sut.is_preload_disabled(LINUX))
+ finally:
+ os.environ['PATH'] = saved
+
+ try:
+ saved = os.environ['PATH']
+ os.environ['PATH'] = ''
+ # shall be false when it's not in the path
+ self.assertFalse(sut.is_preload_disabled(OSX))
+ self.assertFalse(sut.is_preload_disabled(LINUX))
+
+ self.assertFalse(sut.is_preload_disabled('unix'))
+ finally:
+ os.environ['PATH'] = saved
diff --git a/tools/scan-build-py/tests/unit/test_report.py b/tools/scan-build-py/tests/unit/test_report.py
new file mode 100644
index 0000000..d505afc
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_report.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.report as sut
+from . import fixtures
+import unittest
+import os
+import os.path
+
+
+def run_bug_parse(content):
+ with fixtures.TempDir() as tmpdir:
+ file_name = os.path.join(tmpdir, 'test.html')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ for bug in sut.parse_bug_html(file_name):
+ return bug
+
+
+def run_crash_parse(content, preproc):
+ with fixtures.TempDir() as tmpdir:
+ file_name = os.path.join(tmpdir, preproc + '.info.txt')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ return sut.parse_crash(file_name)
+
+
+class ParseFileTest(unittest.TestCase):
+
+ def test_parse_bug(self):
+ content = [
+ "some header\n",
+ "<!-- BUGDESC Division by zero -->\n",
+ "<!-- BUGTYPE Division by zero -->\n",
+ "<!-- BUGCATEGORY Logic error -->\n",
+ "<!-- BUGFILE xx -->\n",
+ "<!-- BUGLINE 5 -->\n",
+ "<!-- BUGCOLUMN 22 -->\n",
+ "<!-- BUGPATHLENGTH 4 -->\n",
+ "<!-- BUGMETAEND -->\n",
+ "<!-- REPORTHEADER -->\n",
+ "some tails\n"]
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Logic error')
+ self.assertEqual(result['bug_path_length'], 4)
+ self.assertEqual(result['bug_line'], 5)
+ self.assertEqual(result['bug_description'], 'Division by zero')
+ self.assertEqual(result['bug_type'], 'Division by zero')
+ self.assertEqual(result['bug_file'], 'xx')
+
+ def test_parse_bug_empty(self):
+ content = []
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Other')
+ self.assertEqual(result['bug_path_length'], 1)
+ self.assertEqual(result['bug_line'], 0)
+
+ def test_parse_crash(self):
+ content = [
+ "/some/path/file.c\n",
+ "Some very serious Error\n",
+ "bla\n",
+ "bla-bla\n"]
+ result = run_crash_parse(content, 'file.i')
+ self.assertEqual(result['source'], content[0].rstrip())
+ self.assertEqual(result['problem'], content[1].rstrip())
+ self.assertEqual(os.path.basename(result['file']),
+ 'file.i')
+ self.assertEqual(os.path.basename(result['info']),
+ 'file.i.info.txt')
+ self.assertEqual(os.path.basename(result['stderr']),
+ 'file.i.stderr.txt')
+
+ def test_parse_real_crash(self):
+ import libscanbuild.runner as sut2
+ import re
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ # produce failure report
+ opts = {'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'report': ['-fsyntax-only', '-E', filename],
+ 'language': 'c',
+ 'output_dir': tmpdir,
+ 'error_type': 'other_error',
+ 'error_output': 'some output',
+ 'exit_code': 13}
+ sut2.report_failure(opts)
+ # find the info file
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+ self.assertIsNot(pp_file, None)
+ # read the failure report back
+ result = sut.parse_crash(pp_file + '.info.txt')
+ self.assertEqual(result['source'], filename)
+ self.assertEqual(result['problem'], 'Other Error')
+ self.assertEqual(result['file'], pp_file)
+ self.assertEqual(result['info'], pp_file + '.info.txt')
+ self.assertEqual(result['stderr'], pp_file + '.stderr.txt')
+
+
+class ReportMethodTest(unittest.TestCase):
+
+ def test_chop(self):
+ self.assertEqual('file', sut.chop('/prefix', '/prefix/file'))
+ self.assertEqual('file', sut.chop('/prefix/', '/prefix/file'))
+ self.assertEqual('lib/file', sut.chop('/prefix/', '/prefix/lib/file'))
+ self.assertEqual('/prefix/file', sut.chop('', '/prefix/file'))
+
+ def test_chop_when_cwd(self):
+ self.assertEqual('../src/file', sut.chop('/cwd', '/src/file'))
+ self.assertEqual('../src/file', sut.chop('/prefix/cwd',
+ '/prefix/src/file'))
+
+
+class GetPrefixFromCompilationDatabaseTest(fixtures.TestCase):
+
+ def test_with_different_filenames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c', '/tmp/b.c']), '/tmp')
+
+ def test_with_different_dirnames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/tmp/ack/b.c']), '/tmp')
+
+ def test_no_common_prefix(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/usr/ack/b.c']), '/')
+
+ def test_with_single_file(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c']), '/tmp')
+
+ def test_empty(self):
+ self.assertEqual(
+ sut.commonprefix([]), '')
diff --git a/tools/scan-build-py/tests/unit/test_runner.py b/tools/scan-build-py/tests/unit/test_runner.py
new file mode 100644
index 0000000..ea10051
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_runner.py
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.runner as sut
+from . import fixtures
+import unittest
+import re
+import os
+import os.path
+
+
+def run_analyzer(content, opts):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.cpp')
+ with open(filename, 'w') as handle:
+ handle.write(content)
+
+ opts.update({
+ 'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'language': 'c++',
+ 'analyze': ['--analyze', '-x', 'c++', filename],
+ 'output': ['-o', tmpdir]})
+ spy = fixtures.Spy()
+ result = sut.run_analyzer(opts, spy.call)
+ return (result, spy.arg)
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ def test_run_analyzer(self):
+ content = "int div(int n, int d) { return n / d; }"
+ (result, fwds) = run_analyzer(content, dict())
+ self.assertEqual(None, fwds)
+ self.assertEqual(0, result['exit_code'])
+
+ def test_run_analyzer_crash(self):
+ content = "int div(int n, int d) { return n / d }"
+ (result, fwds) = run_analyzer(content, dict())
+ self.assertEqual(None, fwds)
+ self.assertEqual(1, result['exit_code'])
+
+ def test_run_analyzer_crash_and_forwarded(self):
+ content = "int div(int n, int d) { return n / d }"
+ (_, fwds) = run_analyzer(content, {'output_failures': True})
+ self.assertEqual('crash', fwds['error_type'])
+ self.assertEqual(1, fwds['exit_code'])
+ self.assertTrue(len(fwds['error_output']) > 0)
+
+
+class SetAnalyzerOutputTest(fixtures.TestCase):
+
+ def test_not_defined(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isdir(spy.arg['output'][1]))
+
+ def test_html(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'html'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isdir(spy.arg['output'][1]))
+
+ def test_plist_html(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'plist-html'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isfile(spy.arg['output'][1]))
+
+ def test_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'plist'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isfile(spy.arg['output'][1]))
+
+
+class ReportFailureTest(fixtures.TestCase):
+
+ def assertUnderFailures(self, path):
+ self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
+
+ def test_report_failure_create_files(self):
+ with fixtures.TempDir() as tmpdir:
+ # create input file
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ uname_msg = ' '.join(os.uname()) + os.linesep
+ error_msg = 'this is my error output'
+ # execute test
+ opts = {'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'report': ['-fsyntax-only', '-E', filename],
+ 'language': 'c',
+ 'output_dir': tmpdir,
+ 'error_type': 'other_error',
+ 'error_output': error_msg,
+ 'exit_code': 13}
+ sut.report_failure(opts)
+ # verify the result
+ result = dict()
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ with open(key, 'r') as handle:
+ result[key] = handle.readlines()
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+
+ # prepocessor file generated
+ self.assertUnderFailures(pp_file)
+ # info file generated and content dumped
+ info_file = pp_file + '.info.txt'
+ self.assertIn(info_file, result)
+ self.assertEqual('Other Error\n', result[info_file][1])
+ self.assertEqual(uname_msg, result[info_file][3])
+ # error file generated and content dumped
+ error_file = pp_file + '.stderr.txt'
+ self.assertIn(error_file, result)
+ self.assertEqual([error_msg], result[error_file])
+
+
+class AnalyzerTest(unittest.TestCase):
+
+ def test_set_language(self):
+ def test(expected, input):
+ spy = fixtures.Spy()
+ self.assertEqual(spy.success, sut.language_check(input, spy.call))
+ self.assertEqual(expected, spy.arg['language'])
+
+ l = 'language'
+ f = 'file'
+ i = 'c++'
+ test('c', {f: 'file.c', l: 'c', i: False})
+ test('c++', {f: 'file.c', l: 'c++', i: False})
+ test('c++', {f: 'file.c', i: True})
+ test('c', {f: 'file.c', i: False})
+ test('c++', {f: 'file.cxx', i: False})
+ test('c-cpp-output', {f: 'file.i', i: False})
+ test('c++-cpp-output', {f: 'file.i', i: True})
+ test('c-cpp-output', {f: 'f.i', l: 'c-cpp-output', i: True})
+
+ def test_arch_loop(self):
+ def test(input):
+ spy = fixtures.Spy()
+ sut.arch_check(input, spy.call)
+ return spy.arg
+
+ input = {'key': 'value'}
+ self.assertEqual(input, test(input))
+
+ input = {'archs_seen': ['i386']}
+ self.assertEqual({'arch': 'i386'}, test(input))
+
+ input = {'archs_seen': ['ppc']}
+ self.assertEqual(None, test(input))
+
+ input = {'archs_seen': ['i386', 'ppc']}
+ self.assertEqual({'arch': 'i386'}, test(input))
+
+ input = {'archs_seen': ['i386', 'sparc']}
+ result = test(input)
+ self.assertTrue(result == {'arch': 'i386'} or
+ result == {'arch': 'sparc'})
+
+
+@sut.require([])
+def method_without_expecteds(opts):
+ return 0
+
+
+@sut.require(['this', 'that'])
+def method_with_expecteds(opts):
+ return 0
+
+
+@sut.require([])
+def method_exception_from_inside(opts):
+ raise Exception('here is one')
+
+
+class RequireDecoratorTest(unittest.TestCase):
+
+ def test_method_without_expecteds(self):
+ self.assertEqual(method_without_expecteds(dict()), 0)
+ self.assertEqual(method_without_expecteds({}), 0)
+ self.assertEqual(method_without_expecteds({'this': 2}), 0)
+ self.assertEqual(method_without_expecteds({'that': 3}), 0)
+
+ def test_method_with_expecteds(self):
+ self.assertRaises(KeyError, method_with_expecteds, dict())
+ self.assertRaises(KeyError, method_with_expecteds, {})
+ self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
+ self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
+ self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
+
+ def test_method_exception_not_caught(self):
+ self.assertRaises(Exception, method_exception_from_inside, dict())
diff --git a/tools/scan-build-py/tests/unit/test_shell.py b/tools/scan-build-py/tests/unit/test_shell.py
new file mode 100644
index 0000000..a2904b0
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_shell.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.shell as sut
+import unittest
+
+
+class ShellTest(unittest.TestCase):
+
+ def test_encode_decode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.encode(sut.decode(value)), value)
+
+ test("")
+ test("clang")
+ test("clang this and that")
+
+ def test_decode_encode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.decode(sut.encode(value)), value)
+
+ test([])
+ test(['clang'])
+ test(['clang', 'this', 'and', 'that'])
+ test(['clang', 'this and', 'that'])
+ test(['clang', "it's me", 'again'])
+ test(['clang', 'some "words" are', 'quoted'])
+
+ def test_encode(self):
+ self.assertEqual(sut.encode(['clang', "it's me", 'again']),
+ 'clang "it\'s me" again')
+ self.assertEqual(sut.encode(['clang', "it(s me", 'again)']),
+ 'clang "it(s me" "again)"')
+ self.assertEqual(sut.encode(['clang', 'redirect > it']),
+ 'clang "redirect > it"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="VALUE"']),
+ 'clang -DKEY=\\"VALUE\\"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="value with spaces"']),
+ 'clang -DKEY=\\"value with spaces\\"')
diff --git a/tools/scan-build/CMakeLists.txt b/tools/scan-build/CMakeLists.txt
index 8a79201..78c243d 100644
--- a/tools/scan-build/CMakeLists.txt
+++ b/tools/scan-build/CMakeLists.txt
@@ -1,7 +1,7 @@
-add_custom_target(scan-build ALL)
-
option(CLANG_INSTALL_SCANBUILD "Install the scan-build tool" ON)
+include(GNUInstallDirs)
+
if (WIN32 AND NOT CYGWIN)
set(BinFiles
scan-build.bat)
@@ -15,57 +15,68 @@
ccc-analyzer
c++-analyzer)
if (APPLE)
- set(BinFiles ${BinFiles}
- set-xcode-analyzer)
+ list(APPEND BinFiles
+ set-xcode-analyzer)
endif()
endif()
set(ManPages
scan-build.1)
-set(ResourceFiles
+set(ShareFiles
scanview.css
sorttable.js)
if(CLANG_INSTALL_SCANBUILD)
foreach(BinFile ${BinFiles})
- add_custom_command(TARGET scan-build PRE_BUILD
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${BinFile}
- ${CMAKE_BINARY_DIR}/bin/)
- install(PROGRAMS ${BinFile} DESTINATION bin)
+ ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}
+ ${CMAKE_BINARY_DIR}/bin/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
+ install(PROGRAMS bin/${BinFile} DESTINATION bin)
endforeach()
foreach(LibexecFile ${LibexecFiles})
- add_custom_command(TARGET scan-build PRE_BUILD
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${LibexecFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/libexec
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${LibexecFile}
- ${CMAKE_BINARY_DIR}/libexec/)
- install(PROGRAMS ${LibexecFile} DESTINATION libexec)
+ ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile}
+ ${CMAKE_BINARY_DIR}/libexec/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${LibexecFile})
+ install(PROGRAMS libexec/${LibexecFile} DESTINATION libexec)
endforeach()
foreach(ManPage ${ManPages})
- add_custom_command(TARGET scan-build PRE_BUILD
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}
COMMAND ${CMAKE_COMMAND} -E make_directory
- ${CMAKE_BINARY_DIR}/share/man/man1
+ ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${ManPage}
- ${CMAKE_BINARY_DIR}/share/man/man1/)
- install(PROGRAMS ${ManPage} DESTINATION share/man/man1)
+ ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage}
+ ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage})
+ install(PROGRAMS man/${ManPage} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
endforeach()
- foreach(ResourceFile ${ResourceFiles})
- add_custom_command(TARGET scan-build PRE_BUILD
+ foreach(ShareFile ${ShareFiles})
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
- ${CMAKE_BINARY_DIR}/bin
+ ${CMAKE_BINARY_DIR}/share/scan-build
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${ResourceFile}
- ${CMAKE_BINARY_DIR}/bin/)
- install(FILES ${ResourceFile} DESTINATION bin)
+ ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile}
+ ${CMAKE_BINARY_DIR}/share/scan-build/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile})
+ install(FILES share/scan-build/${ShareFile} DESTINATION share/scan-build)
endforeach()
+
+ add_custom_target(scan-build ALL DEPENDS ${Depends})
+ set_target_properties(scan-build PROPERTIES FOLDER "Misc")
endif()
diff --git a/tools/scan-build/Makefile b/tools/scan-build/Makefile
index a6a2c10..23aa198 100644
--- a/tools/scan-build/Makefile
+++ b/tools/scan-build/Makefile
@@ -33,21 +33,21 @@
all:: $(InstallTargets)
-$(ToolDir)/%: % Makefile $(ToolDir)/.dir
+$(ToolDir)/%: bin/% Makefile $(ToolDir)/.dir
$(Echo) "Copying $(notdir $<) to the 'bin' directory..."
$(Verb)cp $< $@
$(Verb)chmod +x $@
-$(LibexecDir)/%: % Makefile $(LibexecDir)/.dir
+$(LibexecDir)/%: libexec/% Makefile $(LibexecDir)/.dir
$(Echo) "Copying $(notdir $<) to the 'libexec' directory..."
$(Verb)cp $< $@
$(Verb)chmod +x $@
-$(ShareDir)/man/man1/%: % Makefile $(ShareDir)/man/man1/.dir
- $(Echo) "Copying $(notdir $<) to the 'share' directory..."
+$(ShareDir)/man/man1/%: man/% Makefile $(ShareDir)/man/man1/.dir
+ $(Echo) "Copying $(notdir $<) to the 'man' directory..."
$(Verb)cp $< $@
-$(ShareDir)/scan-build/%: % Makefile $(ShareDir)/scan-build/.dir
+$(ShareDir)/scan-build/%: share/scan-build/% Makefile $(ShareDir)/scan-build/.dir
$(Echo) "Copying $(notdir $<) to the 'share' directory..."
$(Verb)cp $< $@
diff --git a/tools/scan-build/scan-build b/tools/scan-build/bin/scan-build
similarity index 98%
rename from tools/scan-build/scan-build
rename to tools/scan-build/bin/scan-build
index 65dc4fe..6a14484 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/bin/scan-build
@@ -462,7 +462,7 @@
my $Dir = shift;
- my $JS = Cwd::realpath("$RealBin/sorttable.js");
+ my $JS = Cwd::realpath("$RealBin/../share/scan-build/sorttable.js");
DieDiag("Cannot find 'sorttable.js'.\n")
if (! -r $JS);
@@ -472,7 +472,7 @@
DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
if (! -r "$Dir/sorttable.js");
- my $CSS = Cwd::realpath("$RealBin/scanview.css");
+ my $CSS = Cwd::realpath("$RealBin/../share/scan-build/scanview.css");
DieDiag("Cannot find 'scanview.css'.\n")
if (! -r $CSS);
@@ -1478,7 +1478,9 @@
# Construct an absolute path. Uses the current working directory
# as a base if the original path was not absolute.
- $Options{OutputDir} = abs_path(shift @$Args);
+ my $OutDir = shift @$Args;
+ mkpath($OutDir) unless (-e $OutDir); # abs_path wants existing dir
+ $Options{OutputDir} = abs_path($OutDir);
next;
}
@@ -1816,6 +1818,7 @@
Diag "Viewing analysis results in '$Options{OutputDir}' using scan-view.\n";
my $ScanView = Cwd::realpath("$RealBin/scan-view");
if (! -x $ScanView) { $ScanView = "scan-view"; }
+ if (! -x $ScanView) { $ScanView = Cwd::realpath("$RealBin/../../scan-view/bin/scan-view"); }
exec $ScanView, "$Options{OutputDir}";
}
diff --git a/tools/scan-build/scan-build.bat b/tools/scan-build/bin/scan-build.bat
similarity index 100%
rename from tools/scan-build/scan-build.bat
rename to tools/scan-build/bin/scan-build.bat
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/bin/set-xcode-analyzer
similarity index 100%
rename from tools/scan-build/set-xcode-analyzer
rename to tools/scan-build/bin/set-xcode-analyzer
diff --git a/tools/scan-build/c++-analyzer b/tools/scan-build/libexec/c++-analyzer
similarity index 100%
rename from tools/scan-build/c++-analyzer
rename to tools/scan-build/libexec/c++-analyzer
diff --git a/tools/scan-build/c++-analyzer.bat b/tools/scan-build/libexec/c++-analyzer.bat
similarity index 100%
rename from tools/scan-build/c++-analyzer.bat
rename to tools/scan-build/libexec/c++-analyzer.bat
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer
similarity index 100%
rename from tools/scan-build/ccc-analyzer
rename to tools/scan-build/libexec/ccc-analyzer
diff --git a/tools/scan-build/ccc-analyzer.bat b/tools/scan-build/libexec/ccc-analyzer.bat
similarity index 100%
rename from tools/scan-build/ccc-analyzer.bat
rename to tools/scan-build/libexec/ccc-analyzer.bat
diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/man/scan-build.1
similarity index 100%
rename from tools/scan-build/scan-build.1
rename to tools/scan-build/man/scan-build.1
diff --git a/tools/scan-build/scanview.css b/tools/scan-build/share/scan-build/scanview.css
similarity index 100%
rename from tools/scan-build/scanview.css
rename to tools/scan-build/share/scan-build/scanview.css
diff --git a/tools/scan-build/sorttable.js b/tools/scan-build/share/scan-build/sorttable.js
similarity index 100%
rename from tools/scan-build/sorttable.js
rename to tools/scan-build/share/scan-build/sorttable.js
diff --git a/tools/scan-view/CMakeLists.txt b/tools/scan-view/CMakeLists.txt
index 8f51fd4..b305ca5 100644
--- a/tools/scan-view/CMakeLists.txt
+++ b/tools/scan-view/CMakeLists.txt
@@ -1,36 +1,41 @@
-add_custom_target(scan-view ALL)
-
option(CLANG_INSTALL_SCANVIEW "Install the scan-view tool" ON)
set(BinFiles
- Reporter.py
- ScanView.py
- scan-view
- startfile.py)
+ scan-view)
-set(ResourceFiles
- Resources/FileRadar.scpt
- Resources/GetRadarVersion.scpt
- Resources/bugcatcher.ico)
+set(ShareFiles
+ ScanView.py
+ Reporter.py
+ startfile.py
+ FileRadar.scpt
+ GetRadarVersion.scpt
+ bugcatcher.ico)
if(CLANG_INSTALL_SCANVIEW)
foreach(BinFile ${BinFiles})
- add_custom_command(TARGET scan-view PRE_BUILD
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${BinFile}
- ${CMAKE_BINARY_DIR}/bin/)
- install(PROGRAMS ${BinFile} DESTINATION bin)
+ ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}
+ ${CMAKE_BINARY_DIR}/bin/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
+ install(PROGRAMS bin/${BinFile} DESTINATION bin)
endforeach()
- foreach(ResourceFile ${ResourceFiles})
- add_custom_command(TARGET scan-view PRE_BUILD
+ foreach(ShareFile ${ShareFiles})
+ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/share/scan-view/${ShareFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/share/scan-view
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/${ResourceFile}
- ${CMAKE_BINARY_DIR}/share/scan-view/)
- install(FILES ${ResourceFile} DESTINATION share/scan-view)
+ ${CMAKE_CURRENT_SOURCE_DIR}/share/${ShareFile}
+ ${CMAKE_BINARY_DIR}/share/scan-view/
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/${ShareFile})
+ list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-view/${ShareFile})
+ install(FILES share/${ShareFile} DESTINATION share/scan-view)
endforeach()
+
+ add_custom_target(scan-view ALL DEPENDS ${Depends})
+ set_target_properties(scan-view PROPERTIES FOLDER "Misc")
endif()
diff --git a/tools/scan-view/Makefile b/tools/scan-view/Makefile
index c2ca453..37e4404 100644
--- a/tools/scan-view/Makefile
+++ b/tools/scan-view/Makefile
@@ -15,10 +15,10 @@
CLANG_INSTALL_SCANVIEW ?= 1
ifeq ($(CLANG_INSTALL_SCANVIEW), 1)
- InstallTargets := $(ToolDir)/Reporter.py \
- $(ToolDir)/ScanView.py \
- $(ToolDir)/scan-view \
- $(ToolDir)/startfile.py \
+ InstallTargets := $(ToolDir)/scan-view \
+ $(ShareDir)/scan-view/Reporter.py \
+ $(ShareDir)/scan-view/ScanView.py \
+ $(ShareDir)/scan-view/startfile.py \
$(ShareDir)/scan-view/FileRadar.scpt \
$(ShareDir)/scan-view/GetRadarVersion.scpt \
$(ShareDir)/scan-view/bugcatcher.ico
@@ -26,12 +26,12 @@
all:: $(InstallTargets)
-$(ToolDir)/%: % Makefile $(ToolDir)/.dir
+$(ToolDir)/%: bin/% Makefile $(ToolDir)/.dir
$(Echo) "Copying $(notdir $<) to the 'bin' directory..."
$(Verb)cp $< $@
$(Verb)chmod +x $@
-$(ShareDir)/scan-view/%: Resources/% Makefile $(ShareDir)/scan-view/.dir
+$(ShareDir)/scan-view/%: share/% Makefile $(ShareDir)/scan-view/.dir
$(Echo) "Copying $(notdir $<) to the 'share' directory..."
$(Verb)cp $< $@
diff --git a/tools/scan-view/bin/scan-view b/tools/scan-view/bin/scan-view
new file mode 100755
index 0000000..1b6e8ba
--- /dev/null
+++ b/tools/scan-view/bin/scan-view
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+
+"""The clang static analyzer results viewer.
+"""
+
+import sys
+import imp
+import os
+import posixpath
+import thread
+import time
+import urllib
+import webbrowser
+
+# How long to wait for server to start.
+kSleepTimeout = .05
+kMaxSleeps = int(60 / kSleepTimeout)
+
+# Default server parameters
+
+kDefaultHost = '127.0.0.1'
+kDefaultPort = 8181
+kMaxPortsToTry = 100
+
+###
+
+
+def url_is_up(url):
+ try:
+ o = urllib.urlopen(url)
+ except IOError:
+ return False
+ o.close()
+ return True
+
+
+def start_browser(port, options):
+ import urllib
+ import webbrowser
+
+ url = 'http://%s:%d' % (options.host, port)
+
+ # Wait for server to start...
+ if options.debug:
+ sys.stderr.write('%s: Waiting for server.' % sys.argv[0])
+ sys.stderr.flush()
+ for i in range(kMaxSleeps):
+ if url_is_up(url):
+ break
+ if options.debug:
+ sys.stderr.write('.')
+ sys.stderr.flush()
+ time.sleep(kSleepTimeout)
+ else:
+ print >> sys.stderr, 'WARNING: Unable to detect that server started.'
+
+ if options.debug:
+ print >> sys.stderr, '%s: Starting webbrowser...' % sys.argv[0]
+ webbrowser.open(url)
+
+
+def run(port, options, root):
+ # Prefer to look relative to the installed binary
+ share = os.path.dirname(__file__) + "/../share/scan-view"
+ if not os.path.isdir(share):
+ # Otherwise look relative to the source
+ share = os.path.dirname(__file__) + "/../../scan-view/share"
+ sys.path.append(share)
+
+ import ScanView
+ try:
+ print 'Starting scan-view at: http://%s:%d' % (options.host,
+ port)
+ print ' Use Ctrl-C to exit.'
+ httpd = ScanView.create_server((options.host, port),
+ options, root)
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+
+
+def port_is_open(port):
+ import SocketServer
+ try:
+ t = SocketServer.TCPServer((kDefaultHost, port), None)
+ except:
+ return False
+ t.server_close()
+ return True
+
+
+def main():
+ import argparse
+ parser = argparse.ArgumentParser(description="The clang static analyzer "
+ "results viewer.")
+ parser.add_argument("root", metavar="<results directory>", type=str)
+ parser.add_argument(
+ '--host', dest="host", default=kDefaultHost, type=str,
+ help="Host interface to listen on. (default=%s)" % kDefaultHost)
+ parser.add_argument('--port', dest="port", default=None, type=int,
+ help="Port to listen on. (default=%s)" % kDefaultPort)
+ parser.add_argument("--debug", dest="debug", default=0,
+ action="count",
+ help="Print additional debugging information.")
+ parser.add_argument("--auto-reload", dest="autoReload", default=False,
+ action="store_true",
+ help="Automatically update module for each request.")
+ parser.add_argument("--no-browser", dest="startBrowser", default=True,
+ action="store_false",
+ help="Don't open a webbrowser on startup.")
+ parser.add_argument("--allow-all-hosts", dest="onlyServeLocal",
+ default=True, action="store_false",
+ help='Allow connections from any host (access '
+ 'restricted to "127.0.0.1" by default)')
+ args = parser.parse_args()
+
+ # Make sure this directory is in a reasonable state to view.
+ if not posixpath.exists(posixpath.join(args.root, 'index.html')):
+ parser.error('Invalid directory, analysis results not found!')
+
+ # Find an open port. We aren't particularly worried about race
+ # conditions here. Note that if the user specified a port we only
+ # use that one.
+ if args.port is not None:
+ port = args.port
+ else:
+ for i in range(kMaxPortsToTry):
+ if port_is_open(kDefaultPort + i):
+ port = kDefaultPort + i
+ break
+ else:
+ parser.error('Unable to find usable port in [%d,%d)' %
+ (kDefaultPort, kDefaultPort+kMaxPortsToTry))
+
+ # Kick off thread to wait for server and start web browser, if
+ # requested.
+ if args.startBrowser:
+ t = thread.start_new_thread(start_browser, (port, args))
+
+ run(port, args, args.root)
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/scan-view/scan-view b/tools/scan-view/scan-view
deleted file mode 100755
index fb27da6..0000000
--- a/tools/scan-view/scan-view
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-
-"""The clang static analyzer results viewer.
-"""
-
-import sys
-import posixpath
-import thread
-import time
-import urllib
-import webbrowser
-
-# How long to wait for server to start.
-kSleepTimeout = .05
-kMaxSleeps = int(60 / kSleepTimeout)
-
-# Default server parameters
-
-kDefaultHost = '127.0.0.1'
-kDefaultPort = 8181
-kMaxPortsToTry = 100
-
-###
-
-def url_is_up(url):
- try:
- o = urllib.urlopen(url)
- except IOError:
- return False
- o.close()
- return True
-
-def start_browser(port, options):
- import urllib, webbrowser
-
- url = 'http://%s:%d'%(options.host, port)
-
- # Wait for server to start...
- if options.debug:
- sys.stderr.write('%s: Waiting for server.' % sys.argv[0])
- sys.stderr.flush()
- for i in range(kMaxSleeps):
- if url_is_up(url):
- break
- if options.debug:
- sys.stderr.write('.')
- sys.stderr.flush()
- time.sleep(kSleepTimeout)
- else:
- print >>sys.stderr,'WARNING: Unable to detect that server started.'
-
- if options.debug:
- print >>sys.stderr,'%s: Starting webbrowser...' % sys.argv[0]
- webbrowser.open(url)
-
-def run(port, options, root):
- import ScanView
- try:
- print 'Starting scan-view at: http://%s:%d'%(options.host,
- port)
- print ' Use Ctrl-C to exit.'
- httpd = ScanView.create_server((options.host, port),
- options, root)
- httpd.serve_forever()
- except KeyboardInterrupt:
- pass
-
-def port_is_open(port):
- import SocketServer
- try:
- t = SocketServer.TCPServer((kDefaultHost,port),None)
- except:
- return False
- t.server_close()
- return True
-
-def main():
- from optparse import OptionParser
- parser = OptionParser('usage: %prog [options] <results directory>')
- parser.set_description(__doc__)
- parser.add_option(
- '--host', dest="host", default=kDefaultHost, type="string",
- help="Host interface to listen on. (default=%s)" % kDefaultHost)
- parser.add_option(
- '--port', dest="port", default=None, type="int",
- help="Port to listen on. (default=%s)" % kDefaultPort)
- parser.add_option("--debug", dest="debug", default=0,
- action="count",
- help="Print additional debugging information.")
- parser.add_option("--auto-reload", dest="autoReload", default=False,
- action="store_true",
- help="Automatically update module for each request.")
- parser.add_option("--no-browser", dest="startBrowser", default=True,
- action="store_false",
- help="Don't open a webbrowser on startup.")
- parser.add_option("--allow-all-hosts", dest="onlyServeLocal", default=True,
- action="store_false",
- help='Allow connections from any host (access restricted to "127.0.0.1" by default)')
- (options, args) = parser.parse_args()
-
- if len(args) != 1:
- parser.error('No results directory specified.')
- root, = args
-
- # Make sure this directory is in a reasonable state to view.
- if not posixpath.exists(posixpath.join(root,'index.html')):
- parser.error('Invalid directory, analysis results not found!')
-
- # Find an open port. We aren't particularly worried about race
- # conditions here. Note that if the user specified a port we only
- # use that one.
- if options.port is not None:
- port = options.port
- else:
- for i in range(kMaxPortsToTry):
- if port_is_open(kDefaultPort + i):
- port = kDefaultPort + i
- break
- else:
- parser.error('Unable to find usable port in [%d,%d)'%(kDefaultPort,
- kDefaultPort+kMaxPortsToTry))
-
- # Kick off thread to wait for server and start web browser, if
- # requested.
- if options.startBrowser:
- t = thread.start_new_thread(start_browser, (port,options))
-
- run(port, options, root)
-
-if __name__ == '__main__':
- main()
diff --git a/tools/scan-view/Resources/FileRadar.scpt b/tools/scan-view/share/FileRadar.scpt
similarity index 100%
rename from tools/scan-view/Resources/FileRadar.scpt
rename to tools/scan-view/share/FileRadar.scpt
Binary files differ
diff --git a/tools/scan-view/Resources/GetRadarVersion.scpt b/tools/scan-view/share/GetRadarVersion.scpt
similarity index 100%
rename from tools/scan-view/Resources/GetRadarVersion.scpt
rename to tools/scan-view/share/GetRadarVersion.scpt
diff --git a/tools/scan-view/Reporter.py b/tools/scan-view/share/Reporter.py
similarity index 100%
rename from tools/scan-view/Reporter.py
rename to tools/scan-view/share/Reporter.py
diff --git a/tools/scan-view/ScanView.py b/tools/scan-view/share/ScanView.py
similarity index 99%
rename from tools/scan-view/ScanView.py
rename to tools/scan-view/share/ScanView.py
index 2336b09..7dc0351 100644
--- a/tools/scan-view/ScanView.py
+++ b/tools/scan-view/share/ScanView.py
@@ -73,7 +73,7 @@
###
# Other simple parameters
-kResources = posixpath.join(posixpath.dirname(__file__), '../share/scan-view')
+kShare = posixpath.join(posixpath.dirname(__file__), '../share/scan-view')
kConfigPath = os.path.expanduser('~/.scanview.cfg')
###
@@ -680,7 +680,7 @@
overrides['Radar']['Component Version'] = 'X'
return self.send_report(None, overrides)
elif name=='favicon.ico':
- return self.send_path(posixpath.join(kResources,'bugcatcher.ico'))
+ return self.send_path(posixpath.join(kShare,'bugcatcher.ico'))
# Match directory entries.
if components[-1] == '':
diff --git a/tools/scan-view/Resources/bugcatcher.ico b/tools/scan-view/share/bugcatcher.ico
similarity index 100%
rename from tools/scan-view/Resources/bugcatcher.ico
rename to tools/scan-view/share/bugcatcher.ico
Binary files differ
diff --git a/tools/scan-view/startfile.py b/tools/scan-view/share/startfile.py
similarity index 100%
rename from tools/scan-view/startfile.py
rename to tools/scan-view/share/startfile.py
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
index eeb01cc..b635653 100644
--- a/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -162,5 +162,12 @@
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
+TEST(DynTypedNode, QualType) {
+ QualType Q;
+ DynTypedNode Node = DynTypedNode::create(Q);
+ EXPECT_TRUE(Node == Node);
+ EXPECT_FALSE(Node < Node);
+}
+
} // namespace ast_type_traits
} // namespace clang
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index 4c77def..9fae8d8 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -542,5 +542,43 @@
cxxConstructExpr(), Lang_OBJCXX));
}
+TEST(FunctionDecl, FunctionDeclWithThrowSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 16);
+ EXPECT_TRUE(Verifier.match(
+ "void f() throw();\n",
+ functionDecl()));
+}
+
+TEST(FunctionDecl, FunctionDeclWithNoExceptSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 24);
+ EXPECT_TRUE(Verifier.match(
+ "void f() noexcept(false);\n",
+ functionDecl(),
+ Language::Lang_CXX11));
+}
+
+TEST(CXXMethodDecl, CXXMethodDeclWithThrowSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(2, 1, 2, 16);
+ EXPECT_TRUE(Verifier.match(
+ "class A {\n"
+ "void f() throw();\n"
+ "};\n",
+ functionDecl()));
+}
+
+TEST(CXXMethodDecl, CXXMethodDeclWithNoExceptSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(2, 1, 2, 24);
+ EXPECT_TRUE(Verifier.match(
+ "class A {\n"
+ "void f() noexcept(false);\n"
+ "};\n",
+ functionDecl(),
+ Language::Lang_CXX11));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 476a0be..1e5401d 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -1355,6 +1355,29 @@
EXPECT_TRUE(matches("void f() { static int X; }", M));
}
+TEST(Matcher, VarDecl_StorageDuration) {
+ std::string T =
+ "void f() { int x; static int y; } int a;";
+
+ EXPECT_TRUE(matches(T, varDecl(hasName("x"), hasAutomaticStorageDuration())));
+ EXPECT_TRUE(
+ notMatches(T, varDecl(hasName("y"), hasAutomaticStorageDuration())));
+ EXPECT_TRUE(
+ notMatches(T, varDecl(hasName("a"), hasAutomaticStorageDuration())));
+
+ EXPECT_TRUE(matches(T, varDecl(hasName("y"), hasStaticStorageDuration())));
+ EXPECT_TRUE(matches(T, varDecl(hasName("a"), hasStaticStorageDuration())));
+ EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasStaticStorageDuration())));
+
+ // FIXME: It is really hard to test with thread_local itself because not all
+ // targets support TLS, which causes this to be an error depending on what
+ // platform the test is being run on. We do not have access to the TargetInfo
+ // object to be able to test whether the platform supports TLS or not.
+ EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasThreadStorageDuration())));
+ EXPECT_TRUE(notMatches(T, varDecl(hasName("y"), hasThreadStorageDuration())));
+ EXPECT_TRUE(notMatches(T, varDecl(hasName("a"), hasThreadStorageDuration())));
+}
+
TEST(Matcher, FindsVarDeclInFunctionParameter) {
EXPECT_TRUE(matches(
"void f(int i) {}",
@@ -1446,6 +1469,14 @@
to(varDecl(hasType(isInteger()))))))));
}
+TEST(IsAnyCharacter, MatchesCharacters) {
+ EXPECT_TRUE(matches("char i = 0;", varDecl(hasType(isAnyCharacter()))));
+}
+
+TEST(IsAnyCharacter, ReportsNoFalsePositives) {
+ EXPECT_TRUE(notMatches("int i;", varDecl(hasType(isAnyCharacter()))));
+}
+
TEST(IsArrow, MatchesMemberVariablesViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };",
memberExpr(isArrow())));
@@ -1577,6 +1608,103 @@
EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
}
+TEST(ForEachArgumentWithParam, ReportsNoFalsePositives) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher CallExpr =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+
+ // IntParam does not match.
+ EXPECT_TRUE(notMatches("void f(int* i) { int* y; f(y); }", CallExpr));
+ // ArgumentY does not match.
+ EXPECT_TRUE(notMatches("void f(int i) { int x; f(x); }", CallExpr));
+}
+
+TEST(ForEachArgumentWithParam, MatchesCXXMemberCallExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher CallExpr =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct S {"
+ " const S& operator[](int i) { return *this; }"
+ "};"
+ "void f(S S1) {"
+ " int y = 1;"
+ " S1[y];"
+ "}",
+ CallExpr, new VerifyIdIsBoundTo<ParmVarDecl>("param", 1)));
+
+ StatementMatcher CallExpr2 =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct S {"
+ " static void g(int i);"
+ "};"
+ "void f() {"
+ " int y = 1;"
+ " S::g(y);"
+ "}",
+ CallExpr2, new VerifyIdIsBoundTo<ParmVarDecl>("param", 1)));
+}
+
+TEST(ForEachArgumentWithParam, MatchesCallExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher CallExpr =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+
+ EXPECT_TRUE(
+ matchAndVerifyResultTrue("void f(int i) { int y; f(y); }", CallExpr,
+ new VerifyIdIsBoundTo<ParmVarDecl>("param")));
+ EXPECT_TRUE(
+ matchAndVerifyResultTrue("void f(int i) { int y; f(y); }", CallExpr,
+ new VerifyIdIsBoundTo<DeclRefExpr>("arg")));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f(int i, int j) { int y; f(y, y); }", CallExpr,
+ new VerifyIdIsBoundTo<ParmVarDecl>("param", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f(int i, int j) { int y; f(y, y); }", CallExpr,
+ new VerifyIdIsBoundTo<DeclRefExpr>("arg", 2)));
+}
+
+TEST(ForEachArgumentWithParam, MatchesConstructExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher ConstructExpr =
+ cxxConstructExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct C {"
+ " C(int i) {}"
+ "};"
+ "int y = 0;"
+ "C Obj(y);",
+ ConstructExpr, new VerifyIdIsBoundTo<ParmVarDecl>("param")));
+}
+
+TEST(ForEachArgumentWithParam, HandlesBoundNodesForNonMatches) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void g(int i, int j) {"
+ " int a;"
+ " int b;"
+ " int c;"
+ " g(a, 0);"
+ " g(a, b);"
+ " g(0, b);"
+ "}",
+ functionDecl(
+ forEachDescendant(varDecl().bind("v")),
+ forEachDescendant(callExpr(forEachArgumentWithParam(
+ declRefExpr(to(decl(equalsBoundNode("v")))), parmVarDecl())))),
+ new VerifyIdIsBoundTo<VarDecl>("v", 4)));
+}
+
TEST(Matcher, ArgumentCount) {
StatementMatcher Call1Arg = callExpr(argumentCountIs(1));
@@ -1686,6 +1814,13 @@
EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
+TEST(IsDefaulted, MatchesDefaultedFunctionDeclarations) {
+ EXPECT_TRUE(notMatches("class A { ~A(); };",
+ functionDecl(hasName("~A"), isDefaulted())));
+ EXPECT_TRUE(matches("class B { ~B() = default; };",
+ functionDecl(hasName("~B"), isDefaulted())));
+}
+
TEST(IsDeleted, MatchesDeletedFunctionDeclarations) {
EXPECT_TRUE(
notMatches("void Func();", functionDecl(hasName("Func"), isDeleted())));
@@ -1693,6 +1828,15 @@
functionDecl(hasName("Func"), isDeleted())));
}
+TEST(IsNoThrow, MatchesNoThrowFunctionDeclarations) {
+ EXPECT_TRUE(notMatches("void f();", functionDecl(isNoThrow())));
+ EXPECT_TRUE(notMatches("void f() throw(int);", functionDecl(isNoThrow())));
+ EXPECT_TRUE(
+ notMatches("void f() noexcept(false);", functionDecl(isNoThrow())));
+ EXPECT_TRUE(matches("void f() throw();", functionDecl(isNoThrow())));
+ EXPECT_TRUE(matches("void f() noexcept;", functionDecl(isNoThrow())));
+}
+
TEST(isConstexpr, MatchesConstexprDeclarations) {
EXPECT_TRUE(matches("constexpr int foo = 42;",
varDecl(hasName("foo"), isConstexpr())));
@@ -3000,6 +3144,15 @@
EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m"))));
}
+TEST(IsVolatileQualified, QualifiersMatch) {
+ EXPECT_TRUE(matches("volatile int i = 42;",
+ varDecl(hasType(isVolatileQualified()))));
+ EXPECT_TRUE(notMatches("volatile int *i;",
+ varDecl(hasType(isVolatileQualified()))));
+ EXPECT_TRUE(matches("typedef volatile int v_int; v_int i = 42;",
+ varDecl(hasType(isVolatileQualified()))));
+}
+
TEST(IsConstQualified, MatchesConstInt) {
EXPECT_TRUE(matches("const int i = 42;",
varDecl(hasType(isConstQualified()))));
@@ -4097,6 +4250,13 @@
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
}
+TEST(TypeMatching, MatchesBool) {
+ EXPECT_TRUE(matches("struct S { bool func(); };",
+ cxxMethodDecl(returns(booleanType()))));
+ EXPECT_TRUE(notMatches("struct S { void func(); };",
+ cxxMethodDecl(returns(booleanType()))));
+}
+
TEST(TypeMatching, MatchesVoid) {
EXPECT_TRUE(matches("struct S { void func(); };",
cxxMethodDecl(returns(voidType()))));
@@ -4455,6 +4615,8 @@
nestedNameSpecifier()));
EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}",
nestedNameSpecifier()));
+ EXPECT_TRUE(matches("namespace a { namespace b {} } namespace ab = a::b;",
+ nestedNameSpecifier()));
EXPECT_TRUE(matches(
"struct A { static void f() {} }; void g() { A::f(); }",
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 9ed7ef6..68824e6 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -178,6 +178,7 @@
Args.push_back("-xcuda");
Args.push_back("-fno-ms-extensions");
Args.push_back("--cuda-host-only");
+ Args.push_back("-nocudainc");
Args.push_back(CompileArg);
if (!runToolOnCodeWithArgs(Factory->create(),
CudaHeader + Code, Args)) {
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index ac07035..7abc549 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -370,14 +370,6 @@
EXPECT_EQ(1, Counts[3]); // d
}
-template <typename T, size_t N>
-std::vector<StringRef> makeStringRefVector(const T (&Arr)[N]) {
- std::vector<StringRef> Vec;
- for (size_t i = 0; i != N; ++i)
- Vec.push_back(Arr[i]);
- return Vec;
-}
-
template <typename DirIter>
static void checkContents(DirIter I, ArrayRef<StringRef> Expected) {
std::error_code EC;
@@ -405,20 +397,14 @@
checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Upper->addRegularFile("/file2");
- {
- const char *Contents[] = {"/file2", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Lower->addDirectory("/dir1");
Lower->addRegularFile("/dir1/foo");
Upper->addDirectory("/dir2");
Upper->addRegularFile("/dir2/foo");
checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
- {
- const char *Contents[] = {"/dir2", "/file2", "/dir1", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
}
TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
@@ -440,11 +426,8 @@
Upper->addDirectory("/dir");
Upper->addRegularFile("/dir/file2");
- {
- const char *Contents[] = {"/dir", "/dir/file2", "/file1"};
- checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/file1"});
Lower->addDirectory("/dir1");
Lower->addRegularFile("/dir1/foo");
@@ -460,13 +443,10 @@
Upper->addRegularFile("/hiddenByUp");
checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
ArrayRef<StringRef>("/dir2/foo"));
- {
- const char *Contents[] = { "/dir", "/dir/file2", "/dir2", "/dir2/foo",
- "/hiddenByUp", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
- "/dir1/a/b", "/dir1/foo", "/file1" };
- checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
+ "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
+ "/dir1/a/b", "/dir1/foo", "/file1"});
}
TEST(VirtualFileSystemTest, ThreeLevelIteration) {
@@ -486,10 +466,7 @@
Lower->addRegularFile("/file1");
Upper->addRegularFile("/file3");
- {
- const char *Contents[] = {"/file3", "/file2", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
}
TEST(VirtualFileSystemTest, HiddenInIteration) {
@@ -510,11 +487,9 @@
Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
- {
- const char *Contents[] = {"/hiddenByUp", "/onlyInUp", "/hiddenByMid",
- "/onlyInMid", "/onlyInLow"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(
+ O->dir_begin("/", EC),
+ {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
// Make sure we get the top-most entry
{
@@ -657,6 +632,18 @@
Stat = FS.status("c");
ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+
+ auto ReplaceBackslashes = [](std::string S) {
+ std::replace(S.begin(), S.end(), '\\', '/');
+ return S;
+ };
+ NormalizedFS.setCurrentWorkingDirectory("/b/c");
+ NormalizedFS.setCurrentWorkingDirectory(".");
+ ASSERT_EQ("/b/c", ReplaceBackslashes(
+ NormalizedFS.getCurrentWorkingDirectory().get()));
+ NormalizedFS.setCurrentWorkingDirectory("..");
+ ASSERT_EQ("/b", ReplaceBackslashes(
+ NormalizedFS.getCurrentWorkingDirectory().get()));
}
// NOTE: in the tests below, we use '//root/' as our root directory, since it is
@@ -1067,15 +1054,9 @@
O->pushOverlay(FS);
std::error_code EC;
- {
- const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
- "//root/foo"};
- checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("//root/", EC),
+ {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
- {
- const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
- checkContents(O->dir_begin("//root/foo/bar", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("//root/foo/bar", EC),
+ {"//root/foo/bar/a", "//root/foo/bar/b"});
}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 6636d82..b85ec7e 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -25,6 +25,6 @@
add_subdirectory(CodeGen)
# FIXME: libclang unit tests are disabled on Windows due
# to failures, mostly in libclang.VirtualFileOverlay_*.
-if(NOT WIN32)
+if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)
add_subdirectory(libclang)
endif()
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 1c68d67..d9a16db 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -313,7 +313,7 @@
" f();\n"
"}",
AllowsMergedIf);
- verifyFormat("if (a) {/* Never merge this */\n"
+ verifyFormat("if (a) { /* Never merge this */\n"
" f();\n"
"}",
AllowsMergedIf);
@@ -1022,6 +1022,15 @@
" lineWith(); // comment\n"
" // at start\n"
"}"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // b",
+ format("int xy; // a\n"
+ "int z; //b"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // bb",
+ format("int xy; // a\n"
+ "int z; //bb",
+ getLLVMStyleWithColumns(12)));
verifyFormat("#define A \\\n"
" int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
@@ -1197,6 +1206,13 @@
"comment */"));
}
+TEST_F(FormatTest, CommentReflowingCanBeTurnedOff) {
+ FormatStyle Style = getLLVMStyleWithColumns(20);
+ Style.ReflowComments = false;
+ verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
+ verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
+}
+
TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) {
EXPECT_EQ("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */",
@@ -1867,11 +1883,21 @@
"};");
verifyFormat("class A {\n"
"public slots:\n"
- " void f() {}\n"
+ " void f1() {}\n"
"public Q_SLOTS:\n"
- " void f() {}\n"
+ " void f2() {}\n"
+ "protected slots:\n"
+ " void f3() {}\n"
+ "protected Q_SLOTS:\n"
+ " void f4() {}\n"
+ "private slots:\n"
+ " void f5() {}\n"
+ "private Q_SLOTS:\n"
+ " void f6() {}\n"
"signals:\n"
- " void g();\n"
+ " void g1();\n"
+ "Q_SIGNALS:\n"
+ " void g2();\n"
"};");
// Don't interpret 'signals' the wrong way.
@@ -2927,6 +2953,8 @@
" EXCLUSIVE_LOCK_FUNCTION(mu_);\n"
"};",
getLLVMStyleWithColumns(40)));
+
+ verifyFormat("MACRO(>)");
}
TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
@@ -3322,7 +3350,7 @@
verifyFormat("aaaaaa = aaaaaaa(aaaaaaa, // break\n"
" aaaaaa) >>\n"
" bbbbbb;");
- verifyFormat("Whitespaces.addUntouchableComment(\n"
+ verifyFormat("aa = Whitespaces.addUntouchableComment(\n"
" SourceMgr.getSpellingColumnNumber(\n"
" TheLine.Last->FormatTok.Tok.getLocation()) -\n"
" 1);");
@@ -3588,6 +3616,7 @@
FormatStyle OnePerLine = getLLVMStyle();
OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ OnePerLine.AllowAllParametersOfDeclarationOnNextLine = false;
verifyFormat("SomeClass::Constructor()\n"
" : aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
@@ -3614,6 +3643,13 @@
" : aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaa) {}",
OnePerLine);
+ OnePerLine.BinPackParameters = false;
+ verifyFormat(
+ "Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaa().aaa(),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ OnePerLine);
OnePerLine.ColumnLimit = 60;
verifyFormat("Constructor()\n"
" : aaaaaaaaaaaaaaaaaaaa(a),\n"
@@ -4035,6 +4071,23 @@
" int aaaaaaaaaaaaaaaaaaaa,\n"
" int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
NoBinPacking);
+
+ NoBinPacking.AllowAllParametersOfDeclarationOnNextLine = false;
+ verifyFormat("void aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " vector<int> bbbbbbbbbbbbbbb);",
+ NoBinPacking);
+ // FIXME: This behavior difference is probably not wanted. However, currently
+ // we cannot distinguish BreakBeforeParameter being set because of the wrapped
+ // template arguments from BreakBeforeParameter being set because of the
+ // one-per-line formatting.
+ verifyFormat(
+ "void fffffffffff(aaaaaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaa> aaaaaaaaaa);",
+ NoBinPacking);
+ verifyFormat(
+ "void fffffffffff(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaa>\n"
+ " aaaaaaaaaa);");
}
TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
@@ -4078,7 +4131,8 @@
verifyFormat("std::vector<aaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaa> aaaaaaaaaaaaaaaaaa;",
+ " aaaaaaaaaaaaaaaaaaaaaaa>\n"
+ " aaaaaaaaaaaaaaaaaa;",
NoBinPacking);
verifyFormat("a(\"a\"\n"
" \"a\",\n"
@@ -4137,8 +4191,13 @@
verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n"
" aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();");
verifyFormat(
- "aaaaaaa->aaaaaaa->aaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ "aaaaaaa->aaaaaaa\n"
+ " ->aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " ->aaaaaaaa(aaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaa->aaaaaaa\n"
+ " ->aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" ->aaaaaaaa(aaaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n"
@@ -4204,6 +4263,31 @@
// Prefer not to break after empty parentheses.
verifyFormat("FirstToken->WhitespaceRange.getBegin().getLocWithOffset(\n"
" First->LastNewlineOffset);");
+
+ // Prefer not to create "hanging" indents.
+ verifyFormat(
+ "return !soooooooooooooome_map\n"
+ " .insert(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .second;");
+ verifyFormat(
+ "return aaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa)\n"
+ " .aaaa(aaaaaaaaaaaaaa);");
+ // No hanging indent here.
+ verifyFormat("aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaa.aaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaa().aaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("aaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ getLLVMStyleWithColumns(60));
+ verifyFormat("aaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ getLLVMStyleWithColumns(59));
+ verifyFormat("aaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
}
TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {
@@ -4341,6 +4425,26 @@
"SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));",
Style);
+
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+ Style.BinPackArguments = false;
+ Style.BinPackParameters = false;
+ verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaa aaaaaaaa,\n"
+ " aaaaaaaaa aaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ Style);
+ verifyFormat("SomeLongVariableName->someVeryLongFunctionName(\n"
+ " aaaaaaaaaaa aaaaaaaaa,\n"
+ " aaaaaaaaaaa aaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat("SomeLongVariableName->someFunction(\n"
+ " foooooooo(\n"
+ " aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));",
+ Style);
}
TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
@@ -4682,28 +4786,82 @@
" \"c\";");
}
-TEST_F(FormatTest, DefinitionReturnTypeBreakingStyle) {
+TEST_F(FormatTest, ReturnTypeBreakingStyle) {
FormatStyle Style = getLLVMStyle();
- Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel;
- verifyFormat("class C {\n"
+ // No declarations or definitions should be moved to own line.
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
+ verifyFormat("class A {\n"
" int f() { return 1; }\n"
+ " int g();\n"
"};\n"
- "int\n"
- "f() {\n"
- " return 1;\n"
- "}",
+ "int f() { return 1; }\n"
+ "int g();\n",
Style);
- Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
- verifyFormat("class C {\n"
+
+ // All declarations and definitions should have the return type moved to its
+ // own
+ // line.
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All;
+ verifyFormat("class E {\n"
" int\n"
" f() {\n"
" return 1;\n"
" }\n"
+ " int\n"
+ " g();\n"
"};\n"
"int\n"
"f() {\n"
" return 1;\n"
- "}",
+ "}\n"
+ "int\n"
+ "g();\n",
+ Style);
+
+ // Top-level definitions, and no kinds of declarations should have the
+ // return type moved to its own line.
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevelDefinitions;
+ verifyFormat("class B {\n"
+ " int f() { return 1; }\n"
+ " int g();\n"
+ "};\n"
+ "int\n"
+ "f() {\n"
+ " return 1;\n"
+ "}\n"
+ "int g();\n",
+ Style);
+
+ // Top-level definitions and declarations should have the return type moved
+ // to its own line.
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
+ verifyFormat("class C {\n"
+ " int f() { return 1; }\n"
+ " int g();\n"
+ "};\n"
+ "int\n"
+ "f() {\n"
+ " return 1;\n"
+ "}\n"
+ "int\n"
+ "g();\n",
+ Style);
+
+ // All definitions should have the return type moved to its own line, but no
+ // kinds of declarations.
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
+ verifyFormat("class D {\n"
+ " int\n"
+ " f() {\n"
+ " return 1;\n"
+ " }\n"
+ " int g();\n"
+ "};\n"
+ "int\n"
+ "f() {\n"
+ " return 1;\n"
+ "}\n"
+ "int g();\n",
Style);
verifyFormat("const char *\n"
"f(void) {\n" // Break here.
@@ -4944,6 +5102,15 @@
verifyFormat("llvm::errs() << aaaaaaaaaaaaaaaaaaaaaa << endl\n"
" << bbbbbbbbbbbbbbbbbbbbbb << endl;");
verifyFormat("llvm::errs() << endl << bbbbbbbbbbbbbbbbbbbbbb << endl;");
+
+ // Handle '\n'.
+ verifyFormat("llvm::errs() << aaaaaaaaaaaaaaaaaaaaaa << \"\\n\"\n"
+ " << bbbbbbbbbbbbbbbbbbbbbb << \"\\n\";");
+ verifyFormat("llvm::errs() << aaaaaaaaaaaaaaaaaaaaaa << \'\\n\'\n"
+ " << bbbbbbbbbbbbbbbbbbbbbb << \'\\n\';");
+ verifyFormat("llvm::errs() << aaaa << \"aaaaaaaaaaaaaaaaaa\\n\"\n"
+ " << bbbb << \"bbbbbbbbbbbbbbbbbb\\n\";");
+ verifyFormat("llvm::errs() << \"\\n\" << bbbbbbbbbbbbbbbbbbbbbb << \"\\n\";");
}
TEST_F(FormatTest, UnderstandsEquals) {
@@ -5317,6 +5484,7 @@
verifyFormat("bool operator!=();");
verifyFormat("int operator+();");
verifyFormat("int operator++();");
+ verifyFormat("bool operator,();");
verifyFormat("bool operator();");
verifyFormat("bool operator()();");
verifyFormat("bool operator[]();");
@@ -5332,6 +5500,8 @@
verifyFormat("void operator delete[](void *ptr);");
verifyFormat("template <typename AAAAAAA, typename BBBBBBB>\n"
"AAAAAAA operator/(const AAAAAAA &a, BBBBBBB &b);");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaa operator,(\n"
+ " aaaaaaaaaaaaaaaaaaaaa &aaaaaaaaaaaaaaaaaaaaaaaaaa) const;");
verifyFormat(
"ostream &operator<<(ostream &OutputStream,\n"
@@ -5509,6 +5679,7 @@
Left.PointerAlignment = FormatStyle::PAS_Left;
verifyFormat("x = *a(x) = *a(y);", Left);
verifyFormat("for (;; * = b) {\n}", Left);
+ verifyFormat("return *this += 1;", Left);
verifyIndependentOfContext("a = *(x + y);");
verifyIndependentOfContext("a = &(x + y);");
@@ -5638,7 +5809,7 @@
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n"
"aaaaaaaaaaaaaaaaaaaaaaa(int i);");
FormatStyle AfterType = getLLVMStyle();
- AfterType.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
+ AfterType.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
verifyFormat("__attribute__((nodebug)) void\n"
"foo() {}\n",
AfterType);
@@ -5789,6 +5960,8 @@
verifyFormat("virtual void foo(int *a, char *) const;");
verifyFormat("int a = sizeof(int *) + b;");
verifyFormat("int a = alignof(int *) + b;", getGoogleStyle());
+ verifyFormat("bool b = f(g<int>) && c;");
+ verifyFormat("typedef void (*f)(int i) func;");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *foo = (aaaaaaaaaaaaaaaaa *)\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
@@ -5821,6 +5994,7 @@
verifyFormat("#define DEREF_AND_CALL_F(x) f(*x)");
verifyFormat("some_var = function(*some_pointer_var)[0];");
verifyFormat("void f() { function(*some_pointer_var)[0] = 10; }");
+ verifyFormat("int x = f(&h)();");
}
TEST_F(FormatTest, FormatsPointersToArrayTypes) {
@@ -5937,6 +6111,10 @@
TEST_F(FormatTest, FormatsArrays) {
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]\n"
" [bbbbbbbbbbbbbbbbbbbbbbbbb] = c;");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaa(aaaaaaaaaaaa)]\n"
+ " [bbbbbbbbbbb(bbbbbbbbbbbb)] = c;");
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " aaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaa][aaaaaaaaaaaaa]) {\n}");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
@@ -5957,6 +6135,9 @@
" .aaaaaaaaaaaaaaaaaaaaaa();");
verifyNoCrash("a[,Y?)]", getLLVMStyleWithColumns(10));
+
+ FormatStyle NoColumnLimit = getLLVMStyleWithColumns(0);
+ verifyFormat("aaaaa[bbbbbb].cccccc()", NoColumnLimit);
}
TEST_F(FormatTest, LineStartsWithSpecialCharacter) {
@@ -6426,6 +6607,21 @@
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb};");
verifyNoCrash("a<,");
+
+ // No braced initializer here.
+ verifyFormat("void f() {\n"
+ " struct Dummy {};\n"
+ " f(v);\n"
+ "}");
+
+ // Long lists should be formatted in columns even if they are nested.
+ verifyFormat(
+ "vector<int> x = function({1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777});");
}
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
@@ -7163,6 +7359,11 @@
" interval:(float)theInterval {\n"
"}");
verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " longKeyword:(NSRect)theRect\n"
+ " longerKeyword:(float)theInterval\n"
+ " error:(NSError **)theError {\n"
+ "}");
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
" longKeyword:(NSRect)theRect\n"
" evenLongerKeyword:(float)theInterval\n"
" error:(NSError **)theError {\n"
@@ -7565,7 +7766,12 @@
" aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\"\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyFormat(
+ "NSArray *some_variable = @[\n"
+ " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n"
"];");
verifyFormat("NSArray *some_variable = @[\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
@@ -7573,12 +7779,6 @@
" @\"aaaaaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
"];");
- verifyGoogleFormat("NSArray *some_variable = @[\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\"\n"
- "];");
verifyFormat("NSArray *array = @[\n"
" @\"a\",\n"
" @\"a\",\n" // Trailing comma -> one per line.
@@ -8147,7 +8347,7 @@
"\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
"};",
Tab);
- verifyFormat("enum A {\n"
+ verifyFormat("enum AA {\n"
"\ta1, // Force multiple lines\n"
"\ta2,\n"
"\ta3\n"
@@ -8654,7 +8854,7 @@
Alignment);
verifyFormat("class C {\n"
"public:\n"
- " int i = 1;\n"
+ " int i = 1;\n"
" virtual void f() = 0;\n"
"};",
Alignment);
@@ -8703,6 +8903,19 @@
" loooooooooooooooooooooongParameterB);\n"
"int j = 2;",
Alignment);
+
+ verifyFormat("template <typename T, typename T_0 = very_long_type_name_0,\n"
+ " typename B = very_long_type_name_1,\n"
+ " typename T_2 = very_long_type_name_2>\n"
+ "auto foo() {}\n",
+ Alignment);
+ verifyFormat("int a, b = 1;\n"
+ "int c = 2;\n"
+ "int dd = 3;\n",
+ Alignment);
+ verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n"
+ "float b[1][] = {{3.f}};\n",
+ Alignment);
}
TEST_F(FormatTest, AlignConsecutiveDeclarations) {
@@ -8903,6 +9116,47 @@
"int myvar = 1;",
Alignment);
Alignment.ColumnLimit = 80;
+ Alignment.AlignConsecutiveAssignments = false;
+
+ verifyFormat(
+ "template <typename LongTemplate, typename VeryLongTemplateTypeName,\n"
+ " typename LongType, typename B>\n"
+ "auto foo() {}\n",
+ Alignment);
+ verifyFormat("float a, b = 1;\n"
+ "int c = 2;\n"
+ "int dd = 3;\n",
+ Alignment);
+ verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n"
+ "float b[1][] = {{3.f}};\n",
+ Alignment);
+ Alignment.AlignConsecutiveAssignments = true;
+ verifyFormat("float a, b = 1;\n"
+ "int c = 2;\n"
+ "int dd = 3;\n",
+ Alignment);
+ verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n"
+ "float b[1][] = {{3.f}};\n",
+ Alignment);
+ Alignment.AlignConsecutiveAssignments = false;
+
+ Alignment.ColumnLimit = 30;
+ Alignment.BinPackParameters = false;
+ verifyFormat("void foo(float a,\n"
+ " float b,\n"
+ " int c,\n"
+ " uint32_t *d) {\n"
+ " int * e = 0;\n"
+ " float f = 0;\n"
+ " double g = 0;\n"
+ "}\n"
+ "void bar(ino_t a,\n"
+ " int b,\n"
+ " uint32_t *c,\n"
+ " bool d) {}\n",
+ Alignment);
+ Alignment.BinPackParameters = true;
+ Alignment.ColumnLimit = 80;
}
TEST_F(FormatTest, LinuxBraceBreaking) {
@@ -8917,6 +9171,8 @@
" if (true) {\n"
" a();\n"
" b();\n"
+ " } else {\n"
+ " a();\n"
" }\n"
" }\n"
" void g() { return; }\n"
@@ -9563,12 +9819,15 @@
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
+ CHECK_PARSE_BOOL(DisableFormat);
CHECK_PARSE_BOOL(IndentCaseLabels);
CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
+ CHECK_PARSE_BOOL(ReflowComments);
+ CHECK_PARSE_BOOL(SortIncludes);
CHECK_PARSE_BOOL(SpacesInParentheses);
CHECK_PARSE_BOOL(SpacesInSquareBrackets);
CHECK_PARSE_BOOL(SpacesInAngles);
@@ -9718,6 +9977,19 @@
CHECK_PARSE("BreakBeforeBraces: Custom", BreakBeforeBraces,
FormatStyle::BS_Custom);
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All;
+ CHECK_PARSE("AlwaysBreakAfterReturnType: None", AlwaysBreakAfterReturnType,
+ FormatStyle::RTBS_None);
+ CHECK_PARSE("AlwaysBreakAfterReturnType: All", AlwaysBreakAfterReturnType,
+ FormatStyle::RTBS_All);
+ CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevel",
+ AlwaysBreakAfterReturnType, FormatStyle::RTBS_TopLevel);
+ CHECK_PARSE("AlwaysBreakAfterReturnType: AllDefinitions",
+ AlwaysBreakAfterReturnType, FormatStyle::RTBS_AllDefinitions);
+ CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevelDefinitions",
+ AlwaysBreakAfterReturnType,
+ FormatStyle::RTBS_TopLevelDefinitions);
+
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
CHECK_PARSE("AlwaysBreakAfterDefinitionReturnType: None",
AlwaysBreakAfterDefinitionReturnType, FormatStyle::DRTBS_None);
@@ -10317,6 +10589,8 @@
verifyFormat("auto my_lambda = [](const string &some_parameter) {\n"
" return some_parameter.size();\n"
"};");
+ verifyFormat("std::function<std::string(const std::string &)> my_lambda =\n"
+ " [](const string &s) { return s; };");
verifyFormat("int i = aaaaaa ? 1 //\n"
" : [] {\n"
" return 2; //\n"
@@ -10395,6 +10669,7 @@
// Lambdas created through weird macros.
verifyFormat("void f() {\n"
" MACRO((const AA &a) { return 1; });\n"
+ " MACRO((AA &a) { return 1; });\n"
"}");
verifyFormat("if (blah_blah(whatever, whatever, [] {\n"
@@ -10833,6 +11108,12 @@
verifyNoCrash("#define a\\\n /**/}");
}
+TEST_F(FormatTest, FormatsTableGenCode) {
+ FormatStyle Style = getLLVMStyle();
+ Style.Language = FormatStyle::LK_TableGen;
+ verifyFormat("include \"a.td\"\ninclude \"b.td\"", Style);
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index b491cd5..38fa5cd 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -80,8 +80,8 @@
" q();",
getGoogleJSStyleWithColumns(20));
verifyFormat("var x = aaaaaaaaaa ?\n"
- " bbbbbb :\n"
- " ccc;",
+ " bbbbbb :\n"
+ " ccc;",
getGoogleJSStyleWithColumns(20));
verifyFormat("var b = a.map((x) => x + 1);");
@@ -111,6 +111,13 @@
" interface: 1,\n"
" switch: 1,\n"
"};");
+ verifyFormat("var struct = 2;");
+ verifyFormat("var union = 2;");
+}
+
+TEST_F(FormatTestJS, CppKeywords) {
+ // Make sure we don't mess stuff up because of C++ keywords.
+ verifyFormat("return operator && (aa);");
}
TEST_F(FormatTestJS, ES6DestructuringAssignment) {
@@ -277,13 +284,16 @@
verifyFormat("var aaaaa: List<SomeThing> =\n"
" [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");
verifyFormat("return [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"];");
+ verifyFormat("return [\n"
+ " aaaa().bbbbbbbb('A'),\n"
+ " aaaa().bbbbbbbb('B'),\n"
+ " aaaa().bbbbbbbb('C'),\n"
+ "];");
verifyFormat("var someVariable = SomeFunction([\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"]);");
verifyFormat("var someVariable = SomeFunction([\n"
@@ -291,22 +301,33 @@
"]);",
getGoogleJSStyleWithColumns(51));
verifyFormat("var someVariable = SomeFunction(aaaa, [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"]);");
verifyFormat("var someVariable = SomeFunction(\n"
" aaaa,\n"
" [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
- " ccccccccccccccccccccccccccc\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccccccccc\n"
" ],\n"
" aaaa);");
+ verifyFormat("var aaaa = aaaaa || // wrap\n"
+ " [];");
verifyFormat("someFunction([], {a: a});");
}
+TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) {
+ verifyFormat("var array = [\n"
+ " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
+ " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
+ "];");
+ verifyFormat("var array = someFunction([\n"
+ " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
+ " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
+ "]);");
+}
+
TEST_F(FormatTestJS, FunctionLiterals) {
verifyFormat("doFoo(function() {});");
verifyFormat("doFoo(function() { return 1; });");
@@ -446,6 +467,12 @@
" }\n"
"}",
Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ verifyFormat("var func = function() {\n"
+ " return 1;\n"
+ "};",
+ Style);
}
TEST_F(FormatTestJS, MultipleFunctionLiterals) {
@@ -499,6 +526,12 @@
verifyFormat("getSomeLongPromise()\n"
" .then(function(value) { body(); })\n"
" .thenCatch(function(error) { body(); });");
+
+ verifyFormat("return [aaaaaaaaaaaaaaaaaaaaaa]\n"
+ " .aaaaaaa(function() {\n"
+ " //\n"
+ " })\n"
+ " .bbbbbb();");
}
TEST_F(FormatTestJS, ArrowFunctions) {
@@ -522,11 +555,11 @@
"};");
verifyFormat("var a = a.aaaaaaa(\n"
" (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
+ " aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
verifyFormat("var a = a.aaaaaaa(\n"
" (a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n"
- " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n"
- " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
+ " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n"
+ " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
// FIXME: This is bad, we should be wrapping before "() => {".
verifyFormat("someFunction(() => {\n"
@@ -543,6 +576,11 @@
"}");
}
+TEST_F(FormatTestJS, ForLoops) {
+ verifyFormat("for (var i in [2, 3]) {\n"
+ "}");
+}
+
TEST_F(FormatTestJS, AutomaticSemicolonInsertion) {
// The following statements must not wrap, as otherwise the program meaning
// would change due to automatic semicolon insertion.
@@ -553,6 +591,10 @@
verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10));
verifyFormat("aaaaaaaaa--;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("return [\n"
+ " aaa\n"
+ "];",
+ getGoogleJSStyleWithColumns(12));
}
TEST_F(FormatTestJS, ClosureStyleCasts) {
@@ -576,7 +618,7 @@
TEST_F(FormatTestJS, StringLiteralConcatenation) {
verifyFormat("var literal = 'hello ' +\n"
- " 'world';");
+ " 'world';");
}
TEST_F(FormatTestJS, RegexLiteralClassification) {
@@ -695,15 +737,22 @@
TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("var x: string;");
+ verifyFormat("var x: {a: string; b: number;} = {};");
verifyFormat("function x(): string {\n return 'x';\n}");
verifyFormat("function x(): {x: string} {\n return {x: 'x'};\n}");
verifyFormat("function x(y: string): string {\n return 'x';\n}");
verifyFormat("for (var y: string in x) {\n x();\n}");
+ verifyFormat("function x(y: {a?: number;} = {}): number {\n"
+ " return 12;\n"
+ "}");
verifyFormat("((a: string, b: number): string => a + b);");
verifyFormat("var x: (y: number) => string;");
verifyFormat("var x: P<string, (a: number) => string>;");
verifyFormat("var x = {y: function(): z { return 1; }};");
verifyFormat("var x = {y: function(): {a: number} { return 1; }};");
+ verifyFormat("function someFunc(args: string[]):\n"
+ " {longReturnValue: string[]} {}",
+ getGoogleJSStyleWithColumns(60));
}
TEST_F(FormatTestJS, ClassDeclarations) {
@@ -719,6 +768,16 @@
" aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
" aaaaaaaaaaaaaaaaaaaaaa {}\n"
"}");
+ verifyFormat("foo = class Name {\n"
+ " constructor() {}\n"
+ "};");
+ verifyFormat("foo = class {\n"
+ " constructor() {}\n"
+ "};");
+ verifyFormat("class C {\n"
+ " x: {y: Z;} = {};\n"
+ " private y: {y: Z;} = {};\n"
+ "}");
// ':' is not a type declaration here.
verifyFormat("class X {\n"
@@ -733,12 +792,18 @@
TEST_F(FormatTestJS, InterfaceDeclarations) {
verifyFormat("interface I {\n"
" x: string;\n"
+ " enum: string[];\n"
"}\n"
"var y;");
// Ensure that state is reset after parsing the interface.
verifyFormat("interface a {}\n"
"export function b() {}\n"
"var x;");
+
+ // Arrays of object type literals.
+ verifyFormat("interface I {\n"
+ " o: {}[];\n"
+ "}");
}
TEST_F(FormatTestJS, EnumDeclarations) {
@@ -775,6 +840,7 @@
TEST_F(FormatTestJS, Modules) {
verifyFormat("import SomeThing from 'some/module.js';");
verifyFormat("import {X, Y} from 'some/module.js';");
+ verifyFormat("import a, {X, Y} from 'some/module.js';");
verifyFormat("import {\n"
" VeryLongImportsAreAnnoying,\n"
" VeryLongImportsAreAnnoying,\n"
@@ -812,6 +878,7 @@
" y: string;\n"
"}");
verifyFormat("export class X { y: number; }");
+ verifyFormat("export abstract class X { y: number; }");
verifyFormat("export default class X { y: number }");
verifyFormat("export default function() {\n return 1;\n}");
verifyFormat("export var x = 12;");
@@ -828,6 +895,16 @@
" // adsdasd\n"
" BAZ\n"
"}");
+ verifyFormat("export default [\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ "];");
+ verifyFormat("export default [];");
+ verifyFormat("export default () => {};");
+ verifyFormat("export interface Foo { foo: number; }\n"
+ "export class Bar {\n"
+ " blah(): string { return this.blah; };\n"
+ "}");
}
TEST_F(FormatTestJS, TemplateStrings) {
@@ -846,7 +923,7 @@
getGoogleJSStyleWithColumns(35)); // Barely fits.
EXPECT_EQ("var x = `hello\n"
" ${world}` >=\n"
- " some();",
+ " some();",
format("var x =\n"
" `hello\n"
" ${world}` >= some();",
@@ -871,7 +948,7 @@
// are first token in line.
verifyFormat(
"var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
- " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;");
+ " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;");
// Two template strings.
verifyFormat("var x = `hello` == `hello`;");
@@ -890,6 +967,9 @@
"var y;");
verifyFormat("var x = `\"`; // comment with matching quote \"\n"
"var y;");
+ EXPECT_EQ("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa);",
+ format("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa) ;",
+ getGoogleJSStyleWithColumns(40)));
// Backticks in a comment - not a template string.
EXPECT_EQ("var x = 1 // `/*a`;\n"
" ;",
@@ -927,6 +1007,14 @@
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}");
}
+TEST_F(FormatTestJS, UserDefinedTypeGuards) {
+ verifyFormat(
+ "function foo(check: Object):\n"
+ " check is {foo: string, bar: string, baz: string, foobar: string} {\n"
+ " return 'bar' in check;\n"
+ "}\n");
+}
+
TEST_F(FormatTestJS, OptionalTypes) {
verifyFormat("function x(a?: b, c?, d?) {}");
verifyFormat("class X {\n"
@@ -967,5 +1055,15 @@
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
}
+TEST_F(FormatTestJS, JSDocAnnotations) {
+ EXPECT_EQ("/**\n"
+ " * @export {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ format("/**\n"
+ " * @export {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp
index 160c220..8fadfc0 100644
--- a/unittests/Format/FormatTestJava.cpp
+++ b/unittests/Format/FormatTestJava.cpp
@@ -426,6 +426,7 @@
verifyFormat("public void union(Type a, Type b);");
verifyFormat("public void struct(Object o);");
verifyFormat("public void delete(Object o);");
+ verifyFormat("return operator && (aa);");
}
TEST_F(FormatTestJava, NeverAlignAfterReturn) {
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index 0dadd3b..d3d3d42 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -88,9 +88,10 @@
TEST_F(FormatTestProto, MessageFieldAttributes) {
verifyFormat("optional string test = 1 [default = \"test\"];");
verifyFormat("optional bool a = 1 [default = true, deprecated = true];");
- verifyFormat("optional LongMessageType long_proto_field = 1\n"
- " [default = REALLY_REALLY_LONG_CONSTANT_VALUE,\n"
- " deprecated = true];");
+ verifyFormat("optional LongMessageType long_proto_field = 1 [\n"
+ " default = REALLY_REALLY_LONG_CONSTANT_VALUE,\n"
+ " deprecated = true\n"
+ "];");
verifyFormat("optional LongMessageType long_proto_field = 1\n"
" [default = REALLY_REALLY_LONG_CONSTANT_VALUE];");
verifyFormat("repeated double value = 1\n"
@@ -103,6 +104,16 @@
" aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
" bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
"}];");
+ verifyFormat("repeated double value = 1 [\n"
+ " (aaaaaaa.aaaaaaaaa) = {\n"
+ " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
+ " },\n"
+ " (bbbbbbb.bbbbbbbbb) = {\n"
+ " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
+ " }\n"
+ "];");
verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
" type: \"AAAAAAAAAA\"\n"
" is: \"AAAAAAAAAA\"\n"
@@ -113,6 +124,14 @@
" bbbbbbb: BBBB,\n"
" bbbb: BBB\n"
"}];");
+ verifyFormat("optional AAA aaa = 1 [\n"
+ " foo = {\n"
+ " key: 'a' //\n"
+ " },\n"
+ " bar = {\n"
+ " key: 'a' //\n"
+ " }\n"
+ "];");
}
TEST_F(FormatTestProto, DoesntWrapFileOptions) {
@@ -130,7 +149,6 @@
" field_c: \"OK\"\n"
" msg_field: {field_d: 123}\n"
"};");
-
verifyFormat("option (MyProto.options) = {\n"
" field_a: OK\n"
" field_b: \"OK\"\n"
@@ -140,18 +158,22 @@
" field_e: OK\n"
" }\n"
"};");
-
verifyFormat("option (MyProto.options) = {\n"
" field_a: OK // Comment\n"
" field_b: \"OK\"\n"
" field_c: \"OK\"\n"
" msg_field: {field_d: 123}\n"
"};");
-
verifyFormat("option (MyProto.options) = {\n"
" field_c: \"OK\"\n"
" msg_field{field_d: 123}\n"
"};");
+
+ // Support syntax with <> instead of {}.
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_c: \"OK\",\n"
+ " msg_field: <field_d: 123>\n"
+ "};");
}
TEST_F(FormatTestProto, FormatsService) {
@@ -162,5 +184,10 @@
"};");
}
+TEST_F(FormatTestProto, ExtendingMessage) {
+ verifyFormat("extend .foo.Bar {\n"
+ "}");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestSelective.cpp b/unittests/Format/FormatTestSelective.cpp
index d53d1c0..699600c 100644
--- a/unittests/Format/FormatTestSelective.cpp
+++ b/unittests/Format/FormatTestSelective.cpp
@@ -162,6 +162,13 @@
"// This is\n"
"// not formatted. ",
0, 0));
+ EXPECT_EQ("int x; // Format this line.\n"
+ "int xx; //\n"
+ "int xxxxx; //",
+ format("int x; // Format this line.\n"
+ "int xx; //\n"
+ "int xxxxx; //",
+ 0, 0));
}
TEST_F(FormatTestSelective, IndividualStatementsOfNestedBlocks) {
diff --git a/unittests/Format/SortIncludesTest.cpp b/unittests/Format/SortIncludesTest.cpp
index 84bc554..dbe1174 100644
--- a/unittests/Format/SortIncludesTest.cpp
+++ b/unittests/Format/SortIncludesTest.cpp
@@ -28,7 +28,14 @@
reformat(Style, Sorted, Ranges, FileName));
}
+ unsigned newCursor(llvm::StringRef Code, unsigned Cursor) {
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ sortIncludes(Style, Code, Ranges, "input.cpp", &Cursor);
+ return Cursor;
+ }
+
FormatStyle Style = getLLVMStyle();
+
};
TEST_F(SortIncludesTest, BasicSorting) {
@@ -40,6 +47,35 @@
"#include \"b.h\"\n"));
}
+TEST_F(SortIncludesTest, SupportClangFormatOff) {
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n"
+ "// clang-format off\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "// clang-format on\n",
+ sort("#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "// clang-format off\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "// clang-format on\n"));
+}
+
+TEST_F(SortIncludesTest, IncludeSortingCanBeDisabled) {
+ Style.SortIncludes = false;
+ EXPECT_EQ("#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"b.h\"\n",
+ sort("#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"b.h\"\n"));
+}
+
TEST_F(SortIncludesTest, MixIncludeAndImport) {
EXPECT_EQ("#include \"a.h\"\n"
"#import \"b.h\"\n"
@@ -130,13 +166,21 @@
"#include \"c.h\"\n",
sort("#include \"llvm/a.h\"\n"
"#include \"c.h\"\n"
- "#include \"b.h\"\n"));
+ "#include \"b.h\"\n",
+ "a.cc"));
EXPECT_EQ("#include \"llvm/a.h\"\n"
"#include \"b.h\"\n"
"#include \"c.h\"\n",
sort("#include \"llvm/a.h\"\n"
"#include \"c.h\"\n"
"#include \"b.h\"\n",
+ "a_main.cc"));
+ EXPECT_EQ("#include \"llvm/input.h\"\n"
+ "#include \"b.h\"\n"
+ "#include \"c.h\"\n",
+ sort("#include \"llvm/input.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"b.h\"\n",
"input.mm"));
// Don't do this in headers.
@@ -146,7 +190,64 @@
sort("#include \"llvm/a.h\"\n"
"#include \"c.h\"\n"
"#include \"b.h\"\n",
- "some_header.h"));
+ "a.h"));
+
+ // Only do this in the first #include block.
+ EXPECT_EQ("#include <a>\n"
+ "\n"
+ "#include \"b.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"llvm/a.h\"\n",
+ sort("#include <a>\n"
+ "\n"
+ "#include \"llvm/a.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"b.h\"\n",
+ "a.cc"));
+
+ // Only recognize the first #include with a matching basename as main include.
+ EXPECT_EQ("#include \"a.h\"\n"
+ "#include \"b.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"llvm/a.h\"\n",
+ sort("#include \"b.h\"\n"
+ "#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"llvm/a.h\"\n",
+ "a.cc"));
+}
+
+TEST_F(SortIncludesTest, NegativePriorities) {
+ Style.IncludeCategories = {{".*important_os_header.*", -1}, {".*", 1}};
+ EXPECT_EQ("#include \"important_os_header.h\"\n"
+ "#include \"c_main.h\"\n"
+ "#include \"a_other.h\"\n",
+ sort("#include \"c_main.h\"\n"
+ "#include \"a_other.h\"\n"
+ "#include \"important_os_header.h\"\n",
+ "c_main.cc"));
+
+ // check stable when re-run
+ EXPECT_EQ("#include \"important_os_header.h\"\n"
+ "#include \"c_main.h\"\n"
+ "#include \"a_other.h\"\n",
+ sort("#include \"important_os_header.h\"\n"
+ "#include \"c_main.h\"\n"
+ "#include \"a_other.h\"\n",
+ "c_main.cc"));
+}
+
+TEST_F(SortIncludesTest, CalculatesCorrectCursorPosition) {
+ std::string Code = "#include <ccc>\n" // Start of line: 0
+ "#include <bbbbbb>\n" // Start of line: 15
+ "#include <a>\n"; // Start of line: 33
+ EXPECT_EQ(31u, newCursor(Code, 0));
+ EXPECT_EQ(13u, newCursor(Code, 15));
+ EXPECT_EQ(0u, newCursor(Code, 33));
+
+ EXPECT_EQ(41u, newCursor(Code, 10));
+ EXPECT_EQ(23u, newCursor(Code, 25));
+ EXPECT_EQ(10u, newCursor(Code, 43));
}
} // end namespace
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index d9a87a5..ff11aea 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -176,8 +176,8 @@
EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
}
@@ -195,8 +195,8 @@
EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
}
@@ -205,8 +205,17 @@
Replacements Replaces;
Replaces.insert(Replacement("", 4, 0, "\"\n\""));
// Assume '"12345678"' is turned into '"1234"\n"5678"'.
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 4)); // "123|5678"
- EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "1234|678"
+ EXPECT_EQ(3u, shiftedCodePosition(Replaces, 3)); // "123|5678"
+ EXPECT_EQ(7u, shiftedCodePosition(Replaces, 4)); // "1234|678"
+ EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "12345|78"
+}
+
+TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
+ Replacements Replaces;
+ // Replace the first four characters with "abcd".
+ Replaces.insert(Replacement("", 0, 4, "abcd"));
+ for (unsigned i = 0; i < 3; ++i)
+ EXPECT_EQ(i, shiftedCodePosition(Replaces, i));
}
class FlushRewrittenFilesTest : public ::testing::Test {
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index becebf0..e190dec 100644
--- a/unittests/libclang/LibclangTest.cpp
+++ b/unittests/libclang/LibclangTest.cpp
@@ -379,8 +379,10 @@
Filename = Path.str();
Files.insert(Filename);
}
+ llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename));
std::ofstream OS(Filename);
OS << Contents;
+ assert(OS.good());
}
void DisplayDiagnostics() {
unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);
@@ -465,3 +467,30 @@
ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
}
+
+TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {
+ // Provide a fake GCC 99.9.9 standard library that always overrides any local
+ // GCC installation.
+ std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o",
+ "include/arm-linux-gnueabi/.keep",
+ "include/c++/99.9.9/vector"};
+
+ for (auto &Name : EmptyFiles)
+ WriteFile(Name, "\n");
+
+ std::string Filename = "test.cc";
+ WriteFile(Filename, "#include <vector>\n");
+
+ std::string Clang = "bin/clang";
+ WriteFile(Clang, "");
+
+ const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi",
+ "--gcc-toolchain="};
+
+ EXPECT_EQ(CXError_Success,
+ clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv,
+ sizeof(Argv) / sizeof(Argv[0]),
+ nullptr, 0, TUFlags, &ClangTU));
+ EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
+ DisplayDiagnostics();
+}
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 0c28576..c057444 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -279,6 +279,8 @@
OS << " OS << \" \";\n";
OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
} else if (type == "IdentifierInfo *") {
+ if (isOptional())
+ OS << " if (SA->get" << getUpperName() << "())\n ";
OS << " OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
} else if (type == "TypeSourceInfo *") {
@@ -617,7 +619,7 @@
std::vector<std::string> uniques;
std::set<std::string> unique_set(enums.begin(), enums.end());
for (const auto &i : enums) {
- std::set<std::string>::iterator set_i = unique_set.find(i);
+ auto set_i = unique_set.find(i);
if (set_i != unique_set.end()) {
uniques.push_back(i);
unique_set.erase(set_i);
@@ -663,8 +665,7 @@
OS << type << " " << getUpperName();
}
void writeDeclarations(raw_ostream &OS) const override {
- std::vector<std::string>::const_iterator i = uniques.begin(),
- e = uniques.end();
+ auto i = uniques.cbegin(), e = uniques.cend();
// The last one needs to not have a comma.
--e;
@@ -769,8 +770,7 @@
bool isVariadicEnumArg() const override { return true; }
void writeDeclarations(raw_ostream &OS) const override {
- std::vector<std::string>::const_iterator i = uniques.begin(),
- e = uniques.end();
+ auto i = uniques.cbegin(), e = uniques.cend();
// The last one needs to not have a comma.
--e;
@@ -956,7 +956,7 @@
}
void writeTemplateInstantiation(raw_ostream &OS) const override {
- OS << " " << getType() << " *tempInst" << getUpperName()
+ OS << " auto *tempInst" << getUpperName()
<< " = new (C, 16) " << getType()
<< "[A->" << getLowerName() << "_size()];\n";
OS << " {\n";
@@ -1072,9 +1072,9 @@
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
- ArrayRef<Record*> Bases = Search->getSuperClasses();
- for (const auto *Base : llvm::make_range(Bases.rbegin(), Bases.rend())) {
- if ((Ptr = createArgument(Arg, Attr, Base)))
+ ArrayRef<std::pair<Record*, SMRange>> Bases = Search->getSuperClasses();
+ for (const auto &Base : llvm::make_range(Bases.rbegin(), Bases.rend())) {
+ if ((Ptr = createArgument(Arg, Attr, Base.first)))
break;
}
}
@@ -1381,7 +1381,7 @@
if (Args.empty())
continue;
- if (Args[0]->getSuperClasses().back()->getName() != "TypeArgument")
+ if (Args[0]->getSuperClasses().back().first->getName() != "TypeArgument")
continue;
// All these spellings take a single type argument.
@@ -1419,7 +1419,7 @@
static bool isIdentifierArgument(Record *Arg) {
return !Arg->getSuperClasses().empty() &&
- llvm::StringSwitch<bool>(Arg->getSuperClasses().back()->getName())
+ llvm::StringSwitch<bool>(Arg->getSuperClasses().back().first->getName())
.Case("IdentifierArgument", true)
.Case("EnumArgument", true)
.Case("VariadicEnumArgument", true)
@@ -1476,13 +1476,13 @@
if (!R.getValueAsBit("ASTNode"))
continue;
- ArrayRef<Record *> Supers = R.getSuperClasses();
+ ArrayRef<std::pair<Record *, SMRange>> Supers = R.getSuperClasses();
assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
std::string SuperName;
- for (const auto *Super : llvm::make_range(Supers.rbegin(), Supers.rend())) {
- const Record &R = *Super;
- if (R.getName() != "TargetSpecificAttr" && SuperName.empty())
- SuperName = R.getName();
+ for (const auto &Super : llvm::make_range(Supers.rbegin(), Supers.rend())) {
+ const Record *R = Super.first;
+ if (R->getName() != "TargetSpecificAttr" && SuperName.empty())
+ SuperName = R->getName();
}
OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
@@ -1535,7 +1535,7 @@
}
OS << ", SourceRange Loc = SourceRange()";
OS << ") {\n";
- OS << " " << R.getName() << "Attr *A = new (Ctx) " << R.getName();
+ OS << " auto *A = new (Ctx) " << R.getName();
OS << "Attr(Loc, Ctx, ";
for (auto const &ai : Args) {
if (ai->isFake() && !emitFake) continue;
@@ -1652,7 +1652,7 @@
OS << "};\n\n";
}
- OS << "#endif\n";
+ OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n";
}
// Emits the class method definitions for attributes.
@@ -1727,7 +1727,7 @@
static void EmitAttrList(raw_ostream &OS, StringRef Class,
const std::vector<Record*> &AttrList) {
- std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end();
+ auto i = AttrList.cbegin(), e = AttrList.cend();
if (i != e) {
// Move the end iterator back to emit the last attribute.
@@ -1879,7 +1879,7 @@
OS << " case attr::" << R.getName() << ": {\n";
Args = R.getValueAsListOfDefs("Args");
if (R.isSubClassOf(InhClass) || !Args.empty())
- OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
+ OS << " const auto *SA = cast<" << R.getName()
<< "Attr>(A);\n";
if (R.isSubClassOf(InhClass))
OS << " Record.push_back(SA->isInherited());\n";
@@ -2043,9 +2043,7 @@
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
OS << "case AttrSyntax::CXX: {\n";
// C++11-style attributes are further split out based on the Scope.
- for (std::map<std::string, std::vector<Record *>>::iterator I = CXX.begin(),
- E = CXX.end();
- I != E; ++I) {
+ for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) {
if (I != CXX.begin())
OS << " else ";
if (I->first.empty())
@@ -2195,7 +2193,7 @@
continue;
}
- OS << " const " << R.getName() << "Attr *A = cast<"
+ OS << " const auto *A = cast<"
<< R.getName() << "Attr>(At);\n";
bool TDependent = R.getValueAsBit("TemplateDependent");
@@ -2403,7 +2401,7 @@
// If this code has already been generated, simply return the previous
// instance of it.
static std::set<std::string> CustomSubjectSet;
- std::set<std::string>::iterator I = CustomSubjectSet.find(FnName);
+ auto I = CustomSubjectSet.find(FnName);
if (I != CustomSubjectSet.end())
return *I;
@@ -2417,7 +2415,7 @@
}
OS << "static bool " << FnName << "(const Decl *D) {\n";
- OS << " if (const " << GetSubjectWithSuffix(Base) << " *S = dyn_cast<";
+ OS << " if (const auto *S = dyn_cast<";
OS << GetSubjectWithSuffix(Base);
OS << ">(D))\n";
OS << " return " << Subject.getValueAsString("CheckCode") << ";\n";
@@ -2517,7 +2515,7 @@
// If this code has already been generated, simply return the previous
// instance of it.
static std::set<std::string> CustomLangOptsSet;
- std::set<std::string>::iterator I = CustomLangOptsSet.find(FnName);
+ auto I = CustomLangOptsSet.find(FnName);
if (I != CustomLangOptsSet.end())
return *I;
@@ -2580,7 +2578,7 @@
// If this code has already been generated, simply return the previous
// instance of it.
static std::set<std::string> CustomTargetSet;
- std::set<std::string>::iterator I = CustomTargetSet.find(FnName);
+ auto I = CustomTargetSet.find(FnName);
if (I != CustomTargetSet.end())
return *I;
@@ -2798,13 +2796,13 @@
Args = R.getValueAsListOfDefs("Args");
if (!Args.empty()) {
- OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
+ OS << " const auto *SA = cast<" << R.getName()
<< "Attr>(A);\n";
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writeDump(OS);
- for (auto AI = Args.begin(), AE = Args.end(); AI != AE; ++AI)
- createArgument(**AI, R.getName())->writeDumpChildren(OS);
+ for (const auto *AI : Args)
+ createArgument(*AI, R.getName())->writeDumpChildren(OS);
}
OS <<
" break;\n"
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index efce521..bbc2bdb 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -152,13 +152,12 @@
}
static SMRange findSuperClassRange(const Record *R, StringRef SuperName) {
- ArrayRef<Record *> Supers = R->getSuperClasses();
-
- for (size_t i = 0, e = Supers.size(); i < e; ++i)
- if (Supers[i]->getName() == SuperName)
- return R->getSuperClassRanges()[i];
-
- return SMRange();
+ ArrayRef<std::pair<Record *, SMRange>> Supers = R->getSuperClasses();
+ auto I = std::find_if(Supers.begin(), Supers.end(),
+ [&](const std::pair<Record *, SMRange> &SuperPair) {
+ return SuperPair.first->getName() == SuperName;
+ });
+ return (I != Supers.end()) ? I->second : SMRange();
}
/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 6e7bc90..a298cb1 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -1926,7 +1926,7 @@
ClassKind CK = ClassNone;
if (R->getSuperClasses().size() >= 2)
- CK = ClassMap[R->getSuperClasses()[1]];
+ CK = ClassMap[R->getSuperClasses()[1].first];
std::vector<std::pair<TypeSpec, TypeSpec>> NewTypeSpecs;
for (auto TS : TypeSpecs) {
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 4484e65..724b0e1 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -13,6 +13,7 @@
#include "TableGenBackends.h" // Declares all backends.
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/TableGen/Error.h"
@@ -244,6 +245,8 @@
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
+ llvm_shutdown_obj Y;
+
return TableGenMain(argv[0], &ClangTableGenMain);
}
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index d0503c6..ab68518 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -218,11 +218,11 @@
try:
if Verbose == 1:
print " Executing: %s" % (ScriptPath,)
- check_call("chmod +x %s" % ScriptPath, cwd = Cwd,
+ check_call("chmod +x '%s'" % ScriptPath, cwd = Cwd,
stderr=PBuildLogFile,
stdout=PBuildLogFile,
shell=True)
- check_call(ScriptPath, cwd = Cwd, stderr=PBuildLogFile,
+ check_call("'%s'" % ScriptPath, cwd = Cwd, stderr=PBuildLogFile,
stdout=PBuildLogFile,
shell=True)
except:
@@ -261,7 +261,7 @@
print " Applying patch."
try:
- check_call("patch -p1 < %s" % (PatchfilePath),
+ check_call("patch -p1 < '%s'" % (PatchfilePath),
cwd = PatchedSourceDirPath,
stderr=PBuildLogFile,
stdout=PBuildLogFile,
@@ -285,8 +285,8 @@
# Run scan-build from within the patched source directory.
SBCwd = os.path.join(Dir, PatchedSourceDirName)
- SBOptions = "--use-analyzer " + Clang + " "
- SBOptions += "-plist-html -o " + SBOutputDir + " "
+ SBOptions = "--use-analyzer '%s' " % Clang
+ SBOptions += "-plist-html -o '%s' " % SBOutputDir
SBOptions += "-enable-checker " + AllCheckers + " "
SBOptions += "--keep-empty "
# Always use ccc-analyze to ensure that we can locate the failures
@@ -376,8 +376,8 @@
raise Exception()
# Build and call the analyzer command.
- OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
- Command = CmdPrefix + OutputOption + FileName
+ OutputOption = "-o '%s.plist' " % os.path.join(PlistPath, FileName)
+ Command = CmdPrefix + OutputOption + ("'%s'" % FileName)
LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
try:
if Verbose == 1:
@@ -397,23 +397,30 @@
if Failed == False:
os.remove(LogFile.name);
+def getBuildLogPath(SBOutputDir):
+ return os.path.join(SBOutputDir, LogFolderName, BuildLogName)
+
+def removeLogFile(SBOutputDir):
+ BuildLogPath = getBuildLogPath(SBOutputDir)
+ # Clean up the log file.
+ if (os.path.exists(BuildLogPath)) :
+ RmCommand = "rm '%s'" % BuildLogPath
+ if Verbose == 1:
+ print " Executing: %s" % (RmCommand,)
+ check_call(RmCommand, shell=True)
+
def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time()
- BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
+ BuildLogPath = getBuildLogPath(SBOutputDir)
print "Log file: %s" % (BuildLogPath,)
print "Output directory: %s" %(SBOutputDir, )
- # Clean up the log file.
- if (os.path.exists(BuildLogPath)) :
- RmCommand = "rm " + BuildLogPath
- if Verbose == 1:
- print " Executing: %s" % (RmCommand,)
- check_call(RmCommand, shell=True)
+ removeLogFile(SBOutputDir)
# Clean up scan build results.
if (os.path.exists(SBOutputDir)) :
- RmCommand = "rm -r " + SBOutputDir
+ RmCommand = "rm -r '%s'" % SBOutputDir
if Verbose == 1:
print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True)
@@ -585,6 +592,19 @@
print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
return (NumDiffs > 0)
+def cleanupReferenceResults(SBOutputDir):
+ # Delete html, css, and js files from reference results. These can
+ # include multiple copies of the benchmark source and so get very large.
+ Extensions = ["html", "css", "js"]
+ for E in Extensions:
+ for F in glob.glob("%s/*/*.%s" % (SBOutputDir, E)):
+ P = os.path.join(SBOutputDir, F)
+ RmCommand = "rm '%s'" % P
+ check_call(RmCommand, shell=True)
+
+ # Remove the log file. It leaks absolute path names.
+ removeLogFile(SBOutputDir)
+
def updateSVN(Mode, ProjectsMap):
try:
ProjectsMap.seek(0)
@@ -593,9 +613,9 @@
Path = os.path.join(ProjName, getSBOutputDirName(True))
if Mode == "delete":
- Command = "svn delete %s" % (Path,)
+ Command = "svn delete '%s'" % (Path,)
else:
- Command = "svn add %s" % (Path,)
+ Command = "svn add '%s'" % (Path,)
if Verbose == 1:
print " Executing: %s" % (Command,)
@@ -634,6 +654,8 @@
if IsReferenceBuild == False:
runCmpResults(Dir, Strictness)
+ else:
+ cleanupReferenceResults(SBOutputDir)
print "Completed tests for project %s (time: %.2f)." % \
(ID, (time.time()-TBegin))
diff --git a/utils/perf-training/CMakeLists.txt b/utils/perf-training/CMakeLists.txt
new file mode 100644
index 0000000..f8647a0
--- /dev/null
+++ b/utils/perf-training/CMakeLists.txt
@@ -0,0 +1,62 @@
+
+# All test suites added here should be excuded from check-all
+set(EXCLUDE_FROM_ALL On)
+
+if (CMAKE_CFG_INTDIR STREQUAL ".")
+ set(LLVM_BUILD_MODE ".")
+else ()
+ set(LLVM_BUILD_MODE "%(build_mode)s")
+endif ()
+
+string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} CLANG_TOOLS_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
+
+if(LLVM_BUILD_INSTRUMENTED)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/pgo-data/lit.site.cfg
+ )
+
+ add_lit_testsuite(generate-profraw "Generating clang PGO data"
+ ${CMAKE_CURRENT_BINARY_DIR}/pgo-data/
+ DEPENDS clang clear-profraw
+ )
+
+ add_custom_target(clear-profraw
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py clean ${CMAKE_CURRENT_BINARY_DIR} profraw
+ COMMENT "Clearing old profraw data")
+
+ if(NOT LLVM_PROFDATA)
+ find_program(LLVM_PROFDATA llvm-profdata)
+ endif()
+
+ if(NOT LLVM_PROFDATA)
+ message(FATAL_ERROR "Must set LLVM_PROFDATA to point to llvm-profdata to use for merging PGO data")
+ endif()
+
+ add_custom_target(generate-profdata
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py merge ${LLVM_PROFDATA} ${CMAKE_CURRENT_BINARY_DIR}/clang.profdata ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Merging profdata"
+ DEPENDS generate-profraw)
+endif()
+
+find_program(DTRACE dtrace)
+if(DTRACE)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/order-files.lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/order-files/lit.site.cfg
+ )
+
+ add_lit_testsuite(generate-dtrace-logs "Generating clang dtrace data"
+ ${CMAKE_CURRENT_BINARY_DIR}/order-files/
+ DEPENDS clang clear-dtrace-logs
+ )
+
+ add_custom_target(clear-dtrace-logs
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py clean ${CMAKE_CURRENT_BINARY_DIR} dtrace
+ COMMENT "Clearing old dtrace data")
+
+ add_custom_target(generate-order-file
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py gen-order-file --binary $<TARGET_FILE:clang> --output ${CLANG_ORDER_FILE} ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating order file"
+ DEPENDS generate-dtrace-logs)
+endif()
diff --git a/utils/perf-training/README.txt b/utils/perf-training/README.txt
new file mode 100644
index 0000000..cfbce40
--- /dev/null
+++ b/utils/perf-training/README.txt
@@ -0,0 +1,6 @@
+==========================
+ Performance Training Data
+==========================
+
+This directory contains simple source files for use as training data for
+generating PGO data and linker order files for clang.
diff --git a/utils/perf-training/cxx/hello_world.cpp b/utils/perf-training/cxx/hello_world.cpp
new file mode 100644
index 0000000..66e00d0
--- /dev/null
+++ b/utils/perf-training/cxx/hello_world.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cpp -c %s
+#include <iostream>
+
+int main(int, char**) {
+ std::cout << "Hello, World!";
+ return 0;
+}
diff --git a/utils/perf-training/lit.cfg b/utils/perf-training/lit.cfg
new file mode 100644
index 0000000..af4b43b
--- /dev/null
+++ b/utils/perf-training/lit.cfg
@@ -0,0 +1,37 @@
+# -*- Python -*-
+
+from lit import Test
+import lit.formats
+import lit.util
+
+def getSysrootFlagsOnDarwin(config, lit_config):
+ # On Darwin, support relocatable SDKs by providing Clang with a
+ # default system root path.
+ if 'darwin' in config.target_triple:
+ try:
+ out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
+ res = 0
+ except OSError:
+ res = -1
+ if res == 0 and out:
+ sdk_path = out
+ lit_config.note('using SDKROOT: %r' % sdk_path)
+ return '-isysroot %s' % sdk_path
+ return ''
+
+sysroot_flags = getSysrootFlagsOnDarwin(config, lit_config)
+
+config.clang = lit.util.which('clang', config.clang_tools_dir).replace('\\', '/')
+
+config.name = 'Clang Perf Training'
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap']
+
+use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
+config.test_format = lit.formats.ShTest(use_lit_shell == "0")
+config.substitutions.append( ('%clang_cpp', ' %s --driver-mode=cpp %s ' % (config.clang, sysroot_flags)))
+config.substitutions.append( ('%clang_cc1', ' %s -cc1 %s ' % (config.clang, sysroot_flags)))
+config.substitutions.append( ('%clang', ' %s %s ' % (config.clang, sysroot_flags) ) )
+config.substitutions.append( ('%test_root', config.test_exec_root ) )
+
+config.environment['LLVM_PROFILE_FILE'] = 'perf-training-%p.profraw'
+
diff --git a/utils/perf-training/lit.site.cfg.in b/utils/perf-training/lit.site.cfg.in
new file mode 100644
index 0000000..9dc3802
--- /dev/null
+++ b/utils/perf-training/lit.site.cfg.in
@@ -0,0 +1,20 @@
+import sys
+
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
+config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@"
+config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+ config.clang_tools_dir = config.clang_tools_dir % lit_config.params
+except KeyError:
+ e = sys.exc_info()[1]
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/utils/perf-training/lit.cfg")
diff --git a/utils/perf-training/order-files.lit.cfg b/utils/perf-training/order-files.lit.cfg
new file mode 100644
index 0000000..0e151bf
--- /dev/null
+++ b/utils/perf-training/order-files.lit.cfg
@@ -0,0 +1,39 @@
+# -*- Python -*-
+
+from lit import Test
+import lit.formats
+import lit.util
+import os
+
+def getSysrootFlagsOnDarwin(config, lit_config):
+ # On Darwin, support relocatable SDKs by providing Clang with a
+ # default system root path.
+ if 'darwin' in config.target_triple:
+ try:
+ out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
+ res = 0
+ except OSError:
+ res = -1
+ if res == 0 and out:
+ sdk_path = out
+ lit_config.note('using SDKROOT: %r' % sdk_path)
+ return '-isysroot %s' % sdk_path
+ return ''
+
+sysroot_flags = getSysrootFlagsOnDarwin(config, lit_config)
+
+config.clang = os.path.realpath(lit.util.which('clang', config.clang_tools_dir)).replace('\\', '/')
+
+config.name = 'Clang Perf Training'
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap']
+
+dtrace_wrapper = '%s %s/perf-helper.py dtrace' % (config.python_exe, config.test_source_root)
+
+use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
+config.test_format = lit.formats.ShTest(use_lit_shell == "0")
+config.substitutions.append( ('%clang_cpp', ' %s %s --driver-mode=cpp %s ' % (dtrace_wrapper, config.clang, sysroot_flags)))
+config.substitutions.append( ('%clang_cc1', ' %s %s -cc1 %s ' % (dtrace_wrapper, config.clang, sysroot_flags)))
+config.substitutions.append( ('%clang', ' %s %s %s ' % (dtrace_wrapper, config.clang, sysroot_flags) ) )
+config.substitutions.append( ('%test_root', config.test_exec_root ) )
+
+
diff --git a/utils/perf-training/order-files.lit.site.cfg.in b/utils/perf-training/order-files.lit.site.cfg.in
new file mode 100644
index 0000000..b5d4bbb
--- /dev/null
+++ b/utils/perf-training/order-files.lit.site.cfg.in
@@ -0,0 +1,21 @@
+import sys
+
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
+config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@"
+config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_exe = "@PYTHON_EXECUTABLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+ config.clang_tools_dir = config.clang_tools_dir % lit_config.params
+except KeyError:
+ e = sys.exc_info()[1]
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/utils/perf-training/order-files.lit.cfg")
diff --git a/utils/perf-training/perf-helper.py b/utils/perf-training/perf-helper.py
new file mode 100644
index 0000000..a4ae68c
--- /dev/null
+++ b/utils/perf-training/perf-helper.py
@@ -0,0 +1,351 @@
+#===- perf-helper.py - Clang Python Bindings -----------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+from __future__ import print_function
+
+import sys
+import os
+import subprocess
+import argparse
+import time
+import bisect
+
+def findFilesWithExtension(path, extension):
+ filenames = []
+ for root, dirs, files in os.walk(path):
+ for filename in files:
+ if filename.endswith(extension):
+ filenames.append(os.path.join(root, filename))
+ return filenames
+
+def clean(args):
+ if len(args) != 2:
+ print('Usage: %s clean <path> <extension>\n' % __file__ +
+ '\tRemoves all files with extension from <path>.')
+ return 1
+ for filename in findFilesWithExtension(args[0], args[1]):
+ os.remove(filename)
+ return 0
+
+def merge(args):
+ if len(args) != 3:
+ print('Usage: %s clean <llvm-profdata> <output> <path>\n' % __file__ +
+ '\tMerges all profraw files from path into output.')
+ return 1
+ cmd = [args[0], 'merge', '-o', args[1]]
+ cmd.extend(findFilesWithExtension(args[2], "profraw"))
+ subprocess.check_call(cmd)
+ return 0
+
+def dtrace(args):
+ parser = argparse.ArgumentParser(prog='perf-helper dtrace',
+ description='dtrace wrapper for order file generation')
+ parser.add_argument('--buffer-size', metavar='size', type=int, required=False,
+ default=1, help='dtrace buffer size in MB (default 1)')
+ parser.add_argument('--use-oneshot', required=False, action='store_true',
+ help='Use dtrace\'s oneshot probes')
+ parser.add_argument('--use-ustack', required=False, action='store_true',
+ help='Use dtrace\'s ustack to print function names')
+ parser.add_argument('cmd', nargs='*', help='')
+
+ # Use python's arg parser to handle all leading option arguments, but pass
+ # everything else through to dtrace
+ first_cmd = next(arg for arg in args if not arg.startswith("--"))
+ last_arg_idx = args.index(first_cmd)
+
+ opts = parser.parse_args(args[:last_arg_idx])
+ cmd = args[last_arg_idx:]
+
+ if opts.use_oneshot:
+ target = "oneshot$target:::entry"
+ else:
+ target = "pid$target:::entry"
+ predicate = '%s/probemod=="%s"/' % (target, os.path.basename(args[0]))
+ log_timestamp = 'printf("dtrace-TS: %d\\n", timestamp)'
+ if opts.use_ustack:
+ action = 'ustack(1);'
+ else:
+ action = 'printf("dtrace-Symbol: %s\\n", probefunc);'
+ dtrace_script = "%s { %s; %s }" % (predicate, log_timestamp, action)
+
+ dtrace_args = []
+ if not os.geteuid() == 0:
+ print(
+ 'Script must be run as root, or you must add the following to your sudoers:'
+ + '%%admin ALL=(ALL) NOPASSWD: /usr/sbin/dtrace')
+ dtrace_args.append("sudo")
+
+ dtrace_args.extend((
+ 'dtrace', '-xevaltime=exec',
+ '-xbufsize=%dm' % (opts.buffer_size),
+ '-q', '-n', dtrace_script,
+ '-c', ' '.join(cmd)))
+
+ if sys.platform == "darwin":
+ dtrace_args.append('-xmangled')
+
+ f = open("%d.dtrace" % os.getpid(), "w")
+ start_time = time.time()
+ subprocess.check_call(dtrace_args, stdout=f, stderr=subprocess.PIPE)
+ elapsed = time.time() - start_time
+ print("... data collection took %.4fs" % elapsed)
+
+ return 0
+
+def parse_dtrace_symbol_file(path, all_symbols, all_symbols_set,
+ missing_symbols, opts):
+ def fix_mangling(symbol):
+ if sys.platform == "darwin":
+ if symbol[0] != '_' and symbol != 'start':
+ symbol = '_' + symbol
+ return symbol
+
+ def get_symbols_with_prefix(symbol):
+ start_index = bisect.bisect_left(all_symbols, symbol)
+ for s in all_symbols[start_index:]:
+ if not s.startswith(symbol):
+ break
+ yield s
+
+ # Extract the list of symbols from the given file, which is assumed to be
+ # the output of a dtrace run logging either probefunc or ustack(1) and
+ # nothing else. The dtrace -xdemangle option needs to be used.
+ #
+ # This is particular to OS X at the moment, because of the '_' handling.
+ with open(path) as f:
+ current_timestamp = None
+ for ln in f:
+ # Drop leading and trailing whitespace.
+ ln = ln.strip()
+ if not ln.startswith("dtrace-"):
+ continue
+
+ # If this is a timestamp specifier, extract it.
+ if ln.startswith("dtrace-TS: "):
+ _,data = ln.split(': ', 1)
+ if not data.isdigit():
+ print("warning: unrecognized timestamp line %r, ignoring" % ln,
+ file=sys.stderr)
+ continue
+ current_timestamp = int(data)
+ continue
+ elif ln.startswith("dtrace-Symbol: "):
+
+ _,ln = ln.split(': ', 1)
+ if not ln:
+ continue
+
+ # If there is a '`' in the line, assume it is a ustack(1) entry in
+ # the form of <modulename>`<modulefunc>, where <modulefunc> is never
+ # truncated (but does need the mangling patched).
+ if '`' in ln:
+ yield (current_timestamp, fix_mangling(ln.split('`',1)[1]))
+ continue
+
+ # Otherwise, assume this is a probefunc printout. DTrace on OS X
+ # seems to have a bug where it prints the mangled version of symbols
+ # which aren't C++ mangled. We just add a '_' to anything but start
+ # which doesn't already have a '_'.
+ symbol = fix_mangling(ln)
+
+ # If we don't know all the symbols, or the symbol is one of them,
+ # just return it.
+ if not all_symbols_set or symbol in all_symbols_set:
+ yield (current_timestamp, symbol)
+ continue
+
+ # Otherwise, we have a symbol name which isn't present in the
+ # binary. We assume it is truncated, and try to extend it.
+
+ # Get all the symbols with this prefix.
+ possible_symbols = list(get_symbols_with_prefix(symbol))
+ if not possible_symbols:
+ continue
+
+ # If we found too many possible symbols, ignore this as a prefix.
+ if len(possible_symbols) > 100:
+ print( "warning: ignoring symbol %r " % symbol +
+ "(no match and too many possible suffixes)", file=sys.stderr)
+ continue
+
+ # Report that we resolved a missing symbol.
+ if opts.show_missing_symbols and symbol not in missing_symbols:
+ print("warning: resolved missing symbol %r" % symbol, file=sys.stderr)
+ missing_symbols.add(symbol)
+
+ # Otherwise, treat all the possible matches as having occurred. This
+ # is an over-approximation, but it should be ok in practice.
+ for s in possible_symbols:
+ yield (current_timestamp, s)
+
+def check_output(*popen_args, **popen_kwargs):
+ p = subprocess.Popen(stdout=subprocess.PIPE, *popen_args, **popen_kwargs)
+ stdout,stderr = p.communicate()
+ if p.wait() != 0:
+ raise RuntimeError("process failed")
+ return stdout
+
+def uniq(list):
+ seen = set()
+ for item in list:
+ if item not in seen:
+ yield item
+ seen.add(item)
+
+def form_by_call_order(symbol_lists):
+ # Simply strategy, just return symbols in order of occurrence, even across
+ # multiple runs.
+ return uniq(s for symbols in symbol_lists for s in symbols)
+
+def form_by_call_order_fair(symbol_lists):
+ # More complicated strategy that tries to respect the call order across all
+ # of the test cases, instead of giving a huge preference to the first test
+ # case.
+
+ # First, uniq all the lists.
+ uniq_lists = [list(uniq(symbols)) for symbols in symbol_lists]
+
+ # Compute the successors for each list.
+ succs = {}
+ for symbols in uniq_lists:
+ for a,b in zip(symbols[:-1], symbols[1:]):
+ succs[a] = items = succs.get(a, [])
+ if b not in items:
+ items.append(b)
+
+ # Emit all the symbols, but make sure to always emit all successors from any
+ # call list whenever we see a symbol.
+ #
+ # There isn't much science here, but this sometimes works better than the
+ # more naive strategy. Then again, sometimes it doesn't so more research is
+ # probably needed.
+ return uniq(s
+ for symbols in symbol_lists
+ for node in symbols
+ for s in ([node] + succs.get(node,[])))
+
+def form_by_frequency(symbol_lists):
+ # Form the order file by just putting the most commonly occurring symbols
+ # first. This assumes the data files didn't use the oneshot dtrace method.
+
+ counts = {}
+ for symbols in symbol_lists:
+ for a in symbols:
+ counts[a] = counts.get(a,0) + 1
+
+ by_count = counts.items()
+ by_count.sort(key = lambda (_,n): -n)
+ return [s for s,n in by_count]
+
+def form_by_random(symbol_lists):
+ # Randomize the symbols.
+ merged_symbols = uniq(s for symbols in symbol_lists
+ for s in symbols)
+ random.shuffle(merged_symbols)
+ return merged_symbols
+
+def form_by_alphabetical(symbol_lists):
+ # Alphabetize the symbols.
+ merged_symbols = list(set(s for symbols in symbol_lists for s in symbols))
+ merged_symbols.sort()
+ return merged_symbols
+
+methods = dict((name[len("form_by_"):],value)
+ for name,value in locals().items() if name.startswith("form_by_"))
+
+def genOrderFile(args):
+ parser = argparse.ArgumentParser(
+ "%prog [options] <dtrace data file directories>]")
+ parser.add_argument('input', nargs='+', help='')
+ parser.add_argument("--binary", metavar="PATH", type=str, dest="binary_path",
+ help="Path to the binary being ordered (for getting all symbols)",
+ default=None)
+ parser.add_argument("--output", dest="output_path",
+ help="path to output order file to write", default=None, required=True,
+ metavar="PATH")
+ parser.add_argument("--show-missing-symbols", dest="show_missing_symbols",
+ help="show symbols which are 'fixed up' to a valid name (requires --binary)",
+ action="store_true", default=None)
+ parser.add_argument("--output-unordered-symbols",
+ dest="output_unordered_symbols_path",
+ help="write a list of the unordered symbols to PATH (requires --binary)",
+ default=None, metavar="PATH")
+ parser.add_argument("--method", dest="method",
+ help="order file generation method to use", choices=methods.keys(),
+ default='call_order')
+ opts = parser.parse_args(args)
+
+ # If the user gave us a binary, get all the symbols in the binary by
+ # snarfing 'nm' output.
+ if opts.binary_path is not None:
+ output = check_output(['nm', '-P', opts.binary_path])
+ lines = output.split("\n")
+ all_symbols = [ln.split(' ',1)[0]
+ for ln in lines
+ if ln.strip()]
+ print("found %d symbols in binary" % len(all_symbols))
+ all_symbols.sort()
+ else:
+ all_symbols = []
+ all_symbols_set = set(all_symbols)
+
+ # Compute the list of input files.
+ input_files = []
+ for dirname in opts.input:
+ input_files.extend(findFilesWithExtension(dirname, "dtrace"))
+
+ # Load all of the input files.
+ print("loading from %d data files" % len(input_files))
+ missing_symbols = set()
+ timestamped_symbol_lists = [
+ list(parse_dtrace_symbol_file(path, all_symbols, all_symbols_set,
+ missing_symbols, opts))
+ for path in input_files]
+
+ # Reorder each symbol list.
+ symbol_lists = []
+ for timestamped_symbols_list in timestamped_symbol_lists:
+ timestamped_symbols_list.sort()
+ symbol_lists.append([symbol for _,symbol in timestamped_symbols_list])
+
+ # Execute the desire order file generation method.
+ method = methods.get(opts.method)
+ result = list(method(symbol_lists))
+
+ # Report to the user on what percentage of symbols are present in the order
+ # file.
+ num_ordered_symbols = len(result)
+ if all_symbols:
+ print("note: order file contains %d/%d symbols (%.2f%%)" % (
+ num_ordered_symbols, len(all_symbols),
+ 100.*num_ordered_symbols/len(all_symbols)), file=sys.stderr)
+
+ if opts.output_unordered_symbols_path:
+ ordered_symbols_set = set(result)
+ with open(opts.output_unordered_symbols_path, 'w') as f:
+ f.write("\n".join(s for s in all_symbols if s not in ordered_symbols_set))
+
+ # Write the order file.
+ with open(opts.output_path, 'w') as f:
+ f.write("\n".join(result))
+ f.write("\n")
+
+ return 0
+
+commands = {'clean' : clean,
+ 'merge' : merge,
+ 'dtrace' : dtrace,
+ 'gen-order-file' : genOrderFile}
+
+def main():
+ f = commands[sys.argv[1]]
+ sys.exit(f(sys.argv[2:]))
+
+if __name__ == '__main__':
+ main()
diff --git a/www/comparison.html b/www/comparison.html
index 4bca65d..26f421d 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -55,8 +55,8 @@
by Clang. For instance, in C mode, GCC supports
<a href="http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html">nested
functions</a> and has an
- <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37428">undocumented
- extension allowing VLAs in structs</a>.
+ <a href="https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html">extension
+ allowing VLAs in structs</a>.
</ul>
<p>Pro's of clang vs GCC:</p>
@@ -95,12 +95,13 @@
that produced it (it is not a structured format).</li>
<li>Clang is <a href="features.html#performance">much faster and uses far
less memory</a> than GCC.</li>
- <li>Clang aims to provide extremely clear and concise diagnostics (error and
- warning messages), and includes support for <a
- href="diagnostics.html">expressive diagnostics</a>. GCC's warnings are
- sometimes acceptable, but are often confusing and it does not support
- expressive diagnostics. Clang also preserves typedefs in diagnostics
- consistently, showing macro expansions and many other features.</li>
+ <li>Clang has been designed from the start to provide extremely clear and
+ concise diagnostics (error and warning messages), and includes support
+ for <a href="diagnostics.html">expressive diagnostics</a>.
+ Modern versions of GCC have made significant advances in this area,
+ incorporating various Clang features such as preserving typedefs in
+ diagnostics and showing macro expansions, but GCC is still catching
+ up.</li>
<li>GCC is licensed under the GPL license. <a href="features.html#license">
clang uses a BSD license,</a> which allows it to be embedded in
software that is not GPL-licensed.</li>
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 0c53391..9bf8f91 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -587,11 +587,11 @@
<td>A union's associated types should include the union itself</td>
<td class="full" align="center">Yes</td>
</tr>
- <tr class="open" id="92">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#92">92</a></td>
- <td>extension</td>
+ <tr id="92">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#92">92</a></td>
+ <td>accepted</td>
<td>Should <I>exception-specification</I>s be part of the type system?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="93">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#93">93</a></td>
@@ -1464,11 +1464,11 @@
<td>Explicit instantiation and base class members</td>
<td class="full" align="center">Duplicate of <a href="#470">470</a></td>
</tr>
- <tr class="open" id="238">
+ <tr id="238">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#238">238</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Precision and accuracy constraints on floating point</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="239">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#239">239</a></td>
@@ -1488,11 +1488,11 @@
<td>Error in example in 14.8.1</td>
<td class="full" align="center">Yes</td>
</tr>
- <tr class="open" id="242">
+ <tr id="242">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#242">242</a></td>
- <td>drafting</td>
+ <td>tentatively ready</td>
<td>Interpretation of old-style casts</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="243">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#243">243</a></td>
@@ -2019,7 +2019,7 @@
</tr>
<tr id="330">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#330">330</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Qualification conversions and pointers to arrays of pointers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -2397,7 +2397,7 @@
</tr>
<tr id="393">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#393">393</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Pointer to array of unknown bound in template argument list in parameter</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -2483,7 +2483,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#407">407</a></td>
<td>C++11</td>
<td>Named class with associated typedef: two names or one?</td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Clang 3.8</td>
</tr>
<tr id="408">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#408">408</a></td>
@@ -3365,7 +3365,7 @@
</tr>
<tr class="open" id="554">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#554">554</a></td>
- <td>review</td>
+ <td>drafting</td>
<td>Definition of “declarative region” and “scope”</td>
<td align="center">Not resolved</td>
</tr>
@@ -3587,7 +3587,7 @@
</tr>
<tr id="591">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#591">591</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>When a dependent base class is the current instantiation</td>
<td class="none" align="center">No</td>
</tr>
@@ -3695,7 +3695,7 @@
</tr>
<tr id="609">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#609">609</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>What is a “top-level” cv-qualifier?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -5476,8 +5476,8 @@
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="944">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#944">944</a></td>
- <td>open</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#944">944</a></td>
+ <td>extension</td>
<td><TT>reinterpret_cast</TT> for all types with the same size and alignment</td>
<td align="center">Not resolved</td>
</tr>
@@ -5735,7 +5735,7 @@
</tr>
<tr id="987">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#987">987</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Which declarations introduce namespace members?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -5939,7 +5939,7 @@
</tr>
<tr id="1021">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1021">1021</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Definitions of namespace members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7294,8 +7294,8 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1247">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1247">1247</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1247">1247</a></td>
+ <td>DRWP</td>
<td>Restriction on alias name appearing in <I>type-id</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7455,11 +7455,11 @@
<td>Accessibility and function signatures</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1274">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1274">1274</a></td>
- <td>drafting</td>
+ <tr id="1274">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1274">1274</a></td>
+ <td>DR</td>
<td>Common nonterminal for <I>expression</I> and <I>braced-init-list</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1275">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1275">1275</a></td>
@@ -7515,11 +7515,11 @@
<td>Static data members of classes with typedef name for linkage purposes</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1284">
+ <tr id="1284">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1284">1284</a></td>
- <td>drafting</td>
+ <td>tentatively ready</td>
<td>Should the lifetime of an array be independent of that of its elements?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1285">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1285">1285</a></td>
@@ -7565,7 +7565,7 @@
</tr>
<tr id="1292">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1292">1292</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Dependent calls with <I>braced-init-list</I>s containing a pack expansion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7666,8 +7666,8 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1309">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1309">1309</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1309">1309</a></td>
+ <td>DRWP</td>
<td>Incorrect note regarding lookup of a member of the current instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7701,11 +7701,11 @@
<td>Pointer arithmetic within standard-layout objects</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1315">
+ <tr id="1315">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1315">1315</a></td>
- <td>drafting</td>
+ <td>tentatively ready</td>
<td>Restrictions on non-type template arguments in partial specializations</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1316">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1316">1316</a></td>
@@ -7841,7 +7841,7 @@
</tr>
<tr id="1338">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1338">1338</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Aliasing and allocation functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7857,11 +7857,11 @@
<td>Complete type in member pointer expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1341">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1341">1341</a></td>
- <td>drafting</td>
+ <tr id="1341">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1341">1341</a></td>
+ <td>NAD</td>
<td>Bit-field initializers</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1342">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1342">1342</a></td>
@@ -7919,7 +7919,7 @@
</tr>
<tr id="1351">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1351">1351</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Problems with implicitly-declared <I>exception-specification</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7949,7 +7949,7 @@
</tr>
<tr id="1356">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1356">1356</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Exception specifications of copy assignment operators with virtual bases</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8157,11 +8157,11 @@
<td>Dependency of alias template specializations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1391">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1391">1391</a></td>
- <td>drafting</td>
+ <tr id="1391">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1391">1391</a></td>
+ <td>DR</td>
<td>Conversions to parameter types with non-deduced template arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1392">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td>
@@ -8195,7 +8195,7 @@
</tr>
<tr id="1397">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397">1397</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Class completeness in non-static data member initializers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8489,7 +8489,7 @@
</tr>
<tr id="1446">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1446">1446</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Member function with no <I>ref-qualifier</I> and non-member function with rvalue reference</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8603,7 +8603,7 @@
</tr>
<tr id="1465">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1465">1465</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>noexcept</TT> and <TT>std::bad_array_new_length</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8615,7 +8615,7 @@
</tr>
<tr id="1467">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467">1467</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>List-initialization of aggregate from same-type object</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -8717,7 +8717,7 @@
</tr>
<tr id="1484">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1484">1484</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Unused local classes of function templates</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8753,7 +8753,7 @@
</tr>
<tr id="1490">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1490">1490</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>List-initialization from a string literal</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -8765,7 +8765,7 @@
</tr>
<tr id="1492">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1492">1492</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Exception specifications on template destructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8787,11 +8787,11 @@
<td>Partial specialization of variadic class template</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1496">
+ <tr id="1496">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1496">1496</a></td>
- <td>drafting</td>
+ <td>tentatively ready</td>
<td>Triviality with deleted and missing default constructors</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1497">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1497">1497</a></td>
@@ -8921,7 +8921,7 @@
</tr>
<tr class="open" id="1518">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518">1518</a></td>
- <td>drafting</td>
+ <td>review</td>
<td>Explicit default constructors and copy-list-initialization</td>
<td align="center">Not resolved</td>
</tr>
@@ -9125,7 +9125,7 @@
</tr>
<tr id="1552">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1552">1552</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><I>exception-specification</I>s and defaulted special member functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9161,7 +9161,7 @@
</tr>
<tr id="1558">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1558">1558</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Unused arguments in alias template specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9239,19 +9239,19 @@
</tr>
<tr id="1571">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1571">1571</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>cv-qualification for indirect reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1572">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1572">1572</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Incorrect example for rvalue reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1573">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1573">1573</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Inherited constructor characteristics</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9305,7 +9305,7 @@
</tr>
<tr class="open" id="1582">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1582">1582</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Template default arguments and deduction failure</td>
<td align="center">Not resolved</td>
</tr>
@@ -9317,7 +9317,7 @@
</tr>
<tr class="open" id="1584">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584">1584</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Deducing function types from cv-qualified types</td>
<td align="center">Not resolved</td>
</tr>
@@ -9347,7 +9347,7 @@
</tr>
<tr id="1589">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1589">1589</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Ambiguous ranking of list-initialization sequences</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -9359,7 +9359,7 @@
</tr>
<tr id="1591">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1591">1591</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Deducing array bound and element type from initializer list</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9389,7 +9389,7 @@
</tr>
<tr id="1596">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1596">1596</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Non-array objects as <TT>array[1]</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9413,7 +9413,7 @@
</tr>
<tr id="1600">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1600">1600</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Erroneous reference initialization in example</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9431,7 +9431,7 @@
</tr>
<tr id="1603">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1603">1603</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Errors resulting from giving unnamed namespaces internal linkage</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9497,13 +9497,13 @@
</tr>
<tr id="1614">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1614">1614</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Address of pure virtual function vs odr-use</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1615">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1615">1615</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Alignment of types, variables, and members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9593,13 +9593,13 @@
</tr>
<tr id="1630">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1630">1630</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Multiple default constructor templates</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1631">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1631">1631</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Incorrect overload resolution for single-element <I>initializer-list</I></td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -9611,7 +9611,7 @@
</tr>
<tr id="1633">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1633">1633</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Copy-initialization in member initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9639,15 +9639,15 @@
<td>Recursion in <TT>constexpr</TT> template default constructor</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1638">
+ <tr id="1638">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1638">1638</a></td>
- <td>drafting</td>
+ <td>tentatively ready</td>
<td>Declaring an explicit specialization of a scoped enumeration</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1639">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1639">1639</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><I>exception-specification</I>s and pointer/pointer-to-member expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9681,11 +9681,11 @@
<td>Equivalent <I>exception-specification</I>s in function template declarations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1645">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1645">1645</a></td>
- <td>drafting</td>
+ <tr id="1645">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1645">1645</a></td>
+ <td>DR</td>
<td>Identical inheriting constructors via default arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1646">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1646">1646</a></td>
@@ -9724,16 +9724,16 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1652">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1652">1652</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1652">1652</a></td>
+ <td>DRWP</td>
<td>Object addresses in <TT>constexpr</TT> expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1653">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1653">1653</a></td>
- <td>drafting</td>
+ <tr id="1653">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1653">1653</a></td>
+ <td>accepted</td>
<td>Removing deprecated increment of <TT>bool</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1654">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1654">1654</a></td>
@@ -9755,7 +9755,7 @@
</tr>
<tr id="1657">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1657">1657</a></td>
- <td>accepted</td>
+ <td>WP</td>
<td>Attributes for namespaces and enumerators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9777,11 +9777,11 @@
<td><I>member-declaration</I> requirements and unnamed bit-fields</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1661">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1661">1661</a></td>
- <td>concurrency</td>
+ <tr id="1661">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1661">1661</a></td>
+ <td>NAD</td>
<td>Preservation of infinite loops</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1662">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1662">1662</a></td>
@@ -9845,7 +9845,7 @@
</tr>
<tr id="1672">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1672">1672</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Layout compatibility with multiple empty bases</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9929,7 +9929,7 @@
</tr>
<tr id="1686">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1686">1686</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Which variables are “explicitly declared <TT>const</TT>?”</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9977,7 +9977,7 @@
</tr>
<tr id="1694">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1694">1694</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Restriction on reference to temporary as a constant expression</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9989,7 +9989,7 @@
</tr>
<tr id="1696">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1696">1696</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Temporary lifetime and non-static data member initializers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10043,7 +10043,7 @@
</tr>
<tr id="1705">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1705">1705</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Unclear specification of “more specialized”</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10061,7 +10061,7 @@
</tr>
<tr id="1708">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1708">1708</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>overly-strict requirements for names with C language linkage</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10073,7 +10073,7 @@
</tr>
<tr class="open" id="1710">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1710">1710</a></td>
- <td>review</td>
+ <td>drafting</td>
<td>Missing <TT>template</TT> keyword in <I>class-or-decltype</I></td>
<td align="center">Not resolved</td>
</tr>
@@ -10085,7 +10085,7 @@
</tr>
<tr id="1712">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1712">1712</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>constexpr</TT> variable template declarations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10101,11 +10101,11 @@
<td>odr-use of <TT>this</TT> from a local class</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1715">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1715">1715</a></td>
- <td>drafting</td>
+ <tr id="1715">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1715">1715</a></td>
+ <td>DR</td>
<td>Access and inherited constructor templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1716">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1716">1716</a></td>
@@ -10127,7 +10127,7 @@
</tr>
<tr id="1719">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1719">1719</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Layout compatibility and cv-qualification revisited</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10143,11 +10143,11 @@
<td>Diagnosing ODR violations for static data members</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1722">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1722">1722</a></td>
- <td>drafting</td>
+ <tr id="1722">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1722">1722</a></td>
+ <td>DR</td>
<td>Should lambda to function pointer conversion function be <TT>noexcept</TT>?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1723">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1723">1723</a></td>
@@ -10215,11 +10215,11 @@
<td>Return type and value for <TT>operator=</TT> with <I>ref-qualifier</I></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1734">
+ <tr id="1734">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1734">1734</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Nontrivial deleted copy functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1735">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1735">1735</a></td>
@@ -10227,11 +10227,11 @@
<td>Out-of-range literals in <I>user-defined-literal</I>s</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1736">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1736">1736</a></td>
- <td>drafting</td>
+ <tr id="1736">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1736">1736</a></td>
+ <td>DR</td>
<td>Inheriting constructor templates in a local class</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1737">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1737">1737</a></td>
@@ -10269,15 +10269,15 @@
<td><I>using-declaration</I>s and scoped enumerators</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1743">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1743">1743</a></td>
- <td>open</td>
+ <tr id="1743">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1743">1743</a></td>
+ <td>NAD</td>
<td><I>init-capture</I>s in nested lambdas</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1744">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1744">1744</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Unordered initialization for variable template specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10301,7 +10301,7 @@
</tr>
<tr id="1748">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1748">1748</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Placement new with a null pointer</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
@@ -10313,25 +10313,25 @@
</tr>
<tr id="1750">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1750">1750</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>“Argument” vs “parameter”</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1751">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1751">1751</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Non-trivial operations vs non-trivial initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1752">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1752">1752</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Right-recursion in <I>mem-initializer-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1753">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1753">1753</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10349,19 +10349,19 @@
</tr>
<tr id="1756">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1756">1756</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Direct-list-initialization of a non-class object</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
<tr id="1757">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1757">1757</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Const integral subobjects</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1758">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1758">1758</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Explicit conversion in copy/move list initialization</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -10409,7 +10409,7 @@
</tr>
<tr id="1766">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766">1766</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Values outside the range of the values of an enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10457,7 +10457,7 @@
</tr>
<tr id="1774">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1774">1774</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Discrepancy between subobject destruction and stack unwinding</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10475,7 +10475,7 @@
</tr>
<tr id="1777">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1777">1777</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Empty pack expansion in <I>dynamic-exception-specification</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10487,13 +10487,13 @@
</tr>
<tr id="1779">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1779">1779</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Type dependency of <TT>__func__</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1780">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1780">1780</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Explicit instantiation/specialization of generic lambda <TT>operator()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10505,7 +10505,7 @@
</tr>
<tr id="1782">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1782">1782</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Form of initialization for <TT>nullptr_t</TT> to <TT>bool</TT> conversion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10541,7 +10541,7 @@
</tr>
<tr id="1788">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1788">1788</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Sized deallocation of array of non-class type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10559,7 +10559,7 @@
</tr>
<tr id="1791">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1791">1791</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Incorrect restrictions on <I>cv-qualifier-seq</I> and <I>ref-qualifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10571,7 +10571,7 @@
</tr>
<tr id="1793">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1793">1793</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>thread_local</TT> in explicit specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10583,19 +10583,19 @@
</tr>
<tr id="1795">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1795">1795</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Disambiguating <I>original-namespace-definition</I> and <I>extension-namespace-definition</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1796">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1796">1796</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Is all-bits-zero for null characters a meaningful requirement?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1797">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1797">1797</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Are all bit patterns of <TT>unsigned char</TT> distinct numbers?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10607,13 +10607,13 @@
</tr>
<tr id="1799">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1799">1799</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>mutable</TT> and non-explicit const qualification</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1800">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1800">1800</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Pointer to member of nested anonymous union</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10625,7 +10625,7 @@
</tr>
<tr id="1802">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1802">1802</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>char16_t</TT> string literals and surrogate pairs</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10637,25 +10637,25 @@
</tr>
<tr id="1804">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1804">1804</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Partial specialization and friendship</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1805">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1805">1805</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Conversions of array operands in <I>conditional-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1806">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1806">1806</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Virtual bases and move-assignment</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1807">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1807">1807</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Order of destruction of array elements after an exception</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10667,19 +10667,19 @@
</tr>
<tr id="1809">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1809">1809</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Narrowing and template argument deduction</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1810">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1810">1810</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Invalid <I>ud-suffix</I>es</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1811">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1811">1811</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Lookup of deallocation function in a virtual destructor definition</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10691,25 +10691,25 @@
</tr>
<tr id="1813">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813">1813</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Direct vs indirect bases in standard-layout classes</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1814">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1814">1814</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Default arguments in <I>lambda-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1815">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1815">1815</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Lifetime extension in aggregate initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1816">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1816">1816</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Unclear specification of bit-field values</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10727,7 +10727,7 @@
</tr>
<tr id="1819">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1819">1819</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Acceptable scopes for definition of partial specialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10751,13 +10751,13 @@
</tr>
<tr id="1823">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1823">1823</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>String literal uniqueness in inline functions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1824">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1824">1824</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Completeness of return type vs point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10767,11 +10767,11 @@
<td>Partial ordering between variadic and non-variadic function templates</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1826">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1826">1826</a></td>
- <td>open</td>
+ <tr id="1826">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1826">1826</a></td>
+ <td>NAD</td>
<td><TT>const</TT> floating-point in constant expressions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1827">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1827">1827</a></td>
@@ -10793,7 +10793,7 @@
</tr>
<tr id="1830">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1830">1830</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Repeated specifiers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10805,7 +10805,7 @@
</tr>
<tr id="1832">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1832">1832</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Casting to incomplete enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10817,7 +10817,7 @@
</tr>
<tr id="1834">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1834">1834</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Constant initialization binding a reference to an xvalue</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10841,7 +10841,7 @@
</tr>
<tr id="1838">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1838">1838</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Definition via <I>unqualified-id</I> and <I>using-declaration</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10871,7 +10871,7 @@
</tr>
<tr id="1843">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1843">1843</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Bit-field in conditional operator with <TT>throw</TT> operand</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10889,19 +10889,19 @@
</tr>
<tr id="1846">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1846">1846</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Declaring explicitly-defaulted implicitly-deleted functions</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1847">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1847">1847</a></td>
- <td>drafting</td>
+ <tr id="1847">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1847">1847</a></td>
+ <td>DR</td>
<td>Clarifying compatibility during partial ordering</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1848">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1848">1848</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Parenthesized constructor and destructor declarators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10913,19 +10913,19 @@
</tr>
<tr id="1850">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1850">1850</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Differences between definition context and point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1851">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1851">1851</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>decltype(auto)</TT> in <I>new-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1852">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1852">1852</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Wording issues regarding <TT>decltype(auto)</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10961,7 +10961,7 @@
</tr>
<tr id="1858">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1858">1858</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Comparing pointers to union members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10989,11 +10989,11 @@
<td>Determining “corresponding members” for friendship</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1863">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1863">1863</a></td>
- <td>drafting</td>
+ <tr id="1863">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1863">1863</a></td>
+ <td>DR</td>
<td>Requirements on thrown object type to support <TT>std::current_exception()</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1864">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1864">1864</a></td>
@@ -11003,13 +11003,13 @@
</tr>
<tr id="1865">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1865">1865</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Pointer arithmetic and multi-level qualification conversions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1866">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1866">1866</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Initializing variant members with non-trivial destructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11033,7 +11033,7 @@
</tr>
<tr id="1870">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1870">1870</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Contradictory wording about definitions vs explicit specialization/instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11050,20 +11050,20 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1873">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1873">1873</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1873">1873</a></td>
+ <td>DRWP</td>
<td>Protected member access from derived class friends</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1874">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1874">1874</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Type vs non-type template parameters with <TT>class</TT> keyword</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1875">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1875">1875</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1875">1875</a></td>
+ <td>DRWP</td>
<td>Reordering declarations in class scope</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11075,13 +11075,13 @@
</tr>
<tr id="1877">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1877">1877</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Return type deduction from <TT>return</TT> with no operand</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1878">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1878">1878</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>operator auto</TT> template</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11099,13 +11099,13 @@
</tr>
<tr id="1881">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1881">1881</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Standard-layout classes and unnamed bit-fields</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1882">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1882">1882</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Reserved names without library use</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11123,25 +11123,25 @@
</tr>
<tr id="1885">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1885">1885</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Return value of a function is underspecified</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1886">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1886">1886</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1886">1886</a></td>
+ <td>DRWP</td>
<td>Language linkage for <TT>main()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1887">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1887">1887</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Problems with <TT>::</TT> as <I>nested-name-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1888">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1888">1888</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1888">1888</a></td>
+ <td>DRWP</td>
<td>Implicitly-declared default constructors and <TT>explicit</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11159,13 +11159,13 @@
</tr>
<tr id="1891">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1891">1891</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Move constructor/assignment for closure class</td>
<td class="full" align="center">Clang 3.6</td>
</tr>
<tr id="1892">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1892">1892</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Use of <TT>auto</TT> in function type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11181,11 +11181,11 @@
<td><I>typedef-name</I>s and <I>using-declaration</I>s</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1895">
+ <tr id="1895">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1895">1895</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Deleted conversions in conditional operator operands</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1896">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1896">1896</a></td>
@@ -11206,8 +11206,8 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1899">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1899">1899</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1899">1899</a></td>
+ <td>DRWP</td>
<td>Value-dependent constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11225,15 +11225,15 @@
</tr>
<tr id="1902">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1902">1902</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>What makes a conversion “otherwise ill-formed”?</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
- <tr class="open" id="1903">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1903">1903</a></td>
- <td>open</td>
+ <tr id="1903">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1903">1903</a></td>
+ <td>DR</td>
<td>What declarations are introduced by a non-member <I>using-declaration</I>?</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1904">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1904">1904</a></td>
@@ -11267,7 +11267,7 @@
</tr>
<tr id="1909">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1909">1909</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td>Member class template with the same name as the class</td>
<td class="full" align="center">Yes</td>
</tr>
@@ -11279,7 +11279,7 @@
</tr>
<tr id="1911">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1911">1911</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>constexpr</TT> constructor with non-literal base class</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11308,8 +11308,8 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1916">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1916">1916</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1916">1916</a></td>
+ <td>DRWP</td>
<td>“Same cv-unqualified type”</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11332,8 +11332,8 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1920">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1920">1920</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1920">1920</a></td>
+ <td>DRWP</td>
<td>Qualification mismatch in <I>pseudo-destructor-name</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11344,8 +11344,8 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1922">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1922">1922</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1922">1922</a></td>
+ <td>DRWP</td>
<td>Injected class template names and default arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11362,14 +11362,14 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1925">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1925">1925</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1925">1925</a></td>
+ <td>DRWP</td>
<td>Bit-field prvalues</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1926">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1926">1926</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1926">1926</a></td>
+ <td>DRWP</td>
<td>Potential results of subscript operator</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11379,23 +11379,23 @@
<td>Lifetime of temporaries in <I>init-capture</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1928">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1928">1928</a></td>
- <td>open</td>
+ <tr id="1928">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1928">1928</a></td>
+ <td>NAD</td>
<td>Triviality of deleted special member functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1929">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1929">1929</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1929">1929</a></td>
+ <td>DRWP</td>
<td><TT>template</TT> keyword following namespace <I>nested-name-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1930">
+ <tr id="1930">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1930">1930</a></td>
- <td>review</td>
+ <td>ready</td>
<td><I>init-declarator-list</I> vs <I>member-declarator-list</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1931">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1931">1931</a></td>
@@ -11403,11 +11403,11 @@
<td>Default-constructible and copy-assignable closure types</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1932">
+ <tr id="1932">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1932">1932</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Bit-field results of conditional operators</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1933">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1933">1933</a></td>
@@ -11453,19 +11453,19 @@
</tr>
<tr id="1940">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1940">1940</a></td>
- <td>DR</td>
+ <td>DRWP</td>
<td><TT>static_assert</TT> in anonymous unions</td>
<td class="full" align="center">Yes</td>
</tr>
- <tr class="open" id="1941">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1941">1941</a></td>
- <td>drafting</td>
+ <tr id="1941">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1941">1941</a></td>
+ <td>DR</td>
<td>SFINAE and inherited constructor default arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1942">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1942">1942</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1942">1942</a></td>
+ <td>DRWP</td>
<td>Incorrect reference to <I>trailing-return-type</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11487,11 +11487,11 @@
<td>Friend declarations naming members of class templates in non-templates</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1946">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1946">1946</a></td>
- <td>open</td>
+ <tr id="1946">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1946">1946</a></td>
+ <td>accepted</td>
<td><I>exception-specification</I>s vs pointer dereference</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1947">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1947">1947</a></td>
@@ -11505,11 +11505,11 @@
<td><I>exception-specification</I> of replacement global <TT>new</TT></td>
<td class="full" align="center">Yes</td>
</tr>
- <tr class="open" id="1949">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1949">1949</a></td>
- <td>drafting</td>
+ <tr id="1949">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1949">1949</a></td>
+ <td>DR</td>
<td>“sequenced after” instead of “sequenced before”</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1950">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1950">1950</a></td>
@@ -11518,14 +11518,14 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1951">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1951">1951</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1951">1951</a></td>
+ <td>DRWP</td>
<td>Cv-qualification and literal types</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1952">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1952">1952</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1952">1952</a></td>
+ <td>DRWP</td>
<td>Constant expressions and library undefined behavior</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11541,15 +11541,15 @@
<td><TT>typeid</TT> null dereference check in subexpressions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1955">
+ <tr id="1955">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1955">1955</a></td>
- <td>review</td>
+ <td>ready</td>
<td><TT>#elif</TT> with invalid controlling expression</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1956">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1956">1956</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1956">1956</a></td>
+ <td>DRWP</td>
<td>Reuse of storage of automatic variables</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11560,16 +11560,16 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1958">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1958">1958</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1958">1958</a></td>
+ <td>DRWP</td>
<td><TT>decltype(auto)</TT> with parenthesized initializer</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1959">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1959">1959</a></td>
- <td>drafting</td>
+ <tr id="1959">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1959">1959</a></td>
+ <td>DR</td>
<td>Inadvertently inherited copy constructor</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1960">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1960">1960</a></td>
@@ -11579,19 +11579,19 @@
</tr>
<tr class="open" id="1961">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1961">1961</a></td>
- <td>concurrency</td>
+ <td>review</td>
<td>Potentially-concurrent actions within a signal handler</td>
<td align="center">Not resolved</td>
</tr>
<tr class="open" id="1962">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1962">1962</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Type of <TT>__func__</TT></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1963">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1963">1963</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1963">1963</a></td>
+ <td>DRWP</td>
<td>Implementation-defined identifier characters</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11603,19 +11603,19 @@
</tr>
<tr class="open" id="1965">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1965">1965</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Explicit casts to reference types</td>
<td align="center">Not resolved</td>
</tr>
<tr id="1966">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1966">1966</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1966">1966</a></td>
+ <td>DRWP</td>
<td>Colon following enumeration <I>elaborated-type-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1967">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1967">1967</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1967">1967</a></td>
+ <td>DRWP</td>
<td>Temporary lifetime and move-elision</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11638,8 +11638,8 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1971">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1971">1971</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1971">1971</a></td>
+ <td>DRWP</td>
<td>Unclear disambiguation of destructor and <TT>operator~</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11661,11 +11661,11 @@
<td>Redundant specification of non-type <I>typename-specifier</I></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1975">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1975">1975</a></td>
- <td>drafting</td>
+ <tr id="1975">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1975">1975</a></td>
+ <td>DR</td>
<td>Permissible declarations for <I>exception-specification</I>s</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1976">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1976">1976</a></td>
@@ -11680,14 +11680,14 @@
<td align="center">Not resolved</td>
</tr>
<tr id="1978">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1978">1978</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1978">1978</a></td>
+ <td>DRWP</td>
<td>Redundant description of explicit constructor use</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1979">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1979">1979</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Alias template specialization in template member definition</td>
<td align="center">Not resolved</td>
</tr>
@@ -11697,11 +11697,11 @@
<td>Equivalent but not functionally-equivalent redeclarations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1981">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1981">1981</a></td>
- <td>drafting</td>
+ <tr id="1981">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1981">1981</a></td>
+ <td>DR</td>
<td>Implicit contextual conversions and <TT>explicit</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1982">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1982">1982</a></td>
@@ -11727,11 +11727,11 @@
<td>Unknown bound array member with <I>brace-or-equal-initializer</I></td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr id="1986">
+ <tr class="open" id="1986">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1986">1986</a></td>
- <td>ready</td>
+ <td>drafting</td>
<td>odr-use and delayed initialization</td>
- <td class="none" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr id="1987">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1987">1987</a></td>
@@ -11740,8 +11740,8 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1988">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1988">1988</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1988">1988</a></td>
+ <td>DRWP</td>
<td>Ambiguity between dependent and non-dependent bases in implicit member access</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11751,17 +11751,17 @@
<td>Insufficient restrictions on parameters of postfix operators</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1990">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1990">1990</a></td>
- <td>drafting</td>
+ <tr id="1990">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1990">1990</a></td>
+ <td>DR</td>
<td>Ambiguity due to optional <I>decl-specifier-seq</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1991">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1991">1991</a></td>
- <td>open</td>
+ <tr id="1991">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1991">1991</a></td>
+ <td>DR</td>
<td>Inheriting constructors vs default arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1992">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1992">1992</a></td>
@@ -11781,17 +11781,17 @@
<td>Confusing wording regarding multiple <TT>template<></TT> prefixes</td>
<td class="none" align="center">Duplicate of <a href="#529">529</a></td>
</tr>
- <tr class="open" id="1995">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1995">1995</a></td>
- <td>open</td>
+ <tr id="1995">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1995">1995</a></td>
+ <td>accepted</td>
<td><I>exception-specification</I>s and non-type template parameters</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1996">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1996">1996</a></td>
- <td>open</td>
+ <tr id="1996">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/">1996</a></td>
+ <td></td>
<td>Reference list-initialization ignores conversion functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1997">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1997">1997</a></td>
@@ -11806,22 +11806,22 @@
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1999">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1999">1999</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1999">1999</a></td>
+ <td>DRWP</td>
<td>Representation of source characters as universal-character-names</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2000">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2000">2000</a></td>
- <td>drafting</td>
+ <tr id="2000">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2000">2000</a></td>
+ <td>DR</td>
<td><I>header-name</I> outside <TT>#include</TT> directive</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2001">
+ <tr id="2001">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2001">2001</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td><I>non-directive</I> is underspecified</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2002">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2002">2002</a></td>
@@ -11835,11 +11835,11 @@
<td>Zero-argument macros incorrectly specified</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2004">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2004">2004</a></td>
- <td>drafting</td>
+ <tr id="2004">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2004">2004</a></td>
+ <td>DR</td>
<td>Unions with mutable members in constant expressions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="2005">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2005">2005</a></td>
@@ -11847,11 +11847,11 @@
<td>Incorrect <TT>constexpr</TT> reference initialization requirements</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2006">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2006">2006</a></td>
- <td>drafting</td>
+ <tr id="2006">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2006">2006</a></td>
+ <td>DR</td>
<td>Cv-qualified <TT>void</TT> types</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2007">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2007">2007</a></td>
@@ -11859,11 +11859,11 @@
<td>Argument-dependent lookup for <TT>operator=</TT></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2008">
+ <tr id="2008">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2008">2008</a></td>
- <td>review</td>
+ <td>ready</td>
<td>Default <I>template-argument</I>s underspecified</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2009">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2009">2009</a></td>
@@ -11871,11 +11871,11 @@
<td>Unclear specification of class scope</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2010">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2010">2010</a></td>
- <td>open</td>
+ <tr id="2010">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2010">2010</a></td>
+ <td>accepted</td>
<td><I>exception-specification</I>s and conversion operators</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2011">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2011">2011</a></td>
@@ -11883,11 +11883,11 @@
<td>Unclear effect of reference capture of reference</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2012">
+ <tr id="2012">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2012">2012</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Lifetime of references</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2013">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2013">2013</a></td>
@@ -11901,35 +11901,35 @@
<td>Unneeded deallocation signatures</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2015">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2015">2015</a></td>
- <td>drafting</td>
+ <tr id="2015">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2015">2015</a></td>
+ <td>DR</td>
<td>odr-use of deleted virtual functions</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2016">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2016">2016</a></td>
- <td>drafting</td>
+ <tr id="2016">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2016">2016</a></td>
+ <td>DR</td>
<td>Confusing wording in description of conversion function</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2017">
+ <tr id="2017">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2017">2017</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Flowing off end is not equivalent to no-expression return</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2018">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2018">2018</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Qualification conversion vs reference binding</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2019">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2019">2019</a></td>
- <td>drafting</td>
+ <tr id="2019">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2019">2019</a></td>
+ <td>DR</td>
<td>Member references omitted from description of storage duration</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2020">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2020">2020</a></td>
@@ -11951,33 +11951,33 @@
</tr>
<tr class="open" id="2023">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2023">2023</a></td>
- <td>open</td>
+ <td>drafting</td>
<td>Composite reference result type of conditional operator</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2024">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2024">2024</a></td>
- <td>open</td>
+ <tr id="2024">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2024">2024</a></td>
+ <td>DR</td>
<td>Dependent types and unexpanded parameter packs</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2025">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2025">2025</a></td>
- <td>open</td>
+ <tr id="2025">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2025">2025</a></td>
+ <td>dup</td>
<td>Declaration matching via alias templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2026">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2026">2026</a></td>
- <td>drafting</td>
+ <tr id="2026">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2026">2026</a></td>
+ <td>DR</td>
<td>Zero-initialization and <TT>constexpr</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2027">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2027">2027</a></td>
- <td>drafting</td>
+ <tr id="2027">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2027">2027</a></td>
+ <td>DR</td>
<td>Unclear requirements for multiple <TT>alignas</TT> specifiers</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2028">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2028">2028</a></td>
@@ -11997,36 +11997,942 @@
<td>Access of injected-class-name with template arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2031">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2031">2031</a></td>
- <td>drafting</td>
+ <tr id="2031">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2031">2031</a></td>
+ <td>DR</td>
<td>Missing incompatibility for <TT>&&</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2032">
+ <tr id="2032">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2032">2032</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Default <I>template-argument</I>s of variable templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2033">
+ <tr id="2033">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2033">2033</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Redundant restriction on partial specialization argument</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2034">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2034">2034</a></td>
- <td>open</td>
+ <tr id="2034">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2034">2034</a></td>
+ <td>NAD</td>
<td>Deprecating <TT>uncaught_exception()</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2035">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2035">2035</a></td>
- <td>open</td>
+ <td>review</td>
<td>Multi-section example is confusing</td>
<td align="center">Not resolved</td>
</tr>
+ <tr id="2036">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2036">2036</a></td>
+ <td>NAD</td>
+ <td>Refactoring <I>parameters-and-qualifiers</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2037">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2037">2037</a></td>
+ <td>drafting</td>
+ <td>Alias templates and template declaration matching</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2038">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2038">2038</a></td>
+ <td>tentatively ready</td>
+ <td>Document C++14 incompatibility of new braced deduction rule</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2039">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2039">2039</a></td>
+ <td>tentatively ready</td>
+ <td>Constant conversions to <TT>bool</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2040">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2040">2040</a></td>
+ <td>tentatively ready</td>
+ <td><I>trailing-return-type</I> no longer ambiguous</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2041">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2041">2041</a></td>
+ <td>tentatively ready</td>
+ <td>Namespace for explicit class template specialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2042">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2042">2042</a></td>
+ <td>open</td>
+ <td>Exceptions and deallocation functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2043">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2043">2043</a></td>
+ <td>drafting</td>
+ <td>Generalized template arguments and array-to-pointer decay</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2044">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2044">2044</a></td>
+ <td>tentatively ready</td>
+ <td><TT>decltype(auto)</TT> and <TT>void</TT></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2045">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2045">2045</a></td>
+ <td>drafting</td>
+ <td>“Identical” template parameter lists</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2046">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2046">2046</a></td>
+ <td>concurrency</td>
+ <td>Incomplete thread specifications</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2047">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2047">2047</a></td>
+ <td>ready</td>
+ <td>Coordinating “throws anything” specifications</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2048">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2048">2048</a></td>
+ <td>open</td>
+ <td>C-style casts that cast away constness vs <TT>static_cast</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2049">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2049">2049</a></td>
+ <td>drafting</td>
+ <td>List initializer in non-type template default argument</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2050">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2050">2050</a></td>
+ <td>NAD</td>
+ <td>Consolidate specification of linkage</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2051">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2051">2051</a></td>
+ <td>drafting</td>
+ <td>Simplifying alias rules</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2052">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2052">2052</a></td>
+ <td>DR</td>
+ <td>Template argument deduction vs overloaded operators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2053">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2053">2053</a></td>
+ <td>drafting</td>
+ <td><TT>auto</TT> in non-generic lambdas</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2054">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2054">2054</a></td>
+ <td>open</td>
+ <td>Missing description of class SFINAE</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2055">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2055">2055</a></td>
+ <td>open</td>
+ <td>Explicitly-specified non-deduced parameter packs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2056">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2056">2056</a></td>
+ <td>drafting</td>
+ <td>Member function calls in partially-initialized class objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2057">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2057">2057</a></td>
+ <td>open</td>
+ <td>Template template arguments with default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2058">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2058">2058</a></td>
+ <td>drafting</td>
+ <td>More errors from internal-linkage namespaces</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2059">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2059">2059</a></td>
+ <td>open</td>
+ <td>Linkage and deduced return types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2060">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2060">2060</a></td>
+ <td>NAD</td>
+ <td>Deduced return type for explicit specialization</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2061">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2061">2061</a></td>
+ <td>tentatively ready</td>
+ <td>Inline namespace after simplifications</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2062">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2062">2062</a></td>
+ <td>drafting</td>
+ <td>Class template redeclaration requirements</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2063">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2063">2063</a></td>
+ <td>tentatively ready</td>
+ <td>Type/nontype hiding in class scope</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2064">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2064">2064</a></td>
+ <td>drafting</td>
+ <td>Conflicting specifications for dependent <I>decltype-specifier</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2065">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2065">2065</a></td>
+ <td>drafting</td>
+ <td>Current instantiation of a partial specialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2066">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2066">2066</a></td>
+ <td>tentatively ready</td>
+ <td>Does type-dependent imply value-dependent?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2067">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2067">2067</a></td>
+ <td>open</td>
+ <td>Generated variadic templates requiring empty pack</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2068">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2068">2068</a></td>
+ <td>tentatively ready</td>
+ <td>When can/must a defaulted virtual destructor be defined?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2069">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2069">2069</a></td>
+ <td>tentatively ready</td>
+ <td>Do destructors have names?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2070">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070">2070</a></td>
+ <td>drafting</td>
+ <td><I>using-declaration</I> with dependent <I>nested-name-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2071">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2071">2071</a></td>
+ <td>tentatively ready</td>
+ <td><TT>typedef</TT> with no declarator</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2072">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2072">2072</a></td>
+ <td>drafting</td>
+ <td>Default argument instantiation for member functions of templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2073">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2073">2073</a></td>
+ <td>open</td>
+ <td>Allocating memory for exception objects</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2074">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2074">2074</a></td>
+ <td>drafting</td>
+ <td>Type-dependence of local class of function template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2075">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2075">2075</a></td>
+ <td>DR</td>
+ <td>Passing short initializer lists to array reference parameters</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2076">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2076">2076</a></td>
+ <td>open</td>
+ <td>List-initialization of arguments for constructor parameters</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2077">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2077">2077</a></td>
+ <td>open</td>
+ <td>Overload resolution and invalid rvalue-reference initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2078">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2078">2078</a></td>
+ <td>NAD</td>
+ <td>Name lookup of <I>mem-initilizer-id</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2079">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2079">2079</a></td>
+ <td>tentatively ready</td>
+ <td><TT>[[</TT> appearing in a <I>balanced-token-seq</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2080">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2080">2080</a></td>
+ <td>drafting</td>
+ <td>Example with empty anonymous union member</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2081">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2081">2081</a></td>
+ <td>drafting</td>
+ <td>Deduced return type in redeclaration or specialization of function template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2082">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2082">2082</a></td>
+ <td>ready</td>
+ <td>Referring to parameters in unevaluated operands of default arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2083">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2083">2083</a></td>
+ <td>open</td>
+ <td>Incorrect cases of odr-use</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2084">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2084">2084</a></td>
+ <td>ready</td>
+ <td>NSDMIs and deleted union default constructors</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2085">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2085">2085</a></td>
+ <td>tentatively ready</td>
+ <td>Invalid example of adding special member function via default argument</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2086">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2086">2086</a></td>
+ <td>drafting</td>
+ <td>Reference odr-use vs implicit capture</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2087">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2087">2087</a></td>
+ <td>open</td>
+ <td>Left shift of negative value by zero bits</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2088">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2088">2088</a></td>
+ <td>open</td>
+ <td>Late tiebreakers in partial ordering</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2089">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2089">2089</a></td>
+ <td>drafting</td>
+ <td>Restricting selection of builtin overloaded operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2090">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2090">2090</a></td>
+ <td>drafting</td>
+ <td>Dependency via non-dependent base class</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2091">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2091">2091</a></td>
+ <td>open</td>
+ <td>Deducing reference non-type template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2092">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2092">2092</a></td>
+ <td>open</td>
+ <td>Deduction failure and overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2093">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2093">2093</a></td>
+ <td>ready</td>
+ <td>Qualification conversion for pointer-to-member handler matching</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2094">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2094">2094</a></td>
+ <td>open</td>
+ <td>Trivial copy/move constructor for class with volatile member</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2095">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2095">2095</a></td>
+ <td>tentatively ready</td>
+ <td>Capturing rvalue references to functions by copy</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2096">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2096">2096</a></td>
+ <td>tentatively ready</td>
+ <td>Constraints on literal unions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2097">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2097">2097</a></td>
+ <td>extension</td>
+ <td>Lambdas and <TT>noreturn</TT> attribute</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2098">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2098">2098</a></td>
+ <td>tentatively ready</td>
+ <td>Is <TT>uncaught_exceptions()</TT> per-thread?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2099">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2099">2099</a></td>
+ <td>ready</td>
+ <td>Inferring the bound of an array static data member</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2100">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2100">2100</a></td>
+ <td>open</td>
+ <td>Value-dependent address of static data member of class template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2101">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2101">2101</a></td>
+ <td>DR</td>
+ <td>Incorrect description of type- and value-dependence</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2102">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2102">2102</a></td>
+ <td>drafting</td>
+ <td>Constructor checking in <I>new-expression</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2103">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2103">2103</a></td>
+ <td>drafting</td>
+ <td>Lvalue-to-rvalue conversion is irrelevant in odr-use of a reference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2104">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2104">2104</a></td>
+ <td>drafting</td>
+ <td>Internal-linkage <TT>constexpr</TT> references and ODR requirements</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2105">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2105">2105</a></td>
+ <td>open</td>
+ <td>When do the arguments for a parameter pack end?</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2106">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2106">2106</a></td>
+ <td>tentatively ready</td>
+ <td>Unclear restrictions on use of function-type template arguments</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2107">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2107">2107</a></td>
+ <td>tentatively ready</td>
+ <td>Lifetime of temporaries for default arguments in array copying</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2108">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2108">2108</a></td>
+ <td>open</td>
+ <td>Conversions to non-class prvalues in reference initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2109">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2109">2109</a></td>
+ <td>tentatively ready</td>
+ <td>Value dependence underspecified</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2110">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2110">2110</a></td>
+ <td>drafting</td>
+ <td>Overload resolution for base class conversion and reference/non-reference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2111">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2111">2111</a></td>
+ <td>open</td>
+ <td>Array temporaries in reference binding</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2112">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2112">2112</a></td>
+ <td>drafting</td>
+ <td><TT>new auto{x}</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2113">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2113">2113</a></td>
+ <td>tentatively ready</td>
+ <td>Incompete specification of types for declarators</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2114">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2114">2114</a></td>
+ <td>review</td>
+ <td>Missing description of incompatibility from aggregate NSDMIs</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2115">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2115">2115</a></td>
+ <td>open</td>
+ <td>Order of implicit destruction vs release of automatic storage</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2116">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2116">2116</a></td>
+ <td>drafting</td>
+ <td>Direct or copy initialization for omitted aggregate initializers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2117">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2117">2117</a></td>
+ <td>drafting</td>
+ <td>Explicit specializations and <TT>constexpr</TT> function templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2118">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118">2118</a></td>
+ <td>open</td>
+ <td>Stateful metaprogramming via friend injection</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2119">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2119">2119</a></td>
+ <td>NAD</td>
+ <td>Disambiguation of multi-level covariant return type</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2120">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2120">2120</a></td>
+ <td>DR</td>
+ <td>Array as first non-static data member in standard-layout class</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2121">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2121">2121</a></td>
+ <td>drafting</td>
+ <td>More flexible lambda syntax</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2122">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2122">2122</a></td>
+ <td>drafting</td>
+ <td>Glvalues of <TT>void</TT> type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2123">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2123">2123</a></td>
+ <td>open</td>
+ <td>Omitted constant initialization of local static variables</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2124">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2124">2124</a></td>
+ <td>ready</td>
+ <td>Signature of constructor template</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2125">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2125">2125</a></td>
+ <td>extension</td>
+ <td>Copy elision and comma operator</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2126">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2126">2126</a></td>
+ <td>drafting</td>
+ <td>Lifetime-extended temporaries in constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2127">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2127">2127</a></td>
+ <td>drafting</td>
+ <td>Partial specialization and nullptr</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2128">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2128">2128</a></td>
+ <td>drafting</td>
+ <td>Imprecise rule for reference member initializer</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2129">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2129">2129</a></td>
+ <td>drafting</td>
+ <td>Non-object prvalues and constant expressions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2130">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2130">2130</a></td>
+ <td>ready</td>
+ <td>Over-aligned types in <I>new-expression</I>s</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2131">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2131">2131</a></td>
+ <td>drafting</td>
+ <td>Ambiguity with <I>opaque-enum-declaration</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2132">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2132">2132</a></td>
+ <td>extension</td>
+ <td>Deprecated default generated copy constructors</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2133">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2133">2133</a></td>
+ <td>open</td>
+ <td>Converting <TT>std::nullptr_t</TT> to <TT>bool</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2134">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2134">2134</a></td>
+ <td>NAD</td>
+ <td>Objectless references to non-static member functions</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2135">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2135">2135</a></td>
+ <td>NAD</td>
+ <td><I>mem-initializer</I>s for virtual bases of abstract classes</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr id="2136">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2136">2136</a></td>
+ <td>NAD</td>
+ <td>Argument-dependent lookup and initializer lists</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2137">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2137">2137</a></td>
+ <td>drafting</td>
+ <td>List-initialization from object of same type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2138">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2138">2138</a></td>
+ <td>open</td>
+ <td>Explicit member specialization vs implicit instantiation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2139">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2139">2139</a></td>
+ <td>NAD</td>
+ <td>Floating-point requirements for integer representation</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2140">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2140">2140</a></td>
+ <td>drafting</td>
+ <td>Lvalue-to-rvalue conversion of <TT>std::nullptr_t</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2141">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2141">2141</a></td>
+ <td>drafting</td>
+ <td>Ambiguity in <I>new-expression</I> with <I>elaborated-type-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2142">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2142">2142</a></td>
+ <td>NAD</td>
+ <td>Missing definition of associated classes and namespaces</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2143">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2143">2143</a></td>
+ <td>drafting</td>
+ <td>Value-dependency via injected-class-name</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2144">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2144">2144</a></td>
+ <td>drafting</td>
+ <td>Function/variable declaration ambiguity</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2145">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2145">2145</a></td>
+ <td>drafting</td>
+ <td>Parenthesized declarator in function definition</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2146">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2146">2146</a></td>
+ <td>drafting</td>
+ <td>Scalar object vs memory location in definition of “unsequenced”</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2147">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2147">2147</a></td>
+ <td>tentatively ready</td>
+ <td>Initializer-list arguments and pack deduction</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2148">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2148">2148</a></td>
+ <td>drafting</td>
+ <td>Thread storage duration and order of initialization</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2149">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2149">2149</a></td>
+ <td>drafting</td>
+ <td>Brace elision and array length deduction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2150">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2150">2150</a></td>
+ <td>review</td>
+ <td>Initializer list array lifetime</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2151">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2151">2151</a></td>
+ <td>drafting</td>
+ <td>Exception object is not created</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2152">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2152">2152</a></td>
+ <td>NAD</td>
+ <td>Can an alternative token be used as a <I>ud-suffix</I>?</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2153">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2153">2153</a></td>
+ <td>drafting</td>
+ <td><I>pure-specifier</I> in friend declaration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2154">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2154">2154</a></td>
+ <td>drafting</td>
+ <td>Ambiguity of <I>pure-specifier</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2155">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2155">2155</a></td>
+ <td>review</td>
+ <td>Defining classes and enumerations via <I>using-declaration</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2156">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2156">2156</a></td>
+ <td>drafting</td>
+ <td>Definition of enumeration declared by <I>using-declaration</I></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2157">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2157">2157</a></td>
+ <td>ready</td>
+ <td>Further disambiguation of enumeration <I>elaborated-type-specifier</I></td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2158">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2158">2158</a></td>
+ <td>drafting</td>
+ <td>Polymorphic behavior during destruction</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2159">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2159">2159</a></td>
+ <td>concurrency</td>
+ <td>Lambda capture and local <TT>thread_local</TT> variables</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2160">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2160">2160</a></td>
+ <td>open</td>
+ <td>Issues with partial ordering</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr id="2161">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2161">2161</a></td>
+ <td>NAD</td>
+ <td>Explicit instantiation declaration and “preceding initialization”</td>
+ <td class="none" align="center">Unknown</td>
+ </tr>
+ <tr class="open" id="2162">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2162">2162</a></td>
+ <td>drafting</td>
+ <td>Capturing <TT>this</TT> by reference</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2163">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2163">2163</a></td>
+ <td>drafting</td>
+ <td>Labels in <TT>constexpr</TT> functions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2164">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2164">2164</a></td>
+ <td>drafting</td>
+ <td>Name hiding and <I>using-directive</I>s</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2165">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2165">2165</a></td>
+ <td>drafting</td>
+ <td>Namespaces, declarative regions, and translation units</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2166">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2166">2166</a></td>
+ <td>drafting</td>
+ <td>Unclear meaning of “undefined <TT>constexpr</TT> function”</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2167">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2167">2167</a></td>
+ <td>drafting</td>
+ <td>Non-member references with lifetimes within the current evaluation</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2168">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2168">2168</a></td>
+ <td>open</td>
+ <td>Narrowing conversions and +/- infinity</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2169">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2169">2169</a></td>
+ <td>drafting</td>
+ <td>Narrowing conversions and overload resolution</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2170">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2170">2170</a></td>
+ <td>drafting</td>
+ <td>Unclear definition of odr-use for arrays</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2171">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2171">2171</a></td>
+ <td>drafting</td>
+ <td>Triviality of copy constructor with less-qualified parameter</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2172">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2172">2172</a></td>
+ <td>drafting</td>
+ <td>Multiple exceptions with one exception object</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2173">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2173">2173</a></td>
+ <td>open</td>
+ <td>Partial specialization with non-deduced contexts</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2174">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2174">2174</a></td>
+ <td>review</td>
+ <td>Unclear rules for friend definitions in templates</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2175">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2175">2175</a></td>
+ <td>drafting</td>
+ <td>Ambiguity with attribute in conversion operator declaration</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2176">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2176">2176</a></td>
+ <td>drafting</td>
+ <td>Destroying the returned object when a destructor throws</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2177">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2177">2177</a></td>
+ <td>drafting</td>
+ <td>Placement <TT>operator delete</TT> and parameter copies</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2178">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2178">2178</a></td>
+ <td>open</td>
+ <td>Substitution of dependent template arguments in default template arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2179">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2179">2179</a></td>
+ <td>open</td>
+ <td>Required diagnostic for partial specialization after first use</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2180">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2180">2180</a></td>
+ <td>drafting</td>
+ <td>Virtual bases in destructors and defaulted assignment operators</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2181">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2181">2181</a></td>
+ <td>open</td>
+ <td>Normative requirements in an informative Annex</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2182">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2182">2182</a></td>
+ <td>open</td>
+ <td>Pointer arithmetic in array-like containers</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2183">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2183">2183</a></td>
+ <td>open</td>
+ <td>Problems in description of potential exceptions</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2184">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2184">2184</a></td>
+ <td>open</td>
+ <td>Missing C compatibility entry for decrement of <TT>bool</TT></td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2185">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2185">2185</a></td>
+ <td>open</td>
+ <td>Cv-qualified numeric types</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2186">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2186">2186</a></td>
+ <td>open</td>
+ <td>Unclear point that “preceding initialization” must precede</td>
+ <td align="center">Not resolved</td>
+ </tr>
</table>
</div>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 667f0c2..fb458ca 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -564,44 +564,44 @@
<tr>
<td>New <tt>auto</tt> rules for direct-list-initialization
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html">N3922</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">Clang 3.8 <a href="#n3922">(7)</a></td>
</tr>
<!-- Urbana papers -->
<tr>
<td>Fold expressions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4295.html">N4295</a></td>
- <td class="svn" align="center">Clang 3.6</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr>
<td><tt>u8</tt> character literals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4267.html">N4267</a></td>
- <td class="svn" align="center">Clang 3.6</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr>
<td>Nested namespace definition</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.html">N4230</a></td>
- <td class="svn" align="center">Clang 3.6</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr>
<td>Attributes for namespaces and enumerators</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4266.html">N4266</a></td>
- <td class="svn" align="center">Clang 3.6</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<tr>
<td>Allow constant evaluation for all non-type template arguments</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4268.html">N4268</a></td>
- <td class="svn" align="center">Clang 3.6</td>
+ <td class="full" align="center">Clang 3.6</td>
</tr>
<!-- Kona papers -->
<tr>
<td>Remove deprecated <tt>register</tt> storage class</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0001r1.html">P0001R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">Clang 3.8</td>
</tr>
<tr>
<td>Remove deprecated <tt>bool</tt> increment</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0002r1.html">P0002R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">Clang 3.8</td>
</tr>
<tr>
<td>Make exception specifications part of the type system</td>
@@ -609,12 +609,20 @@
<td class="none" align="center">No</td>
</tr>
<tr>
- <td><tt>__has_include</tt></td>
+ <td><tt>__has_include</tt> in preprocessor conditionals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0061.html">P0061R1</a></td>
<td class="full" align="center">Yes</td>
</tr>
</table>
+<p>
+<span id="n3922">(7): This is a backwards-incompatible change that is applied to
+all language versions that allow type deduction from <tt>auto</tt>
+(per the request of the C++ committee).
+In Clang 3.7, a warning is emitted for all cases that would change meaning.
+</span>
+</p>
+
<h2 id="ts">Technical specifications and standing documents</h2>
<p>ISO C++ also publishes a number of documents describing additional language
@@ -636,7 +644,7 @@
</td>
</tr>
<tr>
- <td class="svn" align="center">
+ <td class="full" align="center">
Clang 3.6 (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4200">N4200</a>)</a>
</td>
</tr>
@@ -671,7 +679,7 @@
</tr>
<tr>
<td>[TS] Transactional Memory</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4302.pdf">N4302</a></td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4514.pdf">N4514</a></td>
<td class="none" align="center">No</td>
</tr>
</table>
diff --git a/www/get_started.html b/www/get_started.html
index 7716e8d..541c45a 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -109,7 +109,7 @@
the best version of libstdc++ headers available and use them - it will
look both for system installations of libstdc++ as well as installations
adjacent to Clang itself. If your configuration fits neither of these
- scenarios, you can use the <tt>--with-gcc-toolchain</tt> configure option
+ scenarios, you can use the <tt>-DGCC_INSTALL_PREFIX</tt> cmake option
to tell Clang where the gcc containing the desired libstdc++ is installed.
</li>
<li>Try it out (assuming you add llvm/Debug+Asserts/bin to your path):
diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status
index bb3007f..fe48428 100755
--- a/www/make_cxx_dr_status
+++ b/www/make_cxx_dr_status
@@ -102,10 +102,10 @@
if status == 'unknown':
avail = 'Unknown'
avail_style = ' class="none"'
- elif status == '3.8':
+ elif status == '3.9':
avail = 'SVN'
avail_style = ' class="svn"'
- elif status in ('3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7'):
+ elif status.startswith('3.'):
avail = 'Clang %s' % status
avail_style = ' class="full"'
elif status == 'yes':