From 570918821a8492048e6ab54955c9864bd6c3e952 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: May 02 2017 18:30:45 +0000 Subject: Vendor import of clang trunk r301939: https://llvm.org/svn/llvm-project/cfe/trunk@301939 --- diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst index d69afba..1c42b42 100644 --- a/docs/SanitizerCoverage.rst +++ b/docs/SanitizerCoverage.rst @@ -8,202 +8,12 @@ SanitizerCoverage Introduction ============ -Sanitizer tools have a very simple code coverage tool built in. It allows to -get function-level, basic-block-level, and edge-level coverage at a very low -cost. - -How to build and run -==================== - -SanitizerCoverage can be used with :doc:`AddressSanitizer`, -:doc:`LeakSanitizer`, :doc:`MemorySanitizer`, -UndefinedBehaviorSanitizer, or without any sanitizer. Pass one of the -following compile-time flags: - -* ``-fsanitize-coverage=func`` for function-level coverage (very fast). -* ``-fsanitize-coverage=bb`` for basic-block-level coverage (may add up to 30% - **extra** slowdown). -* ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown). - -At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``, -``LSAN_OPTIONS``, ``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as -appropriate. For the standalone coverage mode, use ``UBSAN_OPTIONS``. - -Example: - -.. code-block:: console - - % cat -n cov.cc - 1 #include - 2 __attribute__((noinline)) - 3 void foo() { printf("foo\n"); } - 4 - 5 int main(int argc, char **argv) { - 6 if (argc == 2) - 7 foo(); - 8 printf("main\n"); - 9 } - % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=func - % ASAN_OPTIONS=coverage=1 ./a.out; ls -l *sancov - main - -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov - % ASAN_OPTIONS=coverage=1 ./a.out foo ; ls -l *sancov - foo - main - -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov - -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov - -Every time you run an executable instrumented with SanitizerCoverage -one ``*.sancov`` file is created during the process shutdown. -If the executable is dynamically linked against instrumented DSOs, -one ``*.sancov`` file will be also created for every DSO. - -Postprocessing -============== - -The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic, -one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the -magic defines the size of the following offsets. The rest of the data is the -offsets in the corresponding binary/DSO that were executed during the run. - -A simple script -``$LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py`` is -provided to dump these offsets. - -.. code-block:: console - - % sancov.py print a.out.22679.sancov a.out.22673.sancov - sancov.py: read 2 PCs from a.out.22679.sancov - sancov.py: read 1 PCs from a.out.22673.sancov - sancov.py: 2 files merged; 2 PCs total - 0x465250 - 0x4652a0 - -You can then filter the output of ``sancov.py`` through ``addr2line --exe -ObjectFile`` or ``llvm-symbolizer --obj ObjectFile`` to get file names and line -numbers: - -.. code-block:: console - - % sancov.py print a.out.22679.sancov a.out.22673.sancov 2> /dev/null | llvm-symbolizer --obj a.out - cov.cc:3 - cov.cc:5 - -Sancov Tool -=========== - -A new experimental ``sancov`` tool is developed to process coverage files. -The tool is part of LLVM project and is currently supported only on Linux. -It can handle symbolization tasks autonomously without any extra support -from the environment. You need to pass .sancov files (named -``..sancov`` and paths to all corresponding binary elf files. -Sancov matches these files using module names and binaries file names. - -.. code-block:: console - - USAGE: sancov [options] (|<.sancov file>)... - - Action (required) - -print - Print coverage addresses - -covered-functions - Print all covered functions. - -not-covered-functions - Print all not covered functions. - -symbolize - Symbolizes the report. - - Options - -blacklist= - Blacklist file (sanitizer blacklist format). - -demangle - Print demangled function name. - -strip_path_prefix= - Strip this prefix from file paths in reports - - -Coverage Reports (Experimental) -================================ - -``.sancov`` files do not contain enough information to generate a source-level -coverage report. The missing information is contained -in debug info of the binary. Thus the ``.sancov`` has to be symbolized -to produce a ``.symcov`` file first: - -.. code-block:: console - - sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov - -The ``.symcov`` file can be browsed overlayed over the source code by -running ``tools/sancov/coverage-report-server.py`` script that will start -an HTTP server. - - -How good is the coverage? -========================= - -It is possible to find out which PCs are not covered, by subtracting the covered -set from the set of all instrumented PCs. The latter can be obtained by listing -all callsites of ``__sanitizer_cov()`` in the binary. On Linux, ``sancov.py`` -can do this for you. Just supply the path to binary and a list of covered PCs: - -.. code-block:: console - - % sancov.py print a.out.12345.sancov > covered.txt - sancov.py: read 2 64-bit PCs from a.out.12345.sancov - sancov.py: 1 file merged; 2 PCs total - % sancov.py missing a.out < covered.txt - sancov.py: found 3 instrumented PCs in a.out - sancov.py: read 2 PCs from stdin - sancov.py: 1 PCs missing from coverage - 0x4cc61c - -Edge coverage -============= - -Consider this code: - -.. code-block:: c++ - - void foo(int *a) { - if (a) - *a = 0; - } - -It contains 3 basic blocks, let's name them A, B, C: - -.. code-block:: none - - A - |\ - | \ - | B - | / - |/ - C - -If blocks A, B, and C are all covered we know for certain that the edges A=>B -and B=>C were executed, but we still don't know if the edge A=>C was executed. -Such edges of control flow graph are called -`critical `_. The -edge-level coverage (``-fsanitize-coverage=edge``) simply splits all critical -edges by introducing new dummy blocks and then instruments those blocks: - -.. code-block:: none - - A - |\ - | \ - D B - | / - |/ - C - -Tracing PCs -=========== - -*Experimental* feature similar to tracing basic blocks, but with a different API. -With ``-fsanitize-coverage=trace-pc`` the compiler will insert -``__sanitizer_cov_trace_pc()`` on every edge. -With an additional ``...=trace-pc,indirect-calls`` flag -``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call. -These callbacks are not implemented in the Sanitizer run-time and should be defined -by the user. So, these flags do not require the other sanitizer to be used. -This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller) -and can be used with `AFL `__. +LLVM has a simple code coverage instrumentation built in (SanitizerCoverage). +It inserts calls to user-defined functions on function-, basic-block-, and edge- levels. +Default implementations of those callbacks are provided and implement +simple coverage reporting and visualization, +however if you need *just* coverage visualization you may want to use +:doc:`SourceBasedCodeCoverage ` instead. Tracing PCs with guards ======================= @@ -217,7 +27,7 @@ on every edge: Every edge will have its own `guard_variable` (uint32_t). -The compler will also insert a module constructor that will call +The compler will also insert calls to a module constructor: .. code-block:: c++ @@ -226,7 +36,7 @@ The compler will also insert a module constructor that will call // more than once with the same values of start/stop. __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop); -With `trace-pc-guards,indirect-calls` +With an additional ``...=trace-pc,indirect-calls`` flag ``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call. The functions `__sanitizer_cov_trace_pc_*` should be defined by the user. @@ -309,6 +119,75 @@ Example: guard: 0x71bcdc 4 PC 0x4ecdc7 in main trace-pc-guard-example.cc:4:17 guard: 0x71bcd0 1 PC 0x4ecd20 in foo() trace-pc-guard-example.cc:2:14 +Tracing PCs +=========== + +With ``-fsanitize-coverage=trace-pc`` the compiler will insert +``__sanitizer_cov_trace_pc()`` on every edge. +With an additional ``...=trace-pc,indirect-calls`` flag +``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call. +These callbacks are not implemented in the Sanitizer run-time and should be defined +by the user. +This mechanism is used for fuzzing the Linux kernel +(https://github.com/google/syzkaller). + + +Instrumentation points +====================== +Sanitizer Coverage offers different levels of instrumentation. + +* ``edge`` (default): edges are instrumented (see below). +* ``bb``: basic blocks are instrumented. +* ``func``: only the entry block of every function will be instrumented. + +Use these flags together with ``trace-pc-guard`` or ``trace-pc``, +like this: ``-fsanitize-coverage=func,trace-pc-guard``. + +When ``edge`` or ``bb`` is used, some of the edges/blocks may still be left +uninstrumented if such instrumentation is considered redundant. +**TODO**: add a user-visible option to disable the optimization. + + +Edge coverage +------------- + +Consider this code: + +.. code-block:: c++ + + void foo(int *a) { + if (a) + *a = 0; + } + +It contains 3 basic blocks, let's name them A, B, C: + +.. code-block:: none + + A + |\ + | \ + | B + | / + |/ + C + +If blocks A, B, and C are all covered we know for certain that the edges A=>B +and B=>C were executed, but we still don't know if the edge A=>C was executed. +Such edges of control flow graph are called +`critical `_. The +edge-level coverage simply splits all critical +edges by introducing new dummy blocks and then instruments those blocks: + +.. code-block:: none + + A + |\ + | \ + D B + | / + |/ + C Tracing data flow ================= @@ -349,50 +228,107 @@ the `LLVM GEP instructions `_ 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 -================ +Default implementation +====================== -By default, .sancov files are created in the current working directory. -This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``: +The sanitizer run-time (AddressSanitizer, MemorySanitizer, etc) provide a +default implementations of some of the coverage callbacks. +You may use this implementation to dump the coverage on disk at the process +exit. + +Example: .. code-block:: console - % ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo - % ls -l /tmp/cov/*sancov - -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov - -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov + % cat -n cov.cc + 1 #include + 2 __attribute__((noinline)) + 3 void foo() { printf("foo\n"); } + 4 + 5 int main(int argc, char **argv) { + 6 if (argc == 2) + 7 foo(); + 8 printf("main\n"); + 9 } + % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=trace-pc-guard + % ASAN_OPTIONS=coverage=1 ./a.out; wc -c *.sancov + main + SanitizerCoverage: ./a.out.7312.sancov 2 PCs written + 24 a.out.7312.sancov + % ASAN_OPTIONS=coverage=1 ./a.out foo ; wc -c *.sancov + foo + main + SanitizerCoverage: ./a.out.7316.sancov 3 PCs written + 24 a.out.7312.sancov + 32 a.out.7316.sancov -Sudden death -============ +Every time you run an executable instrumented with SanitizerCoverage +one ``*.sancov`` file is created during the process shutdown. +If the executable is dynamically linked against instrumented DSOs, +one ``*.sancov`` file will be also created for every DSO. -Normally, coverage data is collected in memory and saved to disk when the -program exits (with an ``atexit()`` handler), when a SIGSEGV is caught, or when -``__sanitizer_cov_dump()`` is called. +Sancov data format +------------------ -If the program ends with a signal that ASan does not handle (or can not handle -at all, like SIGKILL), coverage data will be lost. This is a big problem on -Android, where SIGKILL is a normal way of evicting applications from memory. +The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic, +one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the +magic defines the size of the following offsets. The rest of the data is the +offsets in the corresponding binary/DSO that were executed during the run. + +Sancov Tool +----------- -With ``ASAN_OPTIONS=coverage=1:coverage_direct=1`` coverage data is written to a -memory-mapped file as soon as it collected. +An simple ``sancov`` tool is provided to process coverage files. +The tool is part of LLVM project and is currently supported only on Linux. +It can handle symbolization tasks autonomously without any extra support +from the environment. You need to pass .sancov files (named +``..sancov`` and paths to all corresponding binary elf files. +Sancov matches these files using module names and binaries file names. .. code-block:: console - % ASAN_OPTIONS="coverage=1:coverage_direct=1" ./a.out - main - % ls - 7036.sancov.map 7036.sancov.raw a.out - % sancov.py rawunpack 7036.sancov.raw - sancov.py: reading map 7036.sancov.map - sancov.py: unpacking 7036.sancov.raw - writing 1 PCs to a.out.7036.sancov - % sancov.py print a.out.7036.sancov - sancov.py: read 1 PCs from a.out.7036.sancov - sancov.py: 1 files merged; 1 PCs total - 0x4b2bae - -Note that on 64-bit platforms, this method writes 2x more data than the default, -because it stores full PC values instead of 32-bit offsets. + USAGE: sancov [options] (|<.sancov file>)... + + Action (required) + -print - Print coverage addresses + -covered-functions - Print all covered functions. + -not-covered-functions - Print all not covered functions. + -symbolize - Symbolizes the report. + + Options + -blacklist= - Blacklist file (sanitizer blacklist format). + -demangle - Print demangled function name. + -strip_path_prefix= - Strip this prefix from file paths in reports + + +Coverage Reports +---------------- +**Experimental** + +``.sancov`` files do not contain enough information to generate a source-level +coverage report. The missing information is contained +in debug info of the binary. Thus the ``.sancov`` has to be symbolized +to produce a ``.symcov`` file first: + +.. code-block:: console + + sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov + +The ``.symcov`` file can be browsed overlayed over the source code by +running ``tools/sancov/coverage-report-server.py`` script that will start +an HTTP server. + +Output directory +---------------- + +By default, .sancov files are created in the current working directory. +This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``: + +.. code-block:: console + + % ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo + % ls -l /tmp/cov/*sancov + -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov + -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 9acc9b7..c50ac1b 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 37 +#define CINDEX_VERSION_MINOR 38 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -81,6 +81,12 @@ extern "C" { typedef void *CXIndex; /** + * \brief An opaque type representing target information for a given translation + * unit. + */ +typedef struct CXTargetInfoImpl *CXTargetInfo; + +/** * \brief A single translation unit, which resides in an index. */ typedef struct CXTranslationUnitImpl *CXTranslationUnit; @@ -1553,6 +1559,36 @@ CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage); /** + * \brief Get target information for this translation unit. + * + * The CXTargetInfo object cannot outlive the CXTranslationUnit object. + */ +CINDEX_LINKAGE CXTargetInfo +clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit); + +/** + * \brief Destroy the CXTargetInfo object. + */ +CINDEX_LINKAGE void +clang_TargetInfo_dispose(CXTargetInfo Info); + +/** + * \brief Get the normalized target triple as a string. + * + * Returns the empty string in case of any error. + */ +CINDEX_LINKAGE CXString +clang_TargetInfo_getTriple(CXTargetInfo Info); + +/** + * \brief Get the pointer width of the target in bits. + * + * Returns -1 in case of error. + */ +CINDEX_LINKAGE int +clang_TargetInfo_getPointerWidth(CXTargetInfo Info); + +/** * @} */ @@ -3975,8 +4011,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); /** - * \brief Given a cursor pointing to an Objective-C message, returns the CXType - * of the receiver. + * \brief Given a cursor pointing to an Objective-C message or property + * reference, or C++ method call, returns the CXType of the receiver. */ CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C); diff --git a/include/clang/AST/ASTStructuralEquivalence.h b/include/clang/AST/ASTStructuralEquivalence.h new file mode 100644 index 0000000..770bb57 --- /dev/null +++ b/include/clang/AST/ASTStructuralEquivalence.h @@ -0,0 +1,101 @@ +//===--- ASTStructuralEquivalence.h - ---------------------------*- 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 StructuralEquivalenceContext class which checks for +// structural equivalence between types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H +#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include + +namespace clang { + +class ASTContext; +class Decl; +class DiagnosticBuilder; +class QualType; +class RecordDecl; +class SourceLocation; + +struct StructuralEquivalenceContext { + /// AST contexts for which we are checking structural equivalence. + ASTContext &FromCtx, &ToCtx; + + /// The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap TentativeEquivalences; + + /// Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque DeclsToCheck; + + /// Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet> &NonEquivalentDecls; + + /// Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + /// Whether warn or error on tag type mismatches. + bool ErrorOnTagTypeMismatch; + + /// Whether to complain about failures. + bool Complain; + + /// \c true if the last diagnostic came from ToCtx. + bool LastDiagFromC2; + + StructuralEquivalenceContext( + ASTContext &FromCtx, ASTContext &ToCtx, + llvm::DenseSet> &NonEquivalentDecls, + bool StrictTypeSpelling = false, bool Complain = true) + : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling), Complain(Complain), + LastDiagFromC2(false) {} + + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); + + /// Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + /// Find the index of the given anonymous struct/union within its + /// context. + /// + /// \returns Returns the index of this anonymous struct/union in its context, + /// including the next assigned index (if none of them match). Returns an + /// empty option if the context is not a record, i.e.. if the anonymous + /// struct/union is at namespace or block scope. + /// + /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It + /// probably makes more sense in some other common place then here. + static llvm::Optional + findUntaggedStructOrUnionIndex(RecordDecl *Anon); + +private: + /// Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); +}; +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index c88cb6a..15ac11a 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -616,6 +616,14 @@ public: getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple()) const; + /// \brief Retrieve the version of the target platform in which this + /// declaration was introduced. + /// + /// \returns An empty version tuple if this declaration has no 'introduced' + /// availability attributes, or the version tuple that's specified in the + /// attribute otherwise. + VersionTuple getVersionIntroduced() const; + /// \brief Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index bd30aad..b1c2503 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1396,7 +1396,7 @@ protected: /// Extra information which affects how the function is called, like /// regparm and the calling convention. - unsigned ExtInfo : 10; + unsigned ExtInfo : 11; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. @@ -2941,19 +2941,23 @@ class FunctionType : public Type { // * AST read and write // * Codegen class ExtInfo { - // Feel free to rearrange or add bits, but if you go over 10, + // Feel free to rearrange or add bits, but if you go over 11, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|produces|regparm| - // |0 .. 4| 5 | 6 | 7 .. 9| + // | CC |noreturn|produces|nocallersavedregs|regparm| + // |0 .. 4| 5 | 6 | 7 |8 .. 10| // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; - enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), - RegParmOffset = 7 }; // Assumed to be the last field + enum { NoCallerSavedRegsMask = 0x80 }; + enum { + RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | + NoCallerSavedRegsMask), + RegParmOffset = 8 + }; // Assumed to be the last field uint16_t Bits; @@ -2964,13 +2968,13 @@ class FunctionType : public Type { public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, - bool producesResult) { - assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); - Bits = ((unsigned) cc) | - (noReturn ? NoReturnMask : 0) | - (producesResult ? ProducesResultMask : 0) | - (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult, bool noCallerSavedRegs) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); } // Constructor with all defaults. Use when for example creating a @@ -2983,6 +2987,7 @@ class FunctionType : public Type { bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = Bits >> RegParmOffset; @@ -3016,6 +3021,13 @@ class FunctionType : public Type { return ExtInfo(Bits & ~ProducesResultMask); } + ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { + if (noCallerSavedRegs) + return ExtInfo(Bits | NoCallerSavedRegsMask); + else + return ExtInfo(Bits & ~NoCallerSavedRegsMask); + } + ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 44893fb..04a948a 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -1931,6 +1931,12 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr { let Documentation = [AnyX86InterruptDocs]; } +def AnyX86NoCallerSavedRegisters : InheritableAttr, + TargetSpecificAttr { + let Spellings = [GCC<"no_caller_saved_registers">]; + let Documentation = [AnyX86NoCallerSavedRegistersDocs]; +} + def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr { let Spellings = [GNU<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 71cfe36..be2a915 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -2657,6 +2657,40 @@ hardware design, touch the red zone. }]; } +def AnyX86NoCallerSavedRegistersDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. + +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. + +For example: + + .. code-block:: c + + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { + ... + } + + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + }]; +} + def SwiftCallDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 652d062..a07dbf6 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -154,12 +154,14 @@ def note_constexpr_baa_insufficient_alignment : Note< def note_constexpr_baa_value_insufficient_alignment : Note< "value of the aligned pointer (%0) is not a multiple of the asserted %1 " "%plural{1:byte|:bytes}1">; +def note_constexpr_array_unknown_bound_arithmetic : Note< + "cannot perform pointer arithmetic on pointer to array without constant bound">; def warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, InGroup>; -// This is a temporary diagnostic, and shall be removed once our +// This is a temporary diagnostic, and shall be removed once our // implementation is complete, and like the preceding constexpr notes belongs // in Sema. def note_unimplemented_constexpr_lambda_feature_ast : Note< diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 3980805..3833f0f 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -233,7 +233,9 @@ def note_drv_t_option_is_global : Note< "The last /TC or /TP option takes precedence over earlier instances">; def note_drv_address_sanitizer_debug_runtime : Note< "AddressSanitizer doesn't support linking with debug runtime libraries yet">; -def note_drv_use_standard : Note<"use '%0' for '%1' standard">; +def note_drv_use_standard : Note<"use '%0'" + "%select{| or '%3'|, '%3', or '%4'|, '%3', '%4', or '%5'}2 " + "for '%1' standard">; def err_analyzer_config_no_value : Error< "analyzer-config option '%0' has a key but no value">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 4cde1c8..05e03fa 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -890,6 +890,7 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; def BackendOptimizationFailure : DiagGroup<"pass-failed">; // Instrumentation based profiling warnings. +def ProfileInstrMissing : DiagGroup<"profile-instr-missing">; def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index cf33d5f..cd284e9 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -475,6 +475,8 @@ def warn_pragma_pop_macro_no_push : Warning< def warn_pragma_message : Warning<"%0">, InGroup, DefaultWarnNoWerror; def err_pragma_message : Error<"%0">; +def err_pragma_module_import_expected_module_name : Error< + "expected %select{identifier in|'.' or end of directive after}0 module name">; def warn_pragma_ignored : Warning<"unknown pragma ignored">, InGroup, DefaultIgnore; def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, @@ -503,7 +505,7 @@ def warn_pragma_diagnostic_invalid_token : InGroup; def warn_pragma_diagnostic_unknown_warning : ExtWarn<"unknown warning group '%0', ignored">, - InGroup; + InGroup; // - #pragma __debug def warn_pragma_debug_unexpected_command : Warning< "unexpected debug command '%0'">, InGroup; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b5fed1f..d62ab09 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1180,6 +1180,10 @@ def err_objc_kindof_nonobject : Error< def err_objc_kindof_wrong_position : Error< "'__kindof' type specifier must precede the declarator">; +def err_objc_method_unsupported_param_ret_type : Error< + "%0 %select{parameter|return}1 type is unsupported; " + "support for vector types for this target is introduced in %2">; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; @@ -2819,6 +2823,9 @@ def err_regparm_mismatch : Error<"function declared with regparm(%0) " def err_returns_retained_mismatch : Error< "function declared with the ns_returns_retained attribute " "was previously declared without the ns_returns_retained attribute">; +def err_function_attribute_mismatch : Error< + "function declared with %0 attribute " + "was previously declared without the %0 attribute">; def err_objc_precise_lifetime_bad_type : Error< "objc_precise_lifetime only applies to retainable types; type here is %0">; def warn_objc_precise_lifetime_meaningless : Error< @@ -8931,8 +8938,13 @@ def warn_not_a_doxygen_trailing_member_comment : Warning< let CategoryName = "Instrumentation Issue" in { def warn_profile_data_out_of_date : Warning< "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" - " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, + " mismatched data that will be ignored">, InGroup; +def warn_profile_data_missing : Warning< + "profile data may be incomplete: of %0 function%s0, %1 %plural{1:has|:have}1" + " no data">, + InGroup, + DefaultIgnore; def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup; diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 6ae34a8..60c8a68 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -266,7 +266,8 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") -LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") +BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, + "allow editor placeholders in source") #undef LANGOPT #undef COMPATIBLE_LANGOPT diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index 2703f29..d1f0512 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -461,7 +461,7 @@ class CGFunctionInfo final unsigned EffectiveCallingConvention : 8; /// The clang::CallingConv that this was originally created with. - unsigned ASTCallingConvention : 8; + unsigned ASTCallingConvention : 7; /// Whether this is an instance method. unsigned InstanceMethod : 1; @@ -475,6 +475,9 @@ class CGFunctionInfo final /// Whether this function is returns-retained. unsigned ReturnsRetained : 1; + /// Whether this function saved caller registers. + unsigned NoCallerSavedRegs : 1; + /// How many arguments to pass inreg. unsigned HasRegParm : 1; unsigned RegParm : 3; @@ -560,6 +563,9 @@ public: /// is not always reliable for call sites. bool isReturnsRetained() const { return ReturnsRetained; } + /// Whether this function no longer saves caller registers. + bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; } + /// getASTCallingConvention() - Return the AST-specified calling /// convention. CallingConv getASTCallingConvention() const { @@ -583,10 +589,9 @@ public: unsigned getRegParm() const { return RegParm; } FunctionType::ExtInfo getExtInfo() const { - return FunctionType::ExtInfo(isNoReturn(), - getHasRegParm(), getRegParm(), - getASTCallingConvention(), - isReturnsRetained()); + return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), + getASTCallingConvention(), isReturnsRetained(), + isNoCallerSavedRegs()); } CanQualType getReturnType() const { return getArgsBuffer()[0].type; } @@ -623,6 +628,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); + ID.AddBoolean(NoCallerSavedRegs); ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); ID.AddInteger(Required.getOpaqueData()); @@ -648,6 +654,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); + ID.AddBoolean(info.getNoCallerSavedRegs()); ID.AddBoolean(info.getHasRegParm()); ID.AddInteger(info.getRegParm()); ID.AddInteger(required.getOpaqueData()); diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index 6190265..d0d9c67 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -61,6 +61,8 @@ def _SLASH_Brepro_ : CLFlag<"Brepro-">, def _SLASH_C : CLFlag<"C">, HelpText<"Don't discard comments when preprocessing">, Alias; def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias; +def _SLASH_d1reportAllClassLayout : CLFlag<"d1reportAllClassLayout">, + HelpText<"Dump record layout information">, Alias; def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">, MetaVarName<"">, Alias; def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias; diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h index b6ec8b8..b082e4e 100644 --- a/include/clang/Edit/EditedSource.h +++ b/include/clang/Edit/EditedSource.h @@ -65,7 +65,7 @@ public: bool commit(const Commit &commit); - void applyRewrites(EditsReceiver &receiver); + void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true); void clearRewrites(); StringRef copyString(StringRef str) { return str.copy(StrAlloc); } diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 778b40b..cb44985 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -99,8 +99,6 @@ class GenerateModuleAction : public ASTFrontendAction { CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0; protected: - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; - std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; @@ -112,20 +110,11 @@ protected: }; class GenerateModuleFromModuleMapAction : public GenerateModuleAction { - clang::Module *Module = nullptr; - const FileEntry *ModuleMapForUniquing = nullptr; - bool IsSystem = false; - private: bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; std::unique_ptr CreateOutputFile(CompilerInstance &CI, StringRef InFile) override; - -public: - GenerateModuleFromModuleMapAction() {} - GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem) - : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {} }; class GenerateModuleInterfaceAction : public GenerateModuleAction { diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 4fd0f82..36c0468 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -23,6 +23,7 @@ class MemoryBuffer; } namespace clang { +class FileEntry; namespace frontend { enum ActionKind { @@ -62,25 +63,65 @@ namespace frontend { }; } -enum InputKind { - IK_None, - IK_Asm, - IK_C, - IK_CXX, - IK_ObjC, - IK_ObjCXX, - IK_PreprocessedC, - IK_PreprocessedCXX, - IK_PreprocessedObjC, - IK_PreprocessedObjCXX, - IK_OpenCL, - IK_CUDA, - IK_PreprocessedCuda, - IK_RenderScript, - IK_AST, - IK_LLVM_IR -}; +/// The kind of a file that we've been handed as an input. +class InputKind { +private: + unsigned Lang : 4; + unsigned Fmt : 3; + unsigned Preprocessed : 1; + +public: + /// The language for the input, used to select and validate the language + /// standard and possible actions. + enum Language { + Unknown, + + /// Assembly: we accept this only so that we can preprocess it. + Asm, + + /// LLVM IR: we accept this so that we can run the optimizer on it, + /// and compile it to assembly or object code. + LLVM_IR, + + ///@{ Languages that the frontend can parse and compile. + C, + CXX, + ObjC, + ObjCXX, + OpenCL, + CUDA, + RenderScript, + ///@} + }; + + /// The input file format. + enum Format { + Source, + ModuleMap, + Precompiled + }; + + constexpr InputKind(Language L = Unknown, Format F = Source, + bool PP = false) + : Lang(L), Fmt(F), Preprocessed(PP) {} + + Language getLanguage() const { return static_cast(Lang); } + Format getFormat() const { return static_cast(Fmt); } + bool isPreprocessed() const { return Preprocessed; } + /// Is the input kind fully-unknown? + bool isUnknown() const { return Lang == Unknown && Fmt == Source; } + + /// Is the language of the input some dialect of Objective-C? + bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; } + + InputKind getPreprocessed() const { + return InputKind(getLanguage(), getFormat(), true); + } + InputKind withFormat(Format F) const { + return InputKind(getLanguage(), F, isPreprocessed()); + } +}; /// \brief An input file for the front end. class FrontendInputFile { @@ -96,7 +137,7 @@ class FrontendInputFile { bool IsSystem; public: - FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } + FrontendInputFile() : Buffer(nullptr), Kind(), IsSystem(false) { } FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, @@ -109,13 +150,7 @@ public: bool isEmpty() const { return File.empty() && Buffer == nullptr; } bool isFile() const { return !isBuffer(); } bool isBuffer() const { return Buffer != nullptr; } - bool isPreprocessed() const { - return Kind == IK_PreprocessedC || - Kind == IK_PreprocessedCXX || - Kind == IK_PreprocessedObjC || - Kind == IK_PreprocessedObjCXX || - Kind == IK_PreprocessedCuda; - } + bool isPreprocessed() const { return Kind.isPreprocessed(); } StringRef getFile() const { assert(isFile()); @@ -224,6 +259,10 @@ public: /// The input files and their types. std::vector Inputs; + /// When the input is a module map, the original module map file from which + /// that map was inferred, if any (for umbrella modules). + std::string OriginalModuleMap; + /// The output file, if any. std::string OutputFile; @@ -299,10 +338,10 @@ public: {} /// getInputKindForExtension - Return the appropriate input kind for a file - /// extension. For example, "c" would return IK_C. + /// extension. For example, "c" would return InputKind::C. /// - /// \return The input kind for the extension, or IK_None if the extension is - /// not recognized. + /// \return The input kind for the extension, or InputKind::Unknown if the + /// extension is not recognized. static InputKind getInputKindForExtension(StringRef Extension); }; diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h index 5ead90f..ec32aa8 100644 --- a/include/clang/Frontend/LangStandard.h +++ b/include/clang/Frontend/LangStandard.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_FRONTEND_LANGSTANDARD_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/FrontendOptions.h" #include "llvm/ADT/StringRef.h" namespace clang { @@ -19,18 +20,17 @@ namespace frontend { enum LangFeatures { LineComment = (1 << 0), - C89 = (1 << 1), - C99 = (1 << 2), - C11 = (1 << 3), - CPlusPlus = (1 << 4), - CPlusPlus11 = (1 << 5), - CPlusPlus14 = (1 << 6), - CPlusPlus1z = (1 << 7), - Digraphs = (1 << 8), - GNUMode = (1 << 9), - HexFloat = (1 << 10), - ImplicitInt = (1 << 11), - OpenCL = (1 << 12) + C99 = (1 << 1), + C11 = (1 << 2), + CPlusPlus = (1 << 3), + CPlusPlus11 = (1 << 4), + CPlusPlus14 = (1 << 5), + CPlusPlus1z = (1 << 6), + Digraphs = (1 << 7), + GNUMode = (1 << 8), + HexFloat = (1 << 9), + ImplicitInt = (1 << 10), + OpenCL = (1 << 11) }; } @@ -39,7 +39,7 @@ enum LangFeatures { /// standard. struct LangStandard { enum Kind { -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ lang_##id, #include "clang/Frontend/LangStandards.def" lang_unspecified @@ -48,6 +48,7 @@ struct LangStandard { const char *ShortName; const char *Description; unsigned Flags; + InputKind::Language Language; public: /// getName - Get the name of this standard. @@ -56,12 +57,12 @@ public: /// getDescription - Get the description of this standard. const char *getDescription() const { return Description; } + /// Get the language that this standard describes. + InputKind::Language getLanguage() const { return Language; } + /// Language supports '//' comments. bool hasLineComments() const { return Flags & frontend::LineComment; } - /// isC89 - Language is a superset of C89. - bool isC89() const { return Flags & frontend::C89; } - /// isC99 - Language is a superset of C99. bool isC99() const { return Flags & frontend::C99; } diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def index 425ac84..1d214fd 100644 --- a/include/clang/Frontend/LangStandards.def +++ b/include/clang/Frontend/LangStandards.def @@ -11,10 +11,11 @@ #error "LANGSTANDARD must be defined before including this file" #endif -/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES) /// /// \param IDENT - The name of the standard as a C++ identifier. /// \param NAME - The name of the standard. +/// \param LANG - The InputKind::Language for which this is a standard. /// \param DESC - A short description of the standard. /// \param FEATURES - The standard features as flags, these are enums from the /// clang::frontend namespace, which is assumed to be be available. @@ -23,146 +24,126 @@ /// \param IDENT - The name of the standard as a C++ identifier. /// \param ALIAS - The alias of the standard. +/// LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) +/// Same as LANGSTANDARD_ALIAS, but for a deprecated alias. + #ifndef LANGSTANDARD_ALIAS #define LANGSTANDARD_ALIAS(IDENT, ALIAS) #endif +#ifndef LANGSTANDARD_ALIAS_DEPR +#define LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) LANGSTANDARD_ALIAS(IDENT, ALIAS) +#endif + // C89-ish modes. LANGSTANDARD(c89, "c89", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(c90, "c90", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(iso9899_1990, "iso9899:1990", - "ISO C 1990", - C89 | ImplicitInt) + C, "ISO C 1990", + ImplicitInt) +LANGSTANDARD_ALIAS(c89, "c90") +LANGSTANDARD_ALIAS(c89, "iso9899:1990") LANGSTANDARD(c94, "iso9899:199409", - "ISO C 1990 with amendment 1", - C89 | Digraphs | ImplicitInt) + C, "ISO C 1990 with amendment 1", + Digraphs | ImplicitInt) LANGSTANDARD(gnu89, "gnu89", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) -LANGSTANDARD(gnu90, "gnu90", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) + C, "ISO C 1990 with GNU extensions", + LineComment | Digraphs | GNUMode | ImplicitInt) +LANGSTANDARD_ALIAS(gnu89, "gnu90") // C99-ish modes LANGSTANDARD(c99, "c99", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(c9x, "c9x", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_1999, - "iso9899:1999", "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_199x, - "iso9899:199x", "ISO C 1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c99, "iso9899:1999") +LANGSTANDARD_ALIAS_DEPR(c99, "c9x") +LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x") LANGSTANDARD(gnu99, "gnu99", - "ISO C 1999 with GNU extensions", - LineComment | C99 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu9x, "gnu9x", - "ISO C 1999 with GNU extensions", + C, "ISO C 1999 with GNU extensions", LineComment | C99 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x") // C11 modes LANGSTANDARD(c11, "c11", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(c1x, "c1x", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_2011, - "iso9899:2011", "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_201x, - "iso9899:201x", "ISO C 2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c11, "iso9899:2011") +LANGSTANDARD_ALIAS_DEPR(c11, "c1x") +LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x") LANGSTANDARD(gnu11, "gnu11", - "ISO C 2011 with GNU extensions", - LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu1x, "gnu1x", - "ISO C 2011 with GNU extensions", + C, "ISO C 2011 with GNU extensions", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") // C++ modes LANGSTANDARD(cxx98, "c++98", - "ISO C++ 1998 with amendments", - LineComment | CPlusPlus | Digraphs) -LANGSTANDARD(cxx03, "c++03", - "ISO C++ 1998 with amendments", + CXX, "ISO C++ 1998 with amendments", LineComment | CPlusPlus | Digraphs) +LANGSTANDARD_ALIAS(cxx98, "c++03") + LANGSTANDARD(gnucxx98, "gnu++98", - "ISO C++ 1998 with amendments and GNU extensions", + CXX, "ISO C++ 1998 with amendments and GNU extensions", LineComment | CPlusPlus | Digraphs | GNUMode) +LANGSTANDARD_ALIAS(gnucxx98, "gnu++03") -LANGSTANDARD(cxx0x, "c++0x", - "ISO C++ 2011 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs) LANGSTANDARD(cxx11, "c++11", - "ISO C++ 2011 with amendments", + CXX, "ISO C++ 2011 with amendments", LineComment | CPlusPlus | CPlusPlus11 | Digraphs) -LANGSTANDARD(gnucxx0x, "gnu++0x", - "ISO C++ 2011 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) -LANGSTANDARD(gnucxx11, "gnu++11", +LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x") + +LANGSTANDARD(gnucxx11, "gnu++11", CXX, "ISO C++ 2011 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x") -LANGSTANDARD(cxx1y, "c++1y", - "ISO C++ 2014 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) LANGSTANDARD(cxx14, "c++14", - "ISO C++ 2014 with amendments", + CXX, "ISO C++ 2014 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) -LANGSTANDARD(gnucxx1y, "gnu++1y", - "ISO C++ 2014 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | - GNUMode) +LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y") + LANGSTANDARD(gnucxx14, "gnu++14", - "ISO C++ 2014 with amendments and GNU extensions", + CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y") LANGSTANDARD(cxx1z, "c++1z", - "Working draft for ISO C++ 2017", + CXX, "Working draft for ISO C++ 2017", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat) + LANGSTANDARD(gnucxx1z, "gnu++1z", - "Working draft for ISO C++ 2017 with GNU extensions", + CXX, "Working draft for ISO C++ 2017 with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat | GNUMode) // OpenCL -LANGSTANDARD(opencl, "cl", - "OpenCL 1.0", +LANGSTANDARD(opencl10, "cl1.0", + OpenCL, "OpenCL 1.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) +LANGSTANDARD_ALIAS_DEPR(opencl10, "cl") + LANGSTANDARD(opencl11, "cl1.1", - "OpenCL 1.1", + OpenCL, "OpenCL 1.1", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl12, "cl1.2", - "OpenCL 1.2", + OpenCL, "OpenCL 1.2", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl20, "cl2.0", - "OpenCL 2.0", + OpenCL, "OpenCL 2.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) -LANGSTANDARD_ALIAS(opencl, "CL") -LANGSTANDARD_ALIAS(opencl11, "CL1.1") -LANGSTANDARD_ALIAS(opencl12, "CL1.2") -LANGSTANDARD_ALIAS(opencl20, "CL2.0") +LANGSTANDARD_ALIAS_DEPR(opencl10, "CL") +LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") +LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2") +LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0") // CUDA -LANGSTANDARD(cuda, "cuda", - "NVIDIA CUDA(tm)", +LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", LineComment | CPlusPlus | Digraphs) #undef LANGSTANDARD #undef LANGSTANDARD_ALIAS - +#undef LANGSTANDARD_ALIAS_DEPR diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index 51983b9..64c6f2a 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -375,13 +375,16 @@ public: /// \param SuggestedModule If non-null, and the file found is semantically /// part of a known module, this will be set to the module that should /// be imported instead of preprocessing/parsing the file found. + /// + /// \param IsMapped If non-null, and the search involved header maps, set to + /// true. const FileEntry *LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef> Includers, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false, bool BuildSystemModule = false); + bool *IsMapped, bool SkipCache = false, bool BuildSystemModule = false); /// \brief Look up a subframework for the specified \#include file. /// diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 6cc3b0b..44b7b2e 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -126,7 +126,7 @@ public: SourceLocation getDefinitionEndLoc() const { return EndLocation; } /// \brief Get length in characters of the macro definition. - unsigned getDefinitionLength(SourceManager &SM) const { + unsigned getDefinitionLength(const SourceManager &SM) const { if (IsDefinitionLengthCached) return DefinitionLength; return getDefinitionLengthSlow(SM); @@ -285,7 +285,7 @@ public: void dump() const; private: - unsigned getDefinitionLengthSlow(SourceManager &SM) const; + unsigned getDefinitionLengthSlow(const SourceManager &SM) const; void setOwningModuleID(unsigned ID) { assert(isFromASTFile()); diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 2d027f3..81c3bd7 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -247,10 +247,14 @@ public: } /// \brief Hook called whenever a macro \#undef is seen. + /// \param MacroNameTok The active Token + /// \param MD A MacroDefinition for the named macro. + /// \param Undef New MacroDirective if the macro was defined, null otherwise. /// /// MD is released immediately following this callback. virtual void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { } /// \brief Hook called whenever the 'defined' operator is seen. @@ -439,15 +443,17 @@ public: Second->MacroExpands(MacroNameTok, MD, Range, Args); } - void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { First->MacroDefined(MacroNameTok, MD); Second->MacroDefined(MacroNameTok, MD); } void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override { - First->MacroUndefined(MacroNameTok, MD); - Second->MacroUndefined(MacroNameTok, MD); + const MacroDefinition &MD, + const MacroDirective *Undef) override { + First->MacroUndefined(MacroNameTok, MD, Undef); + Second->MacroUndefined(MacroNameTok, MD, Undef); } void Defined(const Token &MacroNameTok, const MacroDefinition &MD, diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 826ba33..fc2c507 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -488,7 +488,8 @@ namespace clang { void MacroExpands(const Token &Id, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override; void MacroDefined(const Token &Id, const MacroDirective *MD) override; - void MacroUndefined(const Token &Id, const MacroDefinition &MD) override; + void MacroUndefined(const Token &Id, const MacroDefinition &MD, + const MacroDirective *Undef) override; void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 3efe914..b1a7325 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1263,6 +1263,10 @@ public: CachedTokens[CachedLexPos-1] = Tok; } + /// Enter an annotation token into the token stream. + void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, + void *AnnotationVal); + /// Update the current token to represent the provided /// identifier, in order to cache an action performed by typo correction. void TypoCorrectToken(const Token &Tok) { @@ -1602,6 +1606,7 @@ private: *Ident_AbnormalTermination; const char *getCurLexerEndPos(); + void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod); public: void PoisonSEHIdentifiers(bool Poison = true); // Borland @@ -1686,7 +1691,7 @@ public: SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false); + bool *IsMapped, bool SkipCache = false); /// \brief Get the DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. @@ -1962,6 +1967,7 @@ public: void HandlePragmaPoison(); void HandlePragmaSystemHeader(Token &SysHeaderTok); void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaModuleImport(Token &Tok); void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); void HandlePragmaIncludeAlias(Token &Tok); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0f16cb9..e24d643 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1068,6 +1068,12 @@ public: /// same special member, we should act as if it is not yet declared. llvm::SmallSet SpecialMembersBeingDeclared; + /// The function definitions which were renamed as part of typo-correction + /// to match their respective declarations. We want to keep track of them + /// to ensure that we don't emit a "redefinition" error if we encounter a + /// correctly named definition after the renamed definition. + llvm::SmallPtrSet TypoCorrectedFunctionDefinitions; + void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); @@ -3117,6 +3123,8 @@ public: const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); + void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, @@ -3162,6 +3170,7 @@ public: bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckNoReturnAttr(const AttributeList &attr); + bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); @@ -10151,7 +10160,6 @@ private: void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); - void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(Expr *E); /// \brief Perform semantic checks on a completed expression. This will either diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 241a724..fcc67da 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -2189,7 +2189,7 @@ static std::string applyEditsToTemp(const FileEntry *FE, Rewriter rewriter(SM, LangOpts); RewritesReceiver Rec(rewriter); - Editor.applyRewrites(Rec); + Editor.applyRewrites(Rec, /*adjustRemovals=*/false); const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID); SmallString<512> NewText; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4626052..3b526a2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -7918,6 +7918,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) return QualType(); + if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs()) + return QualType(); // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 9549282..4fb6051 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTImporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" @@ -321,1396 +322,12 @@ namespace clang { }; } -using namespace clang; - -//---------------------------------------------------------------------------- -// Structural Equivalence -//---------------------------------------------------------------------------- - -namespace { - struct StructuralEquivalenceContext { - /// \brief AST contexts for which we are checking structural equivalence. - ASTContext &C1, &C2; - - /// \brief The set of "tentative" equivalences between two canonical - /// declarations, mapping from a declaration in the first context to the - /// declaration in the second context that we believe to be equivalent. - llvm::DenseMap TentativeEquivalences; - - /// \brief Queue of declarations in the first context whose equivalence - /// with a declaration in the second context still needs to be verified. - std::deque DeclsToCheck; - - /// \brief Declaration (from, to) pairs that are known not to be equivalent - /// (which we have already complained about). - llvm::DenseSet > &NonEquivalentDecls; - - /// \brief Whether we're being strict about the spelling of types when - /// unifying two types. - bool StrictTypeSpelling; - - /// \brief Whether to complain about failures. - bool Complain; - - /// \brief \c true if the last diagnostic came from C2. - bool LastDiagFromC2; - - StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, - llvm::DenseSet > &NonEquivalentDecls, - bool StrictTypeSpelling = false, - bool Complain = true) - : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), - StrictTypeSpelling(StrictTypeSpelling), Complain(Complain), - LastDiagFromC2(false) {} - - /// \brief Determine whether the two declarations are structurally - /// equivalent. - bool IsStructurallyEquivalent(Decl *D1, Decl *D2); - - /// \brief Determine whether the two types are structurally equivalent. - bool IsStructurallyEquivalent(QualType T1, QualType T2); - - private: - /// \brief Finish checking all of the structural equivalences. - /// - /// \returns true if an error occurred, false otherwise. - bool Finish(); - - public: - DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { - assert(Complain && "Not allowed to complain"); - if (LastDiagFromC2) - C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics()); - LastDiagFromC2 = false; - return C1.getDiagnostics().Report(Loc, DiagID); - } - - DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { - assert(Complain && "Not allowed to complain"); - if (!LastDiagFromC2) - C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics()); - LastDiagFromC2 = true; - return C2.getDiagnostics().Report(Loc, DiagID); - } - }; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - QualType T1, QualType T2); -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Decl *D1, Decl *D2); -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateArgument &Arg1, - const TemplateArgument &Arg2); - -/// \brief Determine structural equivalence of two expressions. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Expr *E1, Expr *E2) { - if (!E1 || !E2) - return E1 == E2; - - // FIXME: Actually perform a structural comparison! - return true; -} - -/// \brief Determine whether two identifiers are equivalent. -static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, - const IdentifierInfo *Name2) { - if (!Name1 || !Name2) - return Name1 == Name2; - - return Name1->getName() == Name2->getName(); -} - -/// \brief Determine whether two nested-name-specifiers are equivalent. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2) { - if (NNS1->getKind() != NNS2->getKind()) - return false; - - NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), - *Prefix2 = NNS2->getPrefix(); - if ((bool)Prefix1 != (bool)Prefix2) - return false; - - if (Prefix1) - if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) - return false; - - switch (NNS1->getKind()) { - case NestedNameSpecifier::Identifier: - return IsStructurallyEquivalent(NNS1->getAsIdentifier(), - NNS2->getAsIdentifier()); - case NestedNameSpecifier::Namespace: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), - NNS2->getAsNamespace()); - case NestedNameSpecifier::NamespaceAlias: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(), - NNS2->getAsNamespaceAlias()); - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), - QualType(NNS2->getAsType(), 0)); - case NestedNameSpecifier::Global: - return true; - case NestedNameSpecifier::Super: - return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), - NNS2->getAsRecordDecl()); - } - return false; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateName &N1, - const TemplateName &N2) { - if (N1.getKind() != N2.getKind()) - return false; - switch (N1.getKind()) { - case TemplateName::Template: - return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(), - N2.getAsTemplateDecl()); - - case TemplateName::OverloadedTemplate: { - OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(), - *OS2 = N2.getAsOverloadedTemplate(); - OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(), - E1 = OS1->end(), E2 = OS2->end(); - for (; I1 != E1 && I2 != E2; ++I1, ++I2) - if (!IsStructurallyEquivalent(Context, *I1, *I2)) - return false; - return I1 == E1 && I2 == E2; - } - - case TemplateName::QualifiedTemplate: { - QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), - *QN2 = N2.getAsQualifiedTemplateName(); - return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) && - IsStructurallyEquivalent(Context, QN1->getQualifier(), - QN2->getQualifier()); - } - - case TemplateName::DependentTemplate: { - DependentTemplateName *DN1 = N1.getAsDependentTemplateName(), - *DN2 = N2.getAsDependentTemplateName(); - if (!IsStructurallyEquivalent(Context, DN1->getQualifier(), - DN2->getQualifier())) - return false; - if (DN1->isIdentifier() && DN2->isIdentifier()) - return IsStructurallyEquivalent(DN1->getIdentifier(), - DN2->getIdentifier()); - else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator()) - return DN1->getOperator() == DN2->getOperator(); - return false; - } - - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(), - *TS2 = N2.getAsSubstTemplateTemplateParm(); - return IsStructurallyEquivalent(Context, TS1->getParameter(), - TS2->getParameter()) && - IsStructurallyEquivalent(Context, TS1->getReplacement(), - TS2->getReplacement()); - } - case TemplateName::SubstTemplateTemplateParmPack: { - SubstTemplateTemplateParmPackStorage - *P1 = N1.getAsSubstTemplateTemplateParmPack(), - *P2 = N2.getAsSubstTemplateTemplateParmPack(); - return IsStructurallyEquivalent(Context, P1->getArgumentPack(), - P2->getArgumentPack()) && - IsStructurallyEquivalent(Context, P1->getParameterPack(), - P2->getParameterPack()); - } - } - return false; -} - -/// \brief Determine whether two template arguments are equivalent. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateArgument &Arg1, - const TemplateArgument &Arg2) { - if (Arg1.getKind() != Arg2.getKind()) - return false; - - switch (Arg1.getKind()) { - case TemplateArgument::Null: - return true; - - case TemplateArgument::Type: - return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); - - case TemplateArgument::Integral: - if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), - Arg2.getIntegralType())) - return false; - - return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral()); - - case TemplateArgument::Declaration: - return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); - - case TemplateArgument::NullPtr: - return true; // FIXME: Is this correct? - - case TemplateArgument::Template: - return IsStructurallyEquivalent(Context, - Arg1.getAsTemplate(), - Arg2.getAsTemplate()); - - case TemplateArgument::TemplateExpansion: - return IsStructurallyEquivalent(Context, - Arg1.getAsTemplateOrTemplatePattern(), - Arg2.getAsTemplateOrTemplatePattern()); - - case TemplateArgument::Expression: - return IsStructurallyEquivalent(Context, - Arg1.getAsExpr(), Arg2.getAsExpr()); - - case TemplateArgument::Pack: - if (Arg1.pack_size() != Arg2.pack_size()) - return false; - - for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, - Arg1.pack_begin()[I], - Arg2.pack_begin()[I])) - return false; - - return true; - } - - llvm_unreachable("Invalid template argument kind"); -} - -/// \brief Determine structural equivalence for the common part of array -/// types. -static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, - const ArrayType *Array1, - const ArrayType *Array2) { - if (!IsStructurallyEquivalent(Context, - Array1->getElementType(), - Array2->getElementType())) - return false; - if (Array1->getSizeModifier() != Array2->getSizeModifier()) - return false; - if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) - return false; - - return true; -} - -/// \brief Determine structural equivalence of two types. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - QualType T1, QualType T2) { - if (T1.isNull() || T2.isNull()) - return T1.isNull() && T2.isNull(); - - if (!Context.StrictTypeSpelling) { - // We aren't being strict about token-to-token equivalence of types, - // so map down to the canonical type. - T1 = Context.C1.getCanonicalType(T1); - T2 = Context.C2.getCanonicalType(T2); - } - - if (T1.getQualifiers() != T2.getQualifiers()) - return false; - - Type::TypeClass TC = T1->getTypeClass(); - - if (T1->getTypeClass() != T2->getTypeClass()) { - // Compare function types with prototypes vs. without prototypes as if - // both did not have prototypes. - if (T1->getTypeClass() == Type::FunctionProto && - T2->getTypeClass() == Type::FunctionNoProto) - TC = Type::FunctionNoProto; - else if (T1->getTypeClass() == Type::FunctionNoProto && - T2->getTypeClass() == Type::FunctionProto) - TC = Type::FunctionNoProto; - else - return false; - } - - switch (TC) { - case Type::Builtin: - // FIXME: Deal with Char_S/Char_U. - if (cast(T1)->getKind() != cast(T2)->getKind()) - return false; - break; - - case Type::Complex: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getElementType(), - cast(T2)->getElementType())) - return false; - break; - - case Type::Adjusted: - case Type::Decayed: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getOriginalType(), - cast(T2)->getOriginalType())) - return false; - break; - - case Type::Pointer: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getPointeeType(), - cast(T2)->getPointeeType())) - return false; - break; - - case Type::BlockPointer: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getPointeeType(), - cast(T2)->getPointeeType())) - return false; - break; - - case Type::LValueReference: - case Type::RValueReference: { - const ReferenceType *Ref1 = cast(T1); - const ReferenceType *Ref2 = cast(T2); - if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) - return false; - if (Ref1->isInnerRef() != Ref2->isInnerRef()) - return false; - if (!IsStructurallyEquivalent(Context, - Ref1->getPointeeTypeAsWritten(), - Ref2->getPointeeTypeAsWritten())) - return false; - break; - } - - case Type::MemberPointer: { - const MemberPointerType *MemPtr1 = cast(T1); - const MemberPointerType *MemPtr2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - MemPtr1->getPointeeType(), - MemPtr2->getPointeeType())) - return false; - if (!IsStructurallyEquivalent(Context, - QualType(MemPtr1->getClass(), 0), - QualType(MemPtr2->getClass(), 0))) - return false; - break; - } - - case Type::ConstantArray: { - const ConstantArrayType *Array1 = cast(T1); - const ConstantArrayType *Array2 = cast(T2); - if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - break; - } - - case Type::IncompleteArray: - if (!IsArrayStructurallyEquivalent(Context, - cast(T1), - cast(T2))) - return false; - break; - - case Type::VariableArray: { - const VariableArrayType *Array1 = cast(T1); - const VariableArrayType *Array2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Array1->getSizeExpr(), Array2->getSizeExpr())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - - break; - } - - case Type::DependentSizedArray: { - const DependentSizedArrayType *Array1 = cast(T1); - const DependentSizedArrayType *Array2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Array1->getSizeExpr(), Array2->getSizeExpr())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - - break; - } - - case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *Vec1 - = cast(T1); - const DependentSizedExtVectorType *Vec2 - = cast(T2); - if (!IsStructurallyEquivalent(Context, - Vec1->getSizeExpr(), Vec2->getSizeExpr())) - return false; - if (!IsStructurallyEquivalent(Context, - Vec1->getElementType(), - Vec2->getElementType())) - return false; - break; - } - - case Type::Vector: - case Type::ExtVector: { - const VectorType *Vec1 = cast(T1); - const VectorType *Vec2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Vec1->getElementType(), - Vec2->getElementType())) - return false; - if (Vec1->getNumElements() != Vec2->getNumElements()) - return false; - if (Vec1->getVectorKind() != Vec2->getVectorKind()) - return false; - break; - } - - case Type::FunctionProto: { - const FunctionProtoType *Proto1 = cast(T1); - const FunctionProtoType *Proto2 = cast(T2); - if (Proto1->getNumParams() != Proto2->getNumParams()) - return false; - for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I), - Proto2->getParamType(I))) - return false; - } - if (Proto1->isVariadic() != Proto2->isVariadic()) - return false; - if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) - return false; - if (Proto1->getExceptionSpecType() == EST_Dynamic) { - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) - return false; - } - } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { - if (!IsStructurallyEquivalent(Context, - Proto1->getNoexceptExpr(), - Proto2->getNoexceptExpr())) - return false; - } - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) - return false; - - // Fall through to check the bits common with FunctionNoProtoType. - } - - case Type::FunctionNoProto: { - const FunctionType *Function1 = cast(T1); - const FunctionType *Function2 = cast(T2); - if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), - Function2->getReturnType())) - return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) - return false; - break; - } - - case Type::UnresolvedUsing: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getDecl(), - cast(T2)->getDecl())) - return false; - - break; - - case Type::Attributed: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getModifiedType(), - cast(T2)->getModifiedType())) - return false; - if (!IsStructurallyEquivalent(Context, - cast(T1)->getEquivalentType(), - cast(T2)->getEquivalentType())) - return false; - break; - - case Type::Paren: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getInnerType(), - cast(T2)->getInnerType())) - return false; - break; - - case Type::Typedef: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getDecl(), - cast(T2)->getDecl())) - return false; - break; - - case Type::TypeOfExpr: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getUnderlyingExpr(), - cast(T2)->getUnderlyingExpr())) - return false; - break; - - case Type::TypeOf: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getUnderlyingType(), - cast(T2)->getUnderlyingType())) - return false; - break; - - case Type::UnaryTransform: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getUnderlyingType(), - cast(T1)->getUnderlyingType())) - return false; - break; - - case Type::Decltype: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getUnderlyingExpr(), - cast(T2)->getUnderlyingExpr())) - return false; - break; - - case Type::Auto: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getDeducedType(), - cast(T2)->getDeducedType())) - return false; - break; - - case Type::DeducedTemplateSpecialization: { - auto *DT1 = cast(T1); - auto *DT2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - DT1->getTemplateName(), - DT2->getTemplateName())) - return false; - if (!IsStructurallyEquivalent(Context, - DT1->getDeducedType(), - DT2->getDeducedType())) - return false; - break; - } - - case Type::Record: - case Type::Enum: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getDecl(), - cast(T2)->getDecl())) - return false; - break; - - case Type::TemplateTypeParm: { - const TemplateTypeParmType *Parm1 = cast(T1); - const TemplateTypeParmType *Parm2 = cast(T2); - if (Parm1->getDepth() != Parm2->getDepth()) - return false; - if (Parm1->getIndex() != Parm2->getIndex()) - return false; - if (Parm1->isParameterPack() != Parm2->isParameterPack()) - return false; - - // Names of template type parameters are never significant. - break; - } - - case Type::SubstTemplateTypeParm: { - const SubstTemplateTypeParmType *Subst1 - = cast(T1); - const SubstTemplateTypeParmType *Subst2 - = cast(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) - return false; - if (!IsStructurallyEquivalent(Context, - Subst1->getReplacementType(), - Subst2->getReplacementType())) - return false; - break; - } - - case Type::SubstTemplateTypeParmPack: { - const SubstTemplateTypeParmPackType *Subst1 - = cast(T1); - const SubstTemplateTypeParmPackType *Subst2 - = cast(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) - return false; - if (!IsStructurallyEquivalent(Context, - Subst1->getArgumentPack(), - Subst2->getArgumentPack())) - return false; - break; - } - case Type::TemplateSpecialization: { - const TemplateSpecializationType *Spec1 - = cast(T1); - const TemplateSpecializationType *Spec2 - = cast(T2); - if (!IsStructurallyEquivalent(Context, - Spec1->getTemplateName(), - Spec2->getTemplateName())) - return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) - return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Spec1->getArg(I), Spec2->getArg(I))) - return false; - } - break; - } - - case Type::Elaborated: { - const ElaboratedType *Elab1 = cast(T1); - const ElaboratedType *Elab2 = cast(T2); - // CHECKME: what if a keyword is ETK_None or ETK_typename ? - if (Elab1->getKeyword() != Elab2->getKeyword()) - return false; - if (!IsStructurallyEquivalent(Context, - Elab1->getQualifier(), - Elab2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Context, - Elab1->getNamedType(), - Elab2->getNamedType())) - return false; - break; - } - - case Type::InjectedClassName: { - const InjectedClassNameType *Inj1 = cast(T1); - const InjectedClassNameType *Inj2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Inj1->getInjectedSpecializationType(), - Inj2->getInjectedSpecializationType())) - return false; - break; - } - - case Type::DependentName: { - const DependentNameType *Typename1 = cast(T1); - const DependentNameType *Typename2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Typename1->getQualifier(), - Typename2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Typename1->getIdentifier(), - Typename2->getIdentifier())) - return false; - - break; - } - - case Type::DependentTemplateSpecialization: { - const DependentTemplateSpecializationType *Spec1 = - cast(T1); - const DependentTemplateSpecializationType *Spec2 = - cast(T2); - if (!IsStructurallyEquivalent(Context, - Spec1->getQualifier(), - Spec2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Spec1->getIdentifier(), - Spec2->getIdentifier())) - return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) - return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Spec1->getArg(I), Spec2->getArg(I))) - return false; - } - break; - } - - case Type::PackExpansion: - if (!IsStructurallyEquivalent(Context, - cast(T1)->getPattern(), - cast(T2)->getPattern())) - return false; - break; - - case Type::ObjCInterface: { - const ObjCInterfaceType *Iface1 = cast(T1); - const ObjCInterfaceType *Iface2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Iface1->getDecl(), Iface2->getDecl())) - return false; - break; - } - - case Type::ObjCTypeParam: { - const ObjCTypeParamType *Obj1 = cast(T1); - const ObjCTypeParamType *Obj2 = cast(T2); - if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), - Obj2->getDecl())) - return false; - - if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) - return false; - for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Obj1->getProtocol(I), - Obj2->getProtocol(I))) - return false; - } - break; - } - case Type::ObjCObject: { - const ObjCObjectType *Obj1 = cast(T1); - const ObjCObjectType *Obj2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Obj1->getBaseType(), - Obj2->getBaseType())) - return false; - if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) - return false; - for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Obj1->getProtocol(I), - Obj2->getProtocol(I))) - return false; - } - break; - } - - case Type::ObjCObjectPointer: { - const ObjCObjectPointerType *Ptr1 = cast(T1); - const ObjCObjectPointerType *Ptr2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Ptr1->getPointeeType(), - Ptr2->getPointeeType())) - return false; - break; - } - - case Type::Atomic: { - if (!IsStructurallyEquivalent(Context, - cast(T1)->getValueType(), - cast(T2)->getValueType())) - return false; - break; - } - - case Type::Pipe: { - if (!IsStructurallyEquivalent(Context, - cast(T1)->getElementType(), - cast(T2)->getElementType())) - return false; - break; - } - - } // end switch - - return true; -} - -/// \brief Determine structural equivalence of two fields. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - FieldDecl *Field1, FieldDecl *Field2) { - RecordDecl *Owner2 = cast(Field2->getDeclContext()); - - // For anonymous structs/unions, match up the anonymous struct/union type - // declarations directly, so that we don't go off searching for anonymous - // types - if (Field1->isAnonymousStructOrUnion() && - Field2->isAnonymousStructOrUnion()) { - RecordDecl *D1 = Field1->getType()->castAs()->getDecl(); - RecordDecl *D2 = Field2->getType()->castAs()->getDecl(); - return IsStructurallyEquivalent(Context, D1, D2); - } - - // Check for equivalent field names. - IdentifierInfo *Name1 = Field1->getIdentifier(); - IdentifierInfo *Name2 = Field2->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2)) - return false; - - if (!IsStructurallyEquivalent(Context, - Field1->getType(), Field2->getType())) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - } - return false; - } - - if (Field1->isBitField() != Field2->isBitField()) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - if (Field1->isBitField()) { - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Field1->getBitWidthValue(Context.C1); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Field2->getBitWidthValue(Context.C2); - Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) - << Field1->getDeclName(); - } - } - return false; - } - - if (Field1->isBitField()) { - // Make sure that the bit-fields are the same length. - unsigned Bits1 = Field1->getBitWidthValue(Context.C1); - unsigned Bits2 = Field2->getBitWidthValue(Context.C2); - - if (Bits1 != Bits2) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() << Bits2; - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() << Bits1; - } - return false; - } - } - - return true; -} - -/// \brief Find the index of the given anonymous struct/union within its -/// context. -/// -/// \returns Returns the index of this anonymous struct/union in its context, -/// including the next assigned index (if none of them match). Returns an -/// empty option if the context is not a record, i.e.. if the anonymous -/// struct/union is at namespace or block scope. -static Optional findUntaggedStructOrUnionIndex(RecordDecl *Anon) { - ASTContext &Context = Anon->getASTContext(); - QualType AnonTy = Context.getRecordType(Anon); - - RecordDecl *Owner = dyn_cast(Anon->getDeclContext()); - if (!Owner) - return None; - - unsigned Index = 0; - for (const auto *D : Owner->noload_decls()) { - const auto *F = dyn_cast(D); - if (!F) - continue; - - if (F->isAnonymousStructOrUnion()) { - if (Context.hasSameType(F->getType(), AnonTy)) - break; - ++Index; - continue; - } - - // If the field looks like this: - // struct { ... } A; - QualType FieldType = F->getType(); - if (const auto *RecType = dyn_cast(FieldType)) { - const RecordDecl *RecDecl = RecType->getDecl(); - if (RecDecl->getDeclContext() == Owner && - !RecDecl->getIdentifier()) { - if (Context.hasSameType(FieldType, AnonTy)) - break; - ++Index; - continue; - } - } - } - - return Index; -} - -/// \brief Determine structural equivalence of two records. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - RecordDecl *D1, RecordDecl *D2) { - if (D1->isUnion() != D2->isUnion()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) - << D1->getDeclName() << (unsigned)D1->getTagKind(); - } - return false; - } - - if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { - // If both anonymous structs/unions are in a record context, make sure - // they occur in the same location in the context records. - if (Optional Index1 = findUntaggedStructOrUnionIndex(D1)) { - if (Optional Index2 = findUntaggedStructOrUnionIndex(D2)) { - if (*Index1 != *Index2) - return false; - } - } - } - - // If both declarations are class template specializations, we know - // the ODR applies, so check the template and template arguments. - ClassTemplateSpecializationDecl *Spec1 - = dyn_cast(D1); - ClassTemplateSpecializationDecl *Spec2 - = dyn_cast(D2); - if (Spec1 && Spec2) { - // Check that the specialized templates are the same. - if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), - Spec2->getSpecializedTemplate())) - return false; - - // Check that the template arguments are the same. - if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) - return false; - - for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, - Spec1->getTemplateArgs().get(I), - Spec2->getTemplateArgs().get(I))) - return false; - } - // If one is a class template specialization and the other is not, these - // structures are different. - else if (Spec1 || Spec2) - return false; - - // Compare the definitions of these two records. If either or both are - // incomplete, we assume that they are equivalent. - D1 = D1->getDefinition(); - D2 = D2->getDefinition(); - if (!D1 || !D2) - return true; - - if (CXXRecordDecl *D1CXX = dyn_cast(D1)) { - if (CXXRecordDecl *D2CXX = dyn_cast(D2)) { - if (D1CXX->getNumBases() != D2CXX->getNumBases()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) - << D2CXX->getNumBases(); - Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) - << D1CXX->getNumBases(); - } - return false; - } - - // Check the base classes. - for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), - BaseEnd1 = D1CXX->bases_end(), - Base2 = D2CXX->bases_begin(); - Base1 != BaseEnd1; - ++Base1, ++Base2) { - if (!IsStructurallyEquivalent(Context, - Base1->getType(), Base2->getType())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), diag::note_odr_base) - << Base2->getType() - << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - } - return false; - } - - // Check virtual vs. non-virtual inheritance mismatch. - if (Base1->isVirtual() != Base2->isVirtual()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), - diag::note_odr_virtual_base) - << Base2->isVirtual() << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->isVirtual() - << Base1->getSourceRange(); - } - return false; - } - } - } else if (D1CXX->getNumBases() > 0) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); - } - return false; - } - } - - // Check the fields for consistency. - RecordDecl::field_iterator Field2 = D2->field_begin(), - Field2End = D2->field_end(); - for (RecordDecl::field_iterator Field1 = D1->field_begin(), - Field1End = D1->field_end(); - Field1 != Field1End; - ++Field1, ++Field2) { - if (Field2 == Field2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); - } - return false; - } - - if (!IsStructurallyEquivalent(Context, *Field1, *Field2)) - return false; - } - - if (Field2 != Field2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); - } - return false; - } - - return true; -} - -/// \brief Determine structural equivalence of two enums. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - EnumDecl *D1, EnumDecl *D2) { - EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), - EC2End = D2->enumerator_end(); - for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), - EC1End = D1->enumerator_end(); - EC1 != EC1End; ++EC1, ++EC2) { - if (EC2 == EC2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); - } - return false; - } - - llvm::APSInt Val1 = EC1->getInitVal(); - llvm::APSInt Val2 = EC2->getInitVal(); - if (!llvm::APSInt::isSameValue(Val1, Val2) || - !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - } - return false; - } - } - - if (EC2 != EC2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateParameterList *Params1, - TemplateParameterList *Params2) { - if (Params1->size() != Params2->size()) { - if (Context.Complain) { - Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) - << Params1->size() << Params2->size(); - Context.Diag1(Params1->getTemplateLoc(), - diag::note_odr_template_parameter_list); - } - return false; - } - - for (unsigned I = 0, N = Params1->size(); I != N; ++I) { - if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { - if (Context.Complain) { - Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); - Context.Diag1(Params1->getParam(I)->getLocation(), - diag::note_odr_template_parameter_here); - } - return false; - } - - if (!Context.IsStructurallyEquivalent(Params1->getParam(I), - Params2->getParam(I))) { - - return false; - } - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateTypeParmDecl *D1, - TemplateTypeParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NonTypeTemplateParmDecl *D1, - NonTypeTemplateParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - // Check types. - if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) - << D2->getType() << D1->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_value_here) - << D1->getType(); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateTemplateParmDecl *D1, - TemplateTemplateParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - // Check template parameter lists. - return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), - D2->getTemplateParameters()); -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - ClassTemplateDecl *D1, - ClassTemplateDecl *D2) { - // Check template parameters. - if (!IsStructurallyEquivalent(Context, - D1->getTemplateParameters(), - D2->getTemplateParameters())) - return false; - - // Check the templated declaration. - return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), - D2->getTemplatedDecl()); -} - -/// \brief Determine structural equivalence of two declarations. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Decl *D1, Decl *D2) { - // FIXME: Check for known structural equivalences via a callback of some sort. - - // Check whether we already know that these two declarations are not - // structurally equivalent. - if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(), - D2->getCanonicalDecl()))) - return false; - - // Determine whether we've already produced a tentative equivalence for D1. - Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; - if (EquivToD1) - return EquivToD1 == D2->getCanonicalDecl(); - - // Produce a tentative equivalence D1 <-> D2, which will be checked later. - EquivToD1 = D2->getCanonicalDecl(); - Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); - return true; -} - -bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, - Decl *D2) { - if (!::IsStructurallyEquivalent(*this, D1, D2)) - return false; - - return !Finish(); -} - -bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, - QualType T2) { - if (!::IsStructurallyEquivalent(*this, T1, T2)) - return false; - - return !Finish(); -} - -bool StructuralEquivalenceContext::Finish() { - while (!DeclsToCheck.empty()) { - // Check the next declaration. - Decl *D1 = DeclsToCheck.front(); - DeclsToCheck.pop_front(); - - Decl *D2 = TentativeEquivalences[D1]; - assert(D2 && "Unrecorded tentative equivalence?"); - - bool Equivalent = true; - - // FIXME: Switch on all declaration kinds. For now, we're just going to - // check the obvious ones. - if (RecordDecl *Record1 = dyn_cast(D1)) { - if (RecordDecl *Record2 = dyn_cast(D2)) { - // Check for equivalent structure names. - IdentifierInfo *Name1 = Record1->getIdentifier(); - if (!Name1 && Record1->getTypedefNameForAnonDecl()) - Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Record2->getIdentifier(); - if (!Name2 && Record2->getTypedefNameForAnonDecl()) - Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Record1, Record2)) - Equivalent = false; - } else { - // Record/non-record mismatch. - Equivalent = false; - } - } else if (EnumDecl *Enum1 = dyn_cast(D1)) { - if (EnumDecl *Enum2 = dyn_cast(D2)) { - // Check for equivalent enum names. - IdentifierInfo *Name1 = Enum1->getIdentifier(); - if (!Name1 && Enum1->getTypedefNameForAnonDecl()) - Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Enum2->getIdentifier(); - if (!Name2 && Enum2->getTypedefNameForAnonDecl()) - Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Enum1, Enum2)) - Equivalent = false; - } else { - // Enum/non-enum mismatch - Equivalent = false; - } - } else if (TypedefNameDecl *Typedef1 = dyn_cast(D1)) { - if (TypedefNameDecl *Typedef2 = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), - Typedef2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, - Typedef1->getUnderlyingType(), - Typedef2->getUnderlyingType())) - Equivalent = false; - } else { - // Typedef/non-typedef mismatch. - Equivalent = false; - } - } else if (ClassTemplateDecl *ClassTemplate1 - = dyn_cast(D1)) { - if (ClassTemplateDecl *ClassTemplate2 = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), - ClassTemplate2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) - Equivalent = false; - } else { - // Class template/non-class-template mismatch. - Equivalent = false; - } - } else if (TemplateTypeParmDecl *TTP1= dyn_cast(D1)) { - if (TemplateTypeParmDecl *TTP2 = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (NonTypeTemplateParmDecl *NTTP1 - = dyn_cast(D1)) { - if (NonTypeTemplateParmDecl *NTTP2 - = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (TemplateTemplateParmDecl *TTP1 - = dyn_cast(D1)) { - if (TemplateTemplateParmDecl *TTP2 - = dyn_cast(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } - - if (!Equivalent) { - // Note that these two declarations are not equivalent (and we already - // know about it). - NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(), - D2->getCanonicalDecl())); - return true; - } - // FIXME: Check other declaration kinds! - } - - return false; -} - //---------------------------------------------------------------------------- // Import Types //---------------------------------------------------------------------------- +using namespace clang; + QualType ASTNodeImporter::VisitType(const Type *T) { Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) << T->getTypeClassName(); @@ -2634,7 +1251,7 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls()); - return Ctx.IsStructurallyEquivalent(From, To); + return Ctx.IsStructurallyEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, @@ -2813,10 +1430,10 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { FoundTypedef->getUnderlyingType())) return Importer.Imported(D, FoundTypedef); } - + ConflictingDecls.push_back(FoundDecls[I]); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, IDNS, ConflictingDecls.data(), @@ -2825,7 +1442,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { return nullptr; } } - + // Import the underlying type of this typedef; QualType T = Importer.Import(D->getUnderlyingType()); if (T.isNull()) @@ -2845,12 +1462,12 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { StartL, Loc, Name.getAsIdentifierInfo(), TInfo); - + ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); LexicalDC->addDeclInternal(ToTypedef); - + return ToTypedef; } @@ -3024,9 +1641,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { FoundRecord->isAnonymousStructOrUnion()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. - if (Optional Index1 - = findUntaggedStructOrUnionIndex(D)) { - if (Optional Index2 = + if (Optional Index1 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex( + D)) { + if (Optional Index2 = StructuralEquivalenceContext:: findUntaggedStructOrUnionIndex(FoundRecord)) { if (*Index1 != *Index2) continue; @@ -3216,7 +1834,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - + if (FunctionDecl *FoundFunction = dyn_cast(FoundDecls[I])) { if (FoundFunction->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { @@ -3225,14 +1843,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // FIXME: Actually try to merge the body and other attributes. return Importer.Imported(D, FoundFunction); } - + // FIXME: Check for overloading more carefully, e.g., by boosting // Sema::IsOverload out to the AST library. - + // Function overloading is okay in C++. if (Importer.getToContext().getLangOpts().CPlusPlus) continue; - + // Complain about inconsistent function types. Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) << Name << D->getType() << FoundFunction->getType(); @@ -3241,10 +1859,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { << FoundFunction->getType(); } } - + ConflictingDecls.push_back(FoundDecls[I]); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, IDNS, ConflictingDecls.data(), @@ -3449,12 +2067,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); return FoundField; } - + Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) @@ -3514,7 +2132,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), !Name.isEmpty())) { Importer.Imported(D, FoundField); @@ -3638,12 +2256,12 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { if (ToD) return ToD; - // Determine whether we've already imported this ivar + // Determine whether we've already imported this ivar SmallVector FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCIvarDecl *FoundIvar = dyn_cast(FoundDecls[I])) { - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { Importer.Imported(D, FoundIvar); return FoundIvar; @@ -3702,12 +2320,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - + if (VarDecl *FoundVar = dyn_cast(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. if (FoundVar->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; break; @@ -3931,12 +2549,12 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { } // Check parameter types. - for (ObjCMethodDecl::param_iterator P = D->param_begin(), + for (ObjCMethodDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(), FoundP = FoundMethod->param_begin(); P != PEnd; ++P, ++FoundP) { - if (!Importer.IsStructurallyEquivalent((*P)->getType(), + if (!Importer.IsStructurallyEquivalent((*P)->getType(), (*FoundP)->getType())) { - Importer.FromDiag((*P)->getLocation(), + Importer.FromDiag((*P)->getLocation(), diag::err_odr_objc_method_param_type_inconsistent) << D->isInstanceMethod() << Name << (*P)->getType() << (*FoundP)->getType(); @@ -4542,7 +3160,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { if (ObjCPropertyDecl *FoundProp = dyn_cast(FoundDecls[I])) { // Check property types. - if (!Importer.IsStructurallyEquivalent(D->getType(), + if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) << Name << D->getType() << FoundProp->getType(); @@ -7597,7 +6215,7 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, = ImportedTypes.find(From.getTypePtr()); if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) return true; - + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, false, Complain); return Ctx.IsStructurallyEquivalent(From, To); diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp new file mode 100644 index 0000000..8fe72ea --- /dev/null +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -0,0 +1,1318 @@ +//===--- ASTStructuralEquivalence.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 implement StructuralEquivalenceContext class and helper functions +// for layout matching. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTStructuralEquivalence.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/SourceManager.h" + +namespace { + +using namespace clang; + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2); + +/// Determine structural equivalence of two expressions. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Expr *E1, Expr *E2) { + if (!E1 || !E2) + return E1 == E2; + + // FIXME: Actually perform a structural comparison! + return true; +} + +/// Determine whether two identifiers are equivalent. +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2) { + if (!Name1 || !Name2) + return Name1 == Name2; + + return Name1->getName() == Name2->getName(); +} + +/// Determine whether two nested-name-specifiers are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2) { + if (NNS1->getKind() != NNS2->getKind()) + return false; + + NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), + *Prefix2 = NNS2->getPrefix(); + if ((bool)Prefix1 != (bool)Prefix2) + return false; + + if (Prefix1) + if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) + return false; + + switch (NNS1->getKind()) { + case NestedNameSpecifier::Identifier: + return IsStructurallyEquivalent(NNS1->getAsIdentifier(), + NNS2->getAsIdentifier()); + case NestedNameSpecifier::Namespace: + return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), + NNS2->getAsNamespace()); + case NestedNameSpecifier::NamespaceAlias: + return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(), + NNS2->getAsNamespaceAlias()); + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), + QualType(NNS2->getAsType(), 0)); + case NestedNameSpecifier::Global: + return true; + case NestedNameSpecifier::Super: + return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), + NNS2->getAsRecordDecl()); + } + return false; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateName &N1, + const TemplateName &N2) { + if (N1.getKind() != N2.getKind()) + return false; + switch (N1.getKind()) { + case TemplateName::Template: + return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(), + N2.getAsTemplateDecl()); + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(), + *OS2 = N2.getAsOverloadedTemplate(); + OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(), + E1 = OS1->end(), E2 = OS2->end(); + for (; I1 != E1 && I2 != E2; ++I1, ++I2) + if (!IsStructurallyEquivalent(Context, *I1, *I2)) + return false; + return I1 == E1 && I2 == E2; + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), + *QN2 = N2.getAsQualifiedTemplateName(); + return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) && + IsStructurallyEquivalent(Context, QN1->getQualifier(), + QN2->getQualifier()); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DN1 = N1.getAsDependentTemplateName(), + *DN2 = N2.getAsDependentTemplateName(); + if (!IsStructurallyEquivalent(Context, DN1->getQualifier(), + DN2->getQualifier())) + return false; + if (DN1->isIdentifier() && DN2->isIdentifier()) + return IsStructurallyEquivalent(DN1->getIdentifier(), + DN2->getIdentifier()); + else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator()) + return DN1->getOperator() == DN2->getOperator(); + return false; + } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(), + *TS2 = N2.getAsSubstTemplateTemplateParm(); + return IsStructurallyEquivalent(Context, TS1->getParameter(), + TS2->getParameter()) && + IsStructurallyEquivalent(Context, TS1->getReplacement(), + TS2->getReplacement()); + } + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage + *P1 = N1.getAsSubstTemplateTemplateParmPack(), + *P2 = N2.getAsSubstTemplateTemplateParmPack(); + return IsStructurallyEquivalent(Context, P1->getArgumentPack(), + P2->getArgumentPack()) && + IsStructurallyEquivalent(Context, P1->getParameterPack(), + P2->getParameterPack()); + } + } + return false; +} + +/// Determine whether two template arguments are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2) { + if (Arg1.getKind() != Arg2.getKind()) + return false; + + switch (Arg1.getKind()) { + case TemplateArgument::Null: + return true; + + case TemplateArgument::Type: + return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + + case TemplateArgument::Integral: + if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + Arg2.getIntegralType())) + return false; + + return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), + Arg2.getAsIntegral()); + + case TemplateArgument::Declaration: + return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + + case TemplateArgument::NullPtr: + return true; // FIXME: Is this correct? + + case TemplateArgument::Template: + return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(), + Arg2.getAsTemplate()); + + case TemplateArgument::TemplateExpansion: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplateOrTemplatePattern(), + Arg2.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return IsStructurallyEquivalent(Context, Arg1.getAsExpr(), + Arg2.getAsExpr()); + + case TemplateArgument::Pack: + if (Arg1.pack_size() != Arg2.pack_size()) + return false; + + for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I], + Arg2.pack_begin()[I])) + return false; + + return true; + } + + llvm_unreachable("Invalid template argument kind"); +} + +/// Determine structural equivalence for the common part of array +/// types. +static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, + const ArrayType *Array1, + const ArrayType *Array2) { + if (!IsStructurallyEquivalent(Context, Array1->getElementType(), + Array2->getElementType())) + return false; + if (Array1->getSizeModifier() != Array2->getSizeModifier()) + return false; + if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) + return false; + + return true; +} + +/// Determine structural equivalence of two types. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return T1.isNull() && T2.isNull(); + + if (!Context.StrictTypeSpelling) { + // We aren't being strict about token-to-token equivalence of types, + // so map down to the canonical type. + T1 = Context.FromCtx.getCanonicalType(T1); + T2 = Context.ToCtx.getCanonicalType(T2); + } + + if (T1.getQualifiers() != T2.getQualifiers()) + return false; + + Type::TypeClass TC = T1->getTypeClass(); + + if (T1->getTypeClass() != T2->getTypeClass()) { + // Compare function types with prototypes vs. without prototypes as if + // both did not have prototypes. + if (T1->getTypeClass() == Type::FunctionProto && + T2->getTypeClass() == Type::FunctionNoProto) + TC = Type::FunctionNoProto; + else if (T1->getTypeClass() == Type::FunctionNoProto && + T2->getTypeClass() == Type::FunctionProto) + TC = Type::FunctionNoProto; + else + return false; + } + + switch (TC) { + case Type::Builtin: + // FIXME: Deal with Char_S/Char_U. + if (cast(T1)->getKind() != cast(T2)->getKind()) + return false; + break; + + case Type::Complex: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getElementType(), + cast(T2)->getElementType())) + return false; + break; + + case Type::Adjusted: + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getOriginalType(), + cast(T2)->getOriginalType())) + return false; + break; + + case Type::Pointer: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getPointeeType(), + cast(T2)->getPointeeType())) + return false; + break; + + case Type::BlockPointer: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getPointeeType(), + cast(T2)->getPointeeType())) + return false; + break; + + case Type::LValueReference: + case Type::RValueReference: { + const ReferenceType *Ref1 = cast(T1); + const ReferenceType *Ref2 = cast(T2); + if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) + return false; + if (Ref1->isInnerRef() != Ref2->isInnerRef()) + return false; + if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(), + Ref2->getPointeeTypeAsWritten())) + return false; + break; + } + + case Type::MemberPointer: { + const MemberPointerType *MemPtr1 = cast(T1); + const MemberPointerType *MemPtr2 = cast(T2); + if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(), + MemPtr2->getPointeeType())) + return false; + if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0), + QualType(MemPtr2->getClass(), 0))) + return false; + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *Array1 = cast(T1); + const ConstantArrayType *Array2 = cast(T2); + if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + break; + } + + case Type::IncompleteArray: + if (!IsArrayStructurallyEquivalent(Context, cast(T1), + cast(T2))) + return false; + break; + + case Type::VariableArray: { + const VariableArrayType *Array1 = cast(T1); + const VariableArrayType *Array2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), + Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *Array1 = cast(T1); + const DependentSizedArrayType *Array2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), + Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *Vec1 = + cast(T1); + const DependentSizedExtVectorType *Vec2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(), + Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::Vector: + case Type::ExtVector: { + const VectorType *Vec1 = cast(T1); + const VectorType *Vec2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), + Vec2->getElementType())) + return false; + if (Vec1->getNumElements() != Vec2->getNumElements()) + return false; + if (Vec1->getVectorKind() != Vec2->getVectorKind()) + return false; + break; + } + + case Type::FunctionProto: { + const FunctionProtoType *Proto1 = cast(T1); + const FunctionProtoType *Proto2 = cast(T2); + if (Proto1->getNumParams() != Proto2->getNumParams()) + return false; + for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I), + Proto2->getParamType(I))) + return false; + } + if (Proto1->isVariadic() != Proto2->isVariadic()) + return false; + if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) + return false; + if (Proto1->getExceptionSpecType() == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { + if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) + return false; + } + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + return false; + + // Fall through to check the bits common with FunctionNoProtoType. + } + + case Type::FunctionNoProto: { + const FunctionType *Function1 = cast(T1); + const FunctionType *Function2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), + Function2->getReturnType())) + return false; + if (Function1->getExtInfo() != Function2->getExtInfo()) + return false; + break; + } + + case Type::UnresolvedUsing: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getDecl(), + cast(T2)->getDecl())) + return false; + + break; + + case Type::Attributed: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getModifiedType(), + cast(T2)->getModifiedType())) + return false; + if (!IsStructurallyEquivalent( + Context, cast(T1)->getEquivalentType(), + cast(T2)->getEquivalentType())) + return false; + break; + + case Type::Paren: + if (!IsStructurallyEquivalent(Context, cast(T1)->getInnerType(), + cast(T2)->getInnerType())) + return false; + break; + + case Type::Typedef: + if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), + cast(T2)->getDecl())) + return false; + break; + + case Type::TypeOfExpr: + if (!IsStructurallyEquivalent( + Context, cast(T1)->getUnderlyingExpr(), + cast(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::TypeOf: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getUnderlyingType(), + cast(T2)->getUnderlyingType())) + return false; + break; + + case Type::UnaryTransform: + if (!IsStructurallyEquivalent( + Context, cast(T1)->getUnderlyingType(), + cast(T1)->getUnderlyingType())) + return false; + break; + + case Type::Decltype: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getUnderlyingExpr(), + cast(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::Auto: + if (!IsStructurallyEquivalent(Context, cast(T1)->getDeducedType(), + cast(T2)->getDeducedType())) + return false; + break; + + case Type::DeducedTemplateSpecialization: { + auto *DT1 = cast(T1); + auto *DT2 = cast(T2); + if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(), + DT2->getTemplateName())) + return false; + if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(), + DT2->getDeducedType())) + return false; + break; + } + + case Type::Record: + case Type::Enum: + if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), + cast(T2)->getDecl())) + return false; + break; + + case Type::TemplateTypeParm: { + const TemplateTypeParmType *Parm1 = cast(T1); + const TemplateTypeParmType *Parm2 = cast(T2); + if (Parm1->getDepth() != Parm2->getDepth()) + return false; + if (Parm1->getIndex() != Parm2->getIndex()) + return false; + if (Parm1->isParameterPack() != Parm2->isParameterPack()) + return false; + + // Names of template type parameters are never significant. + break; + } + + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *Subst1 = + cast(T1); + const SubstTemplateTypeParmType *Subst2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(), + Subst2->getReplacementType())) + return false; + break; + } + + case Type::SubstTemplateTypeParmPack: { + const SubstTemplateTypeParmPackType *Subst1 = + cast(T1); + const SubstTemplateTypeParmPackType *Subst2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(), + Subst2->getArgumentPack())) + return false; + break; + } + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec1 = + cast(T1); + const TemplateSpecializationType *Spec2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), + Spec2->getTemplateName())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), + Spec2->getArg(I))) + return false; + } + break; + } + + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast(T1); + const ElaboratedType *Elab2 = cast(T2); + // CHECKME: what if a keyword is ETK_None or ETK_typename ? + if (Elab1->getKeyword() != Elab2->getKeyword()) + return false; + if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(), + Elab2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(), + Elab2->getNamedType())) + return false; + break; + } + + case Type::InjectedClassName: { + const InjectedClassNameType *Inj1 = cast(T1); + const InjectedClassNameType *Inj2 = cast(T2); + if (!IsStructurallyEquivalent(Context, + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) + return false; + break; + } + + case Type::DependentName: { + const DependentNameType *Typename1 = cast(T1); + const DependentNameType *Typename2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(), + Typename2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Typename1->getIdentifier(), + Typename2->getIdentifier())) + return false; + + break; + } + + case Type::DependentTemplateSpecialization: { + const DependentTemplateSpecializationType *Spec1 = + cast(T1); + const DependentTemplateSpecializationType *Spec2 = + cast(T2); + if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(), + Spec2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Spec1->getIdentifier(), + Spec2->getIdentifier())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), + Spec2->getArg(I))) + return false; + } + break; + } + + case Type::PackExpansion: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getPattern(), + cast(T2)->getPattern())) + return false; + break; + + case Type::ObjCInterface: { + const ObjCInterfaceType *Iface1 = cast(T1); + const ObjCInterfaceType *Iface2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Iface1->getDecl(), + Iface2->getDecl())) + return false; + break; + } + + case Type::ObjCTypeParam: { + const ObjCTypeParamType *Obj1 = cast(T1); + const ObjCTypeParamType *Obj2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl())) + return false; + + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I), + Obj2->getProtocol(I))) + return false; + } + break; + } + case Type::ObjCObject: { + const ObjCObjectType *Obj1 = cast(T1); + const ObjCObjectType *Obj2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(), + Obj2->getBaseType())) + return false; + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I), + Obj2->getProtocol(I))) + return false; + } + break; + } + + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *Ptr1 = cast(T1); + const ObjCObjectPointerType *Ptr2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(), + Ptr2->getPointeeType())) + return false; + break; + } + + case Type::Atomic: { + if (!IsStructurallyEquivalent(Context, cast(T1)->getValueType(), + cast(T2)->getValueType())) + return false; + break; + } + + case Type::Pipe: { + if (!IsStructurallyEquivalent(Context, cast(T1)->getElementType(), + cast(T2)->getElementType())) + return false; + break; + } + + } // end switch + + return true; +} + +/// Determine structural equivalence of two fields. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FieldDecl *Field1, FieldDecl *Field2) { + RecordDecl *Owner2 = cast(Field2->getDeclContext()); + + // For anonymous structs/unions, match up the anonymous struct/union type + // declarations directly, so that we don't go off searching for anonymous + // types + if (Field1->isAnonymousStructOrUnion() && + Field2->isAnonymousStructOrUnion()) { + RecordDecl *D1 = Field1->getType()->castAs()->getDecl(); + RecordDecl *D2 = Field2->getType()->castAs()->getDecl(); + return IsStructurallyEquivalent(Context, D1, D2); + } + + // Check for equivalent field names. + IdentifierInfo *Name1 = Field1->getIdentifier(); + IdentifierInfo *Name2 = Field2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) + return false; + + if (!IsStructurallyEquivalent(Context, Field1->getType(), + Field2->getType())) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + } + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + if (Field1->isBitField()) { + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Field1->getBitWidthValue(Context.FromCtx); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Field2->getBitWidthValue(Context.ToCtx); + Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx); + unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx); + + if (Bits1 != Bits2) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() << Bits2; + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() << Bits1; + } + return false; + } + } + + return true; +} + +/// Determine structural equivalence of two records. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + RecordDecl *D1, RecordDecl *D2) { + if (D1->isUnion() != D2->isUnion()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + } + return false; + } + + if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (Optional Index1 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) { + if (Optional Index2 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex( + D2)) { + if (*Index1 != *Index2) + return false; + } + } + } + + // If both declarations are class template specializations, we know + // the ODR applies, so check the template and template arguments. + ClassTemplateSpecializationDecl *Spec1 = + dyn_cast(D1); + ClassTemplateSpecializationDecl *Spec2 = + dyn_cast(D2); + if (Spec1 && Spec2) { + // Check that the specialized templates are the same. + if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), + Spec2->getSpecializedTemplate())) + return false; + + // Check that the template arguments are the same. + if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) + return false; + + for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I), + Spec2->getTemplateArgs().get(I))) + return false; + } + // If one is a class template specialization and the other is not, these + // structures are different. + else if (Spec1 || Spec2) + return false; + + // Compare the definitions of these two records. If either or both are + // incomplete, we assume that they are equivalent. + D1 = D1->getDefinition(); + D2 = D2->getDefinition(); + if (!D1 || !D2) + return true; + + if (CXXRecordDecl *D1CXX = dyn_cast(D1)) { + if (CXXRecordDecl *D2CXX = dyn_cast(D2)) { + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + } + return false; + } + + // Check the base classes. + for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; ++Base1, ++Base2) { + if (!IsStructurallyEquivalent(Context, Base1->getType(), + Base2->getType())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_base) + << Base2->getType() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() << Base1->getSourceRange(); + } + return false; + } + + // Check virtual vs. non-virtual inheritance mismatch. + if (Base1->isVirtual() != Base2->isVirtual()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->isVirtual() << Base1->getSourceRange(); + } + return false; + } + } + } else if (D1CXX->getNumBases() > 0) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + } + return false; + } + } + + // Check the fields for consistency. + RecordDecl::field_iterator Field2 = D2->field_begin(), + Field2End = D2->field_end(); + for (RecordDecl::field_iterator Field1 = D1->field_begin(), + Field1End = D1->field_end(); + Field1 != Field1End; ++Field1, ++Field2) { + if (Field2 == Field2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + } + return false; + } + + if (!IsStructurallyEquivalent(Context, *Field1, *Field2)) + return false; + } + + if (Field2 != Field2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + } + return false; + } + + return true; +} + +/// Determine structural equivalence of two enums. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumDecl *D1, EnumDecl *D2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { + if (EC2 == EC2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + } + return false; + } + + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); + if (!llvm::APSInt::isSameValue(Val1, Val2) || + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << EC1->getInitVal().toString(10); + } + return false; + } + } + + if (EC2 != EC2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << EC2->getInitVal().toString(10); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateParameterList *Params1, + TemplateParameterList *Params2) { + if (Params1->size() != Params2->size()) { + if (Context.Complain) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + } + return false; + } + + for (unsigned I = 0, N = Params1->size(); I != N; ++I) { + if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { + if (Context.Complain) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + } + return false; + } + + if (!Context.IsStructurallyEquivalent(Params1->getParam(I), + Params2->getParam(I))) { + + return false; + } + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTypeParmDecl *D1, + TemplateTypeParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NonTypeTemplateParmDecl *D1, + NonTypeTemplateParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + // Check types. + if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTemplateParmDecl *D1, + TemplateTemplateParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + // Check template parameter lists. + return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ClassTemplateDecl *D1, + ClassTemplateDecl *D2) { + // Check template parameters. + if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters())) + return false; + + // Check the templated declaration. + return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), + D2->getTemplatedDecl()); +} + +/// Determine structural equivalence of two declarations. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2) { + // FIXME: Check for known structural equivalences via a callback of some sort. + + // Check whether we already know that these two declarations are not + // structurally equivalent. + if (Context.NonEquivalentDecls.count( + std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()))) + return false; + + // Determine whether we've already produced a tentative equivalence for D1. + Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; + if (EquivToD1) + return EquivToD1 == D2->getCanonicalDecl(); + + // Produce a tentative equivalence D1 <-> D2, which will be checked later. + EquivToD1 = D2->getCanonicalDecl(); + Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); + return true; +} +} // namespace + +namespace clang { + +DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc, + unsigned DiagID) { + assert(Complain && "Not allowed to complain"); + if (LastDiagFromC2) + FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics()); + LastDiagFromC2 = false; + return FromCtx.getDiagnostics().Report(Loc, DiagID); +} + +DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc, + unsigned DiagID) { + assert(Complain && "Not allowed to complain"); + if (!LastDiagFromC2) + ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics()); + LastDiagFromC2 = true; + return ToCtx.getDiagnostics().Report(Loc, DiagID); +} + +Optional +StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { + ASTContext &Context = Anon->getASTContext(); + QualType AnonTy = Context.getRecordType(Anon); + + RecordDecl *Owner = dyn_cast(Anon->getDeclContext()); + if (!Owner) + return None; + + unsigned Index = 0; + for (const auto *D : Owner->noload_decls()) { + const auto *F = dyn_cast(D); + if (!F) + continue; + + if (F->isAnonymousStructOrUnion()) { + if (Context.hasSameType(F->getType(), AnonTy)) + break; + ++Index; + continue; + } + + // If the field looks like this: + // struct { ... } A; + QualType FieldType = F->getType(); + if (const auto *RecType = dyn_cast(FieldType)) { + const RecordDecl *RecDecl = RecType->getDecl(); + if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { + if (Context.hasSameType(FieldType, AnonTy)) + break; + ++Index; + continue; + } + } + } + + return Index; +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, + Decl *D2) { + if (!::IsStructurallyEquivalent(*this, D1, D2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, + QualType T2) { + if (!::IsStructurallyEquivalent(*this, T1, T2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::Finish() { + while (!DeclsToCheck.empty()) { + // Check the next declaration. + Decl *D1 = DeclsToCheck.front(); + DeclsToCheck.pop_front(); + + Decl *D2 = TentativeEquivalences[D1]; + assert(D2 && "Unrecorded tentative equivalence?"); + + bool Equivalent = true; + + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (RecordDecl *Record1 = dyn_cast(D1)) { + if (RecordDecl *Record2 = dyn_cast(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefNameForAnonDecl()) + Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefNameForAnonDecl()) + Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + Equivalent = false; + } else { + // Record/non-record mismatch. + Equivalent = false; + } + } else if (EnumDecl *Enum1 = dyn_cast(D1)) { + if (EnumDecl *Enum2 = dyn_cast(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefNameForAnonDecl()) + Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefNameForAnonDecl()) + Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + Equivalent = false; + } else { + // Enum/non-enum mismatch + Equivalent = false; + } + } else if (TypedefNameDecl *Typedef1 = dyn_cast(D1)) { + if (TypedefNameDecl *Typedef2 = dyn_cast(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + Equivalent = false; + } else { + // Typedef/non-typedef mismatch. + Equivalent = false; + } + } else if (ClassTemplateDecl *ClassTemplate1 = + dyn_cast(D1)) { + if (ClassTemplateDecl *ClassTemplate2 = dyn_cast(D2)) { + if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), + ClassTemplate2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (TemplateTypeParmDecl *TTP1 = + dyn_cast(D1)) { + if (TemplateTypeParmDecl *TTP2 = dyn_cast(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (NonTypeTemplateParmDecl *NTTP1 = + dyn_cast(D1)) { + if (NonTypeTemplateParmDecl *NTTP2 = + dyn_cast(D2)) { + if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (TemplateTemplateParmDecl *TTP1 = + dyn_cast(D1)) { + if (TemplateTemplateParmDecl *TTP2 = + dyn_cast(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } + + if (!Equivalent) { + // Note that these two declarations are not equivalent (and we already + // know about it). + NonEquivalentDecls.insert( + std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())); + return true; + } + // FIXME: Check other declaration kinds! + } + + return false; +} +} // namespace clang diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 13bf352..bbebf75 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangAST ASTDiagnostic.cpp ASTDumper.cpp ASTImporter.cpp + ASTStructuralEquivalence.cpp ASTTypeTraits.cpp AttrImpl.cpp CXXInheritance.cpp diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index cda70c5..5c2c9cb 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -415,6 +415,19 @@ const Attr *Decl::getDefiningAttr() const { return nullptr; } +StringRef getRealizedPlatform(const AvailabilityAttr *A, + const ASTContext &Context) { + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef RealizedPlatform = A->getPlatform()->getName(); + if (!Context.getLangOpts().AppExt) + return RealizedPlatform; + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + return RealizedPlatform.slice(0, suffix); + return RealizedPlatform; +} + /// \brief Determine the availability of the given declaration based on /// the target platform. /// @@ -434,20 +447,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (EnclosingVersion.empty()) return AR_Available; - // Check if this is an App Extension "platform", and if so chop off - // the suffix for matching with the actual platform. StringRef ActualPlatform = A->getPlatform()->getName(); - StringRef RealizedPlatform = ActualPlatform; - if (Context.getLangOpts().AppExt) { - size_t suffix = RealizedPlatform.rfind("_app_extension"); - if (suffix != StringRef::npos) - RealizedPlatform = RealizedPlatform.slice(0, suffix); - } - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); // Match the platform name. - if (RealizedPlatform != TargetPlatform) + if (getRealizedPlatform(A, Context) != TargetPlatform) return AR_Available; StringRef PrettyPlatformName @@ -567,6 +571,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message, return Result; } +VersionTuple Decl::getVersionIntroduced() const { + const ASTContext &Context = getASTContext(); + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + for (const auto *A : attrs()) { + if (const auto *Availability = dyn_cast(A)) { + if (getRealizedPlatform(Availability, Context) != TargetPlatform) + continue; + if (!Availability->getIntroduced().empty()) + return Availability->getIntroduced(); + } + } + return VersionTuple(); +} + bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 2fafa48..4d08053 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -148,7 +148,8 @@ namespace { static unsigned findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base, ArrayRef Path, - uint64_t &ArraySize, QualType &Type, bool &IsArray) { + uint64_t &ArraySize, QualType &Type, bool &IsArray, + bool &IsUnsizedArray) { // This only accepts LValueBases from APValues, and APValues don't support // arrays that lack size info. assert(!isBaseAnAllocSizeCall(Base) && @@ -157,28 +158,34 @@ namespace { Type = getType(Base); for (unsigned I = 0, N = Path.size(); I != N; ++I) { - if (Type->isArrayType()) { - const ConstantArrayType *CAT = - cast(Ctx.getAsArrayType(Type)); - Type = CAT->getElementType(); - ArraySize = CAT->getSize().getZExtValue(); + if (auto AT = Ctx.getAsArrayType(Type)) { MostDerivedLength = I + 1; IsArray = true; + if (auto CAT = Ctx.getAsConstantArrayType(Type)) + ArraySize = CAT->getSize().getZExtValue(); + else { + ArraySize = 0; + IsUnsizedArray = true; + } + Type = AT->getElementType(); } else if (Type->isAnyComplexType()) { const ComplexType *CT = Type->castAs(); Type = CT->getElementType(); ArraySize = 2; MostDerivedLength = I + 1; IsArray = true; + IsUnsizedArray = false; } else if (const FieldDecl *FD = getAsField(Path[I])) { Type = FD->getType(); ArraySize = 0; MostDerivedLength = I + 1; IsArray = false; + IsUnsizedArray = false; } else { // Path[I] describes a base class. ArraySize = 0; IsArray = false; + IsUnsizedArray = false; } } return MostDerivedLength; @@ -200,8 +207,9 @@ namespace { /// Is this a pointer one past the end of an object? unsigned IsOnePastTheEnd : 1; - /// Indicator of whether the first entry is an unsized array. - unsigned FirstEntryIsAnUnsizedArray : 1; + /// Indicator of whether the most-derived object is an unsized array (e.g. + /// of unknown bound). + unsigned MostDerivedIsAnUnsizedArray : 1; /// Indicator of whether the most-derived object is an array element. unsigned MostDerivedIsArrayElement : 1; @@ -231,25 +239,28 @@ namespace { explicit SubobjectDesignator(QualType T) : Invalid(false), IsOnePastTheEnd(false), - FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), + MostDerivedIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), MostDerivedPathLength(0), MostDerivedArraySize(0), MostDerivedType(T) {} SubobjectDesignator(ASTContext &Ctx, const APValue &V) : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false), - FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), + MostDerivedIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), MostDerivedPathLength(0), MostDerivedArraySize(0) { assert(V.isLValue() && "Non-LValue used to make an LValue designator?"); if (!Invalid) { IsOnePastTheEnd = V.isLValueOnePastTheEnd(); ArrayRef VEntries = V.getLValuePath(); Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); - if (V.getLValueBase()) { - bool IsArray = false; + if (auto Base = V.getLValueBase()) { + if (auto Decl = Base.dyn_cast()) + Base = cast(Decl->getMostRecentDecl()); + bool IsArray = false, IsUnsizedArray = false; MostDerivedPathLength = findMostDerivedSubobject( - Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize, - MostDerivedType, IsArray); - MostDerivedIsArrayElement = IsArray; + Ctx, Base, V.getLValuePath(), MostDerivedArraySize, + MostDerivedType, IsArray, IsUnsizedArray); + MostDerivedIsArrayElement = IsArray; + MostDerivedIsAnUnsizedArray = IsUnsizedArray; } } } @@ -263,7 +274,7 @@ namespace { /// known bound. bool isMostDerivedAnUnsizedArray() const { assert(!Invalid && "Calling this makes no sense on invalid designators"); - return Entries.size() == 1 && FirstEntryIsAnUnsizedArray; + return MostDerivedIsAnUnsizedArray; } /// Determine what the most derived array's size is. Results in an assertion @@ -303,6 +314,7 @@ namespace { // This is a most-derived object. MostDerivedType = CAT->getElementType(); MostDerivedIsArrayElement = true; + MostDerivedIsAnUnsizedArray = false; MostDerivedArraySize = CAT->getSize().getZExtValue(); MostDerivedPathLength = Entries.size(); } @@ -315,6 +327,7 @@ namespace { MostDerivedType = ElemTy; MostDerivedIsArrayElement = true; + MostDerivedIsAnUnsizedArray = true; // The value in MostDerivedArraySize is undefined in this case. So, set it // to an arbitrary value that's likely to loudly break things if it's // used. @@ -333,6 +346,7 @@ namespace { if (const FieldDecl *FD = dyn_cast(D)) { MostDerivedType = FD->getType(); MostDerivedIsArrayElement = false; + MostDerivedIsAnUnsizedArray = false; MostDerivedArraySize = 0; MostDerivedPathLength = Entries.size(); } @@ -347,53 +361,14 @@ namespace { // is unlikely to matter. MostDerivedType = EltTy; MostDerivedIsArrayElement = true; + MostDerivedIsAnUnsizedArray = false; MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); /// Add N to the address of this subobject. - void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { - if (Invalid || !N) return; - uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); - if (isMostDerivedAnUnsizedArray()) { - // Can't verify -- trust that the user is doing the right thing (or if - // not, trust that the caller will catch the bad behavior). - // FIXME: Should we reject if this overflows, at least? - Entries.back().ArrayIndex += TruncatedN; - return; - } - - // [expr.add]p4: For the purposes of these operators, a pointer to a - // nonarray object behaves the same as a pointer to the first element of - // an array of length one with the type of the object as its element type. - bool IsArray = MostDerivedPathLength == Entries.size() && - MostDerivedIsArrayElement; - uint64_t ArrayIndex = - IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; - uint64_t ArraySize = - IsArray ? getMostDerivedArraySize() : (uint64_t)1; - - if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { - // Calculate the actual index in a wide enough type, so we can include - // it in the note. - N = N.extend(std::max(N.getBitWidth() + 1, 65)); - (llvm::APInt&)N += ArrayIndex; - assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); - diagnosePointerArithmetic(Info, E, N); - setInvalid(); - return; - } - - ArrayIndex += TruncatedN; - assert(ArrayIndex <= ArraySize && - "bounds check succeeded for out-of-bounds index"); - - if (IsArray) - Entries.back().ArrayIndex = ArrayIndex; - else - IsOnePastTheEnd = (ArrayIndex != 0); - } + void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N); }; /// A stack frame in the constexpr call stack. @@ -495,7 +470,7 @@ namespace { // FIXME: Force the precision of the source value down so we don't // print digits which are usually useless (we don't really care here if // we truncate a digit by accident in edge cases). Ideally, - // APFloat::toString would automatically print the shortest + // APFloat::toString would automatically print the shortest // representation which rounds to the correct value, but it's a bit // tricky to implement. unsigned precision = @@ -720,7 +695,7 @@ namespace { private: OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId, unsigned ExtraNotes, bool IsCCEDiag) { - + 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, @@ -773,7 +748,7 @@ namespace { unsigned ExtraNotes = 0) { return Diag(Loc, DiagId, ExtraNotes, false); } - + OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { @@ -1086,6 +1061,53 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, setInvalid(); } +void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { + if (Invalid || !N) return; + + uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); + if (isMostDerivedAnUnsizedArray()) { + // If we're dealing with an array without constant bound, the expression is + // not a constant expression. + if (!Info.checkingPotentialConstantExpression()) + Info.CCEDiag(E, diag::note_constexpr_array_unknown_bound_arithmetic); + // Can't verify -- trust that the user is doing the right thing (or if + // not, trust that the caller will catch the bad behavior). + // FIXME: Should we reject if this overflows, at least? + Entries.back().ArrayIndex += TruncatedN; + return; + } + + // [expr.add]p4: For the purposes of these operators, a pointer to a + // nonarray object behaves the same as a pointer to the first element of + // an array of length one with the type of the object as its element type. + bool IsArray = MostDerivedPathLength == Entries.size() && + MostDerivedIsArrayElement; + uint64_t ArrayIndex = + IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; + uint64_t ArraySize = + IsArray ? getMostDerivedArraySize() : (uint64_t)1; + + if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { + // Calculate the actual index in a wide enough type, so we can include + // it in the note. + N = N.extend(std::max(N.getBitWidth() + 1, 65)); + (llvm::APInt&)N += ArrayIndex; + assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); + diagnosePointerArithmetic(Info, E, N); + setInvalid(); + return; + } + + ArrayIndex += TruncatedN; + assert(ArrayIndex <= ArraySize && + "bounds check succeeded for out-of-bounds index"); + + if (IsArray) + Entries.back().ArrayIndex = ArrayIndex; + else + IsOnePastTheEnd = (ArrayIndex != 0); +} + CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, APValue *Arguments) @@ -1214,8 +1236,6 @@ namespace { IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); - assert(!Designator.FirstEntryIsAnUnsizedArray && - "Unsized array with a valid base?"); V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); } @@ -1280,12 +1300,9 @@ namespace { if (checkSubobject(Info, E, isa(D) ? CSK_Field : CSK_Base)) Designator.addDeclUnchecked(D, Virtual); } - void addUnsizedArray(EvalInfo &Info, QualType ElemTy) { - assert(Designator.Entries.empty() && getType(Base)->isPointerType()); - assert(isBaseAnAllocSizeCall(Base) && - "Only alloc_size bases can have unsized arrays"); - Designator.FirstEntryIsAnUnsizedArray = true; - Designator.addUnsizedArrayUnchecked(ElemTy); + void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { + if (checkSubobject(Info, E, CSK_ArrayToPointer)) + Designator.addUnsizedArrayUnchecked(ElemTy); } void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { if (checkSubobject(Info, E, CSK_ArrayToPointer)) @@ -3016,6 +3033,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) return CompleteObject(); + + // The complete object can be an array of unknown bound, in which case we + // have to find the most recent declaration and adjust the type accordingly. + if (Info.Ctx.getAsIncompleteArrayType(BaseType)) { + QualType MostRecentType = + cast(D->getMostRecentDecl())->getType(); + if (Info.Ctx.getAsConstantArrayType(MostRecentType)) + BaseType = MostRecentType; + } } else { const Expr *Base = LVal.Base.dyn_cast(); @@ -4098,13 +4124,13 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, if (Info.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; - + // If this function is not constexpr because it is an inherited // non-constexpr constructor, diagnose that directly. auto *CD = dyn_cast(DiagDecl); if (CD && CD->isInheritingConstructor()) { auto *Inherited = CD->getInheritedConstructor().getConstructor(); - if (!Inherited->isConstexpr()) + if (!Inherited->isConstexpr()) DiagDecl = CD = Inherited; } @@ -4418,8 +4444,14 @@ private: bool HandleConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) { - if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) + if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) { CheckPotentialConstantConditional(E); + return false; + } + if (Info.noteFailure()) { + StmtVisitorTy::Visit(E->getTrueExpr()); + StmtVisitorTy::Visit(E->getFalseExpr()); + } return false; } @@ -4635,7 +4667,7 @@ public: return false; This = &ThisVal; Args = Args.slice(1); - } else if (MD && MD->isLambdaStaticInvoker()) { + } else if (MD && MD->isLambdaStaticInvoker()) { // Map the static invoker for the lambda back to the call operator. // Conveniently, we don't have to slice out the 'this' argument (as is // being done for the non-static case), since a static member function @@ -4670,7 +4702,7 @@ public: FD = LambdaCallOp; } - + } else return Error(E); @@ -5240,14 +5272,19 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (E->getBase()->getType()->isVectorType()) return Error(E); - if (!evaluatePointer(E->getBase(), Result)) - return false; + bool Success = true; + if (!evaluatePointer(E->getBase(), Result)) { + if (!Info.noteFailure()) + return false; + Success = false; + } APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return false; - return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index); + return Success && + HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index); } bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { @@ -5425,7 +5462,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base, Result.setInvalid(E); QualType Pointee = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, Pointee); + Result.addUnsizedArray(Info, E, Pointee); return true; } @@ -5470,8 +5507,11 @@ public: bool VisitUnaryAddrOf(const UnaryOperator *E); bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } - bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) - { return Success(E); } + bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { + if (Info.noteFailure()) + EvaluateIgnoredValue(Info, E->getSubExpr()); + return Error(E); + } bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); } bool VisitCallExpr(const CallExpr *E); @@ -5501,7 +5541,7 @@ public: // Update 'Result' to refer to the data member/field of the closure object // that represents the '*this' capture. if (!HandleLValueMember(Info, E, Result, - Info.CurrentCall->LambdaThisCaptureField)) + Info.CurrentCall->LambdaThisCaptureField)) return false; // If we captured '*this' by reference, replace the field with its referent. if (Info.CurrentCall->LambdaThisCaptureField->getType() @@ -5642,12 +5682,18 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Info, Result, SubExpr)) return false; } + // The result is a pointer to the first element of the array. if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(SubExpr->getType())) Result.addArray(Info, E, CAT); - else - Result.Designator.setInvalid(); + // If the array hasn't been given a bound yet, add it as an unsized one. + else { + auto AT = Info.Ctx.getAsArrayType(SubExpr->getType()); + assert(AT && "Array to pointer decay on non-array object?"); + Result.addUnsizedArray(Info, E, AT->getElementType()); + } + return true; case CK_FunctionToPointerDecay: @@ -5715,7 +5761,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { Result.setInvalid(E); QualType PointeeTy = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, PointeeTy); + Result.addUnsizedArray(Info, E, PointeeTy); return true; } @@ -6203,6 +6249,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; + if (Init->isValueDependent()) { + Success = false; + continue; + } // Temporarily override This, in case there's a CXXDefaultInitExpr in here. ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, @@ -6345,7 +6395,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { if (ClosureClass->isInvalidDecl()) return false; if (Info.checkingPotentialConstantExpression()) return true; - + const size_t NumFields = std::distance(ClosureClass->field_begin(), ClosureClass->field_end()); @@ -6364,7 +6414,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { assert(CaptureInitIt != E->capture_init_end()); // Get the initializer for this field Expr *const CurFieldInit = *CaptureInitIt++; - + // If there is no initializer, either this is a VLA or an error has // occurred. if (!CurFieldInit) @@ -6565,18 +6615,18 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // The number of initializers can be less than the number of // vector elements. For OpenCL, this can be due to nested vector - // initialization. For GCC compatibility, missing trailing elements + // initialization. For GCC compatibility, missing trailing elements // should be initialized with zeroes. unsigned CountInits = 0, CountElts = 0; while (CountElts < NumElements) { // Handle nested vector initialization. - if (CountInits < NumInits + if (CountInits < NumInits && E->getInit(CountInits)->getType()->isVectorType()) { APValue v; if (!EvaluateVector(E->getInit(CountInits), v, Info)) return Error(E); unsigned vlen = v.getVectorLength(); - for (unsigned j = 0; j < vlen; j++) + for (unsigned j = 0; j < vlen; j++) Elements.push_back(v.getVectorElt(j)); CountElts += vlen; } else if (EltTy->isIntegerType()) { @@ -6852,7 +6902,7 @@ public: } bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); @@ -6866,7 +6916,7 @@ public: } bool Success(uint64_t Value, const Expr *E, APValue &Result) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); return true; @@ -6942,7 +6992,7 @@ public: } return Success(Info.ArrayInitIndex, E); } - + // Note, GNU defines __null as an integer, not a pointer. bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); @@ -7306,10 +7356,8 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { unsigned I = 0; QualType BaseType = getType(Base); - if (LVal.Designator.FirstEntryIsAnUnsizedArray) { - assert(isBaseAnAllocSizeCall(Base) && - "Unsized array in non-alloc_size call?"); - // If this is an alloc_size base, we should ignore the initial array index + // If this is an alloc_size base, we should ignore the initial array index + if (isBaseAnAllocSizeCall(Base)) { ++I; BaseType = BaseType->castAs()->getPointeeType(); } @@ -8096,12 +8144,12 @@ bool DataRecursiveIntBinOpEvaluator:: Result = RHSResult.Val; return true; } - + if (E->isLogicalOp()) { bool lhsResult, rhsResult; bool LHSIsOK = HandleConversionToBool(LHSResult.Val, lhsResult); bool RHSIsOK = HandleConversionToBool(RHSResult.Val, rhsResult); - + if (LHSIsOK) { if (RHSIsOK) { if (E->getOpcode() == BO_LOr) @@ -8117,26 +8165,26 @@ bool DataRecursiveIntBinOpEvaluator:: return Success(rhsResult, E, Result); } } - + return false; } - + assert(E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); - + if (LHSResult.Failed || RHSResult.Failed) return false; - + const APValue &LHSVal = LHSResult.Val; const APValue &RHSVal = RHSResult.Val; - + // Handle cases like (unsigned long)&a + 4. if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) { Result = LHSVal; addOrSubLValueAsInteger(Result, RHSVal.getInt(), E->getOpcode() == BO_Sub); return true; } - + // Handle cases like 4 + (unsigned long)&a if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) { @@ -8144,7 +8192,7 @@ bool DataRecursiveIntBinOpEvaluator:: addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false); return true; } - + if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) { // Handle (intptr_t)&&A - (intptr_t)&&B. if (!LHSVal.getLValueOffset().isZero() || @@ -8183,7 +8231,7 @@ bool DataRecursiveIntBinOpEvaluator:: void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { Job &job = Queue.back(); - + switch (job.Kind) { case Job::AnyExprKind: { if (const BinaryOperator *Bop = dyn_cast(job.E)) { @@ -8193,12 +8241,12 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { return; } } - + EvaluateExpr(job.E, Result); Queue.pop_back(); return; } - + case Job::BinOpKind: { const BinaryOperator *Bop = cast(job.E); bool SuppressRHSDiags = false; @@ -8213,7 +8261,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { enqueue(Bop->getRHS()); return; } - + case Job::BinOpVisitedLHSKind: { const BinaryOperator *Bop = cast(job.E); EvalResult RHS; @@ -8223,7 +8271,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { return; } } - + llvm_unreachable("Invalid Job::Kind!"); } @@ -8735,7 +8783,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *BaseRT = CurrentType->getAs(); if (!BaseRT) return Error(OOE); - + // Add the offset to the base. Result += RL.getBaseClassOffset(cast(BaseRT->getDecl())); break; @@ -9913,7 +9961,8 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { } static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, - const ASTContext &Ctx, bool &IsConst) { + const ASTContext &Ctx, bool &IsConst, + bool IsCheckingForOverflow) { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. if (const IntegerLiteral *L = dyn_cast(Exp)) { @@ -9929,12 +9978,12 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, IsConst = false; return true; } - + // FIXME: Evaluating values of large array and record types can cause // performance problems. Only do so in C++11 for now. if (Exp->isRValue() && (Exp->getType()->isArrayType() || Exp->getType()->isRecordType()) && - !Ctx.getLangOpts().CPlusPlus11) { + !Ctx.getLangOpts().CPlusPlus11 && !IsCheckingForOverflow) { IsConst = false; return true; } @@ -9949,9 +9998,9 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, /// will be applied to the result. bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { bool IsConst; - if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) + if (FastEvaluateAsRValue(this, Result, Ctx, IsConst, false)) return IsConst; - + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); return ::EvaluateAsRValue(Info, this, Result.Val); } @@ -10074,7 +10123,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { bool IsConst; EvalResult EvalResult; - if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) { + if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst, true)) { EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow); (void)::EvaluateAsRValue(Info, this, EvalResult.Val); } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 5268a29..2be14ab 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -750,6 +750,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (Info.getRegParm()) OS << " __attribute__((regparm (" << Info.getRegParm() << ")))"; + if (Info.getNoCallerSavedRegs()) + OS << "__attribute__((no_caller_saved_registers))"; if (unsigned quals = T->getTypeQuals()) { OS << ' '; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index d7f1793..78b03b1 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -117,6 +117,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "6000"); Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__STDC_NO_THREADS__"); Builder.defineMacro("OBJC_NEW_PROPERTIES"); // AddressSanitizer doesn't play well with source fortification, which is on // by default on Darwin. diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 85788b4..0388380 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -35,7 +35,6 @@ #include "llvm/LTO/LTOBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 1a57b3e..791a57e 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -619,7 +619,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { // Block captures count as local values and have imprecise semantics. // They also can't be arrays, so need to worry about that. - if (dtorKind == QualType::DK_objc_strong_lifetime) { + // + // For const-qualified captures, emit clang.arc.use to ensure the captured + // object doesn't get released while we are still depending on its validity + // within the block. + if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong) + destroyer = CodeGenFunction::emitARCIntrinsicUse; + else if (dtorKind == QualType::DK_objc_strong_lifetime) { destroyer = CodeGenFunction::destroyARCStrongImprecise; } else { destroyer = CGF.getDestroyer(dtorKind); @@ -866,6 +872,12 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } else if (type->isReferenceType()) { Builder.CreateStore(src.getPointer(), blockField); + // If type is const-qualified, copy the value into the block field. + } else if (type.isConstQualified() && + type.getObjCLifetime() == Qualifiers::OCL_Strong) { + llvm::Value *value = Builder.CreateLoad(src, "captured"); + Builder.CreateStore(value, blockField); + // If this is an ARC __strong block-pointer variable, don't do a // block copy. // diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 2623525..a5c43fb 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -788,6 +788,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, FI->ChainCall = chainCall; FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); + FI->NoCallerSavedRegs = info.getNoCallerSavedRegs(); FI->Required = required; FI->HasRegParm = info.getHasRegParm(); FI->RegParm = info.getRegParm(); @@ -1816,6 +1817,8 @@ void CodeGenModule::ConstructAttributeList( RetAttrs.addAttribute(llvm::Attribute::NoAlias); if (TargetDecl->hasAttr()) RetAttrs.addAttribute(llvm::Attribute::NonNull); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute("no_caller_saved_registers"); HasOptnone = TargetDecl->hasAttr(); if (auto *AllocSize = TargetDecl->getAttr()) { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index dd32a44..3e54346 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -4034,11 +4034,9 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { if (I != NameSpaceCache.end()) return cast(I->second); - unsigned LineNo = getLineNumber(NSDecl->getLocation()); - llvm::DIFile *FileD = getOrCreateFile(NSDecl->getLocation()); llvm::DIScope *Context = getDeclContextDescriptor(NSDecl); - llvm::DINamespace *NS = DBuilder.createNameSpace( - Context, NSDecl->getName(), FileD, LineNo, NSDecl->isInline()); + llvm::DINamespace *NS = + DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline()); NameSpaceCache[NSDecl].reset(NS); return NS; } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index f61d60a..ff766e6 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -571,9 +571,10 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, FinishFunction(); } -void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, - const std::vector > - &DtorsAndObjects) { +void CodeGenFunction::GenerateCXXGlobalDtorsFunc( + llvm::Function *Fn, + const std::vector> + &DtorsAndObjects) { { auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(GlobalDecl(), getContext().VoidTy, Fn, diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index d0aacf6..863b438 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -4065,6 +4065,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { RValue RV = EmitAnyExpr(E->getRHS()); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + if (RV.isScalar()) + EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); EmitStoreThroughLValue(RV, LV); return LV; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 76e7df8..f4fbab3 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -2415,6 +2415,12 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, CGF.EmitARCDestroyWeak(addr); } +void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr, + QualType type) { + llvm::Value *value = CGF.Builder.CreateLoad(addr); + CGF.EmitARCIntrinsicUse(value); +} + namespace { struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup { llvm::Value *Token; diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 43b347c..70d24b7 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -886,7 +886,7 @@ protected: /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. - llvm::WeakVH ConstantStringClassRef; + llvm::WeakTrackingVH ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType = nullptr; diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index f738dd0..19b6cba 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -1675,7 +1675,7 @@ static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF, CodeGenFunction::JumpDest LoopExit) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); -}; +} void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { @@ -2093,7 +2093,7 @@ emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF, llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, SourceLocation()); return {LBVal, UBVal}; -}; +} static void emitDistributeParallelForDistributeInnerBoundParams( CodeGenFunction &CGF, const OMPExecutableDirective &S, @@ -2110,7 +2110,7 @@ static void emitDistributeParallelForDistributeInnerBoundParams( auto UBCast = CGF.Builder.CreateIntCast( CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false); CapturedVars.push_back(UBCast); -}; +} static void emitInnerParallelForWhenCombined(CodeGenFunction &CGF, diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index b864069..f57cbe8 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -944,7 +944,7 @@ std::unique_ptr CodeGenAction::loadModule(MemoryBufferRef MBRef) { void CodeGenAction::ExecuteAction() { // If this is an IR file, we have to treat it specially. - if (getCurrentFileKind() == IK_LLVM_IR) { + if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) { BackendAction BA = static_cast(Act); CompilerInstance &CI = getCompilerInstance(); std::unique_ptr OS = diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1ded824..b696408 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -3369,6 +3369,7 @@ public: static Destroyer destroyARCStrongImprecise; static Destroyer destroyARCStrongPrecise; static Destroyer destroyARCWeak; + static Destroyer emitARCIntrinsicUse; void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); llvm::Value *EmitObjCAutoreleasePoolPush(); @@ -3470,9 +3471,10 @@ public: /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global /// variables. - void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, - const std::vector > &DtorsAndObjects); + void GenerateCXXGlobalDtorsFunc( + llvm::Function *Fn, + const std::vector> + &DtorsAndObjects); void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 25d32f1..10f1673 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -369,9 +369,13 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags, if (MainFile.empty()) MainFile = ""; Diags.Report(diag::warn_profile_data_unprofiled) << MainFile; - } else - Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing - << Mismatched; + } else { + if (Mismatched > 0) + Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Mismatched; + + if (Missing > 0) + Diags.Report(diag::warn_profile_data_missing) << Visited << Missing; + } } void CodeGenModule::Release() { @@ -1150,7 +1154,7 @@ void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) { } static void emitUsed(CodeGenModule &CGM, StringRef Name, - std::vector &List) { + std::vector &List) { // Don't create llvm.used if there is no need. if (List.empty()) return; @@ -1324,13 +1328,10 @@ void CodeGenModule::EmitDeferred() { // Grab the list of decls to emit. If EmitGlobalDefinition schedules more // work, it will not interfere with this. - std::vector CurDeclsToEmit; + std::vector CurDeclsToEmit; CurDeclsToEmit.swap(DeferredDeclsToEmit); - for (DeferredGlobal &G : CurDeclsToEmit) { - GlobalDecl D = G.GD; - G.GV = nullptr; - + for (GlobalDecl &D : CurDeclsToEmit) { // 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 @@ -1707,13 +1708,13 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } StringRef MangledName = getMangledName(GD); - if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) { + if (GetGlobalValue(MangledName) != nullptr) { // The value has already been used and should therefore be emitted. - addDeferredDeclToEmit(GV, GD); + addDeferredDeclToEmit(GD); } else if (MustBeEmitted(Global)) { // The value must be emitted, but cannot be emitted eagerly. assert(!MayBeEmittedEagerly(Global)); - addDeferredDeclToEmit(/*GV=*/nullptr, GD); + addDeferredDeclToEmit(GD); } else { // Otherwise, remember that we saw a deferred decl with this name. The // first use of the mangled name will cause it to move into @@ -2040,7 +2041,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (D && isa(D) && getCXXABI().useThunkForDtorVariant(cast(D), GD.getDtorType())) - addDeferredDeclToEmit(F, GD); + addDeferredDeclToEmit(GD); // 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 @@ -2050,7 +2051,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( // Move the potentially referenced deferred decl to the // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we // don't need it anymore). - addDeferredDeclToEmit(F, DDI->second); + addDeferredDeclToEmit(DDI->second); DeferredDecls.erase(DDI); // Otherwise, there are cases we have to worry about where we're @@ -2070,7 +2071,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( FD = FD->getPreviousDecl()) { if (isa(FD->getLexicalDeclContext())) { if (FD->doesThisDeclarationHaveABody()) { - addDeferredDeclToEmit(F, GD.getWithDecl(FD)); + addDeferredDeclToEmit(GD.getWithDecl(FD)); break; } } @@ -2298,7 +2299,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). - addDeferredDeclToEmit(GV, DDI->second); + addDeferredDeclToEmit(DDI->second); DeferredDecls.erase(DDI); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c4985ba..e383378 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -315,14 +315,9 @@ private: /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. - struct DeferredGlobal { - DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {} - llvm::TrackingVH GV; - GlobalDecl GD; - }; - std::vector DeferredDeclsToEmit; - void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) { - DeferredDeclsToEmit.emplace_back(GV, GD); + std::vector DeferredDeclsToEmit; + void addDeferredDeclToEmit(GlobalDecl GD) { + DeferredDeclsToEmit.emplace_back(GD); } /// List of alias we have emitted. Used to make sure that what they point to @@ -349,8 +344,8 @@ private: /// List of global values which are required to be present in the object file; /// bitcast to i8*. This is used for forcing visibility of symbols which may /// otherwise be optimized out. - std::vector LLVMUsed; - std::vector LLVMCompilerUsed; + std::vector LLVMUsed; + std::vector LLVMCompilerUsed; /// Store the list of global constructors and their respective priorities to /// be emitted when the translation unit is complete. @@ -421,7 +416,7 @@ private: SmallVector PrioritizedCXXGlobalInits; /// Global destructor functions and arguments that need to run on termination. - std::vector > CXXGlobalDtors; + std::vector> CXXGlobalDtors; /// \brief The complete set of modules that has been imported. llvm::SetVector ImportedModules; @@ -438,7 +433,7 @@ private: /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. - llvm::WeakVH CFConstantStringClassRef; + llvm::WeakTrackingVH CFConstantStringClassRef; /// \brief The type used to describe the state of a fast enumeration in /// Objective-C's for..in loop. diff --git a/lib/CodeGen/MacroPPCallbacks.cpp b/lib/CodeGen/MacroPPCallbacks.cpp index acea5c1..6a31dfe 100644 --- a/lib/CodeGen/MacroPPCallbacks.cpp +++ b/lib/CodeGen/MacroPPCallbacks.cpp @@ -198,7 +198,8 @@ void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, } void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), diff --git a/lib/CodeGen/MacroPPCallbacks.h b/lib/CodeGen/MacroPPCallbacks.h index 06217f9..e117f96 100644 --- a/lib/CodeGen/MacroPPCallbacks.h +++ b/lib/CodeGen/MacroPPCallbacks.h @@ -110,8 +110,8 @@ public: /// Hook called whenever a macro \#undef is seen. /// /// MD is released immediately following this callback. - void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override; + void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, + const MacroDirective *Undef) override; }; } // end namespace clang diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 7a4d055..8b85680 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -49,7 +49,7 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, // arguments. Therefore, we need to skip the flag and the next argument. bool ShouldSkip = llvm::StringSwitch(Flag) .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) - .Cases("-o", "-coverage-file", "-dependency-file", true) + .Cases("-o", "-dependency-file", true) .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) .Default(false); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 6e1e4cc..555847a 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -2773,12 +2773,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { + if (getToolChain().getTriple().isOSLinux()) { if (!splitDwarfInlining) CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (DebugInfoKind == codegenoptions::NoDebugInfo) - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-enable-split-dwarf"); + if (SplitDwarfArg) { + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-enable-split-dwarf"); + } } // After we've dealt with all combinations of things that could diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp index 5292a58..1a7a68c 100644 --- a/lib/Edit/EditedSource.cpp +++ b/lib/Edit/EditedSource.cpp @@ -363,13 +363,14 @@ static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, - const SourceManager &SM, const LangOptions &LangOpts) { + const SourceManager &SM, const LangOptions &LangOpts, + bool shouldAdjustRemovals) { assert(offs.getFID().isValid()); SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID()); Loc = Loc.getLocWithOffset(offs.getOffset()); assert(Loc.isFileID()); - if (text.empty()) + if (text.empty() && shouldAdjustRemovals) adjustRemoval(SM, LangOpts, Loc, offs, len, text); CharSourceRange range = CharSourceRange::getCharRange(Loc, @@ -387,7 +388,8 @@ static void applyRewrite(EditsReceiver &receiver, receiver.insert(Loc, text); } -void EditedSource::applyRewrites(EditsReceiver &receiver) { +void EditedSource::applyRewrites(EditsReceiver &receiver, + bool shouldAdjustRemovals) { SmallString<128> StrVec; FileOffset CurOffs, CurEnd; unsigned CurLen; @@ -414,14 +416,16 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) { continue; } - applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts); + applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts, + shouldAdjustRemovals); CurOffs = offs; StrVec = act.Text; CurLen = act.RemoveLen; CurEnd = CurOffs.getWithOffset(CurLen); } - applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts); + applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts, + shouldAdjustRemovals); } void EditedSource::clearRewrites() { diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 5be68ad..2d788b5 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -1040,13 +1040,15 @@ void UnwrappedLineParser::parseStructuralElement() { return; } - // Parse function literal unless 'function' is the first token in a line - // in which case this should be treated as a free-standing function. + // Function declarations (as opposed to function expressions) are parsed + // on their own unwrapped line by continuing this loop. Function + // expressions (functions that are not on their own line) must not create + // a new unwrapped line, so they are special cased below. + size_t TokenCount = Line->Tokens.size(); if (Style.Language == FormatStyle::LK_JavaScript && - (FormatTok->is(Keywords.kw_function) || - FormatTok->startsSequence(Keywords.kw_async, - Keywords.kw_function)) && - Line->Tokens.size() > 0) { + FormatTok->is(Keywords.kw_function) && + (TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is( + Keywords.kw_async)))) { tryToParseJSFunction(); break; } diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 2acdc64..32ee9d3 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1076,9 +1076,11 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. @@ -1552,9 +1554,11 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. @@ -1810,10 +1814,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && - "IR inputs not supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && + "IR inputs not support here!"); // Configure the various subsystems. AST->TheSema.reset(); @@ -2399,11 +2405,12 @@ void ASTUnit::CodeComplete( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); - // Use the source and file managers that we were given. Clang->setFileManager(&FileMgr); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 8b4b169..a7b5fa7 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -858,7 +858,8 @@ bool CompilerInstance::InitializeSourceManager( /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr, - /*SuggestedModule=*/nullptr, /*SkipCache=*/true); + /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, + /*SkipCache=*/true); // Also add the header to /showIncludes output. if (File) DepOpts.ShowIncludesPretendHeader = File->getName(); @@ -1015,14 +1016,14 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { /// \brief Determine the appropriate source input kind based on language /// options. -static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { +static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) { if (LangOpts.OpenCL) - return IK_OpenCL; + return InputKind::OpenCL; if (LangOpts.CUDA) - return IK_CUDA; + return InputKind::CUDA; if (LangOpts.ObjC1) - return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC; - return LangOpts.CPlusPlus? IK_CXX : IK_C; + return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC; + return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C; } /// \brief Compile a module file for the given module, using the options @@ -1079,10 +1080,13 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, FrontendOpts.DisableFree = false; FrontendOpts.GenerateGlobalModuleIndex = false; FrontendOpts.BuildingImplicitModule = true; + FrontendOpts.OriginalModuleMap = + ModMap.getModuleMapFileForUniquing(Module)->getName(); // Force implicitly-built modules to hash the content of the module file. HSOpts.ModulesHashContent = true; FrontendOpts.Inputs.clear(); - InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); + InputKind IK(getLanguageFromOptions(*Invocation->getLangOpts()), + InputKind::ModuleMap); // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; @@ -1127,11 +1131,12 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, if (const FileEntry *ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Use the module map where this module resides. - FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK); + FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK, + +Module->IsSystem); } else { SmallString<128> FakeModuleMapFile(Module->Directory->getName()); llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); - FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK); + FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK, +Module->IsSystem); llvm::raw_string_ostream OS(InferredModuleMapContent); Module->print(OS); @@ -1144,11 +1149,6 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer)); } - // Construct a module-generating action. Passing through the module map is - // safe because the FileManager is shared between the compiler instances. - GenerateModuleFromModuleMapAction CreateModuleAction( - ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem); - ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << Module->Name << ModuleFileName; @@ -1157,8 +1157,12 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; - CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); }, - ThreadStackSize); + CRC.RunSafelyOnThread( + [&]() { + GenerateModuleFromModuleMapAction Action; + Instance.ExecuteAction(Action); + }, + ThreadStackSize); ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build_done) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 8cdb829..d3ebf48 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -81,7 +81,7 @@ using namespace llvm::opt; static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; - if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) + if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -652,7 +652,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.EmitSummaryIndex = A && A->containsValue("thin"); Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false); if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { - if (IK != IK_LLVM_IR) + if (IK.getLanguage() != InputKind::LLVM_IR) Diags.Report(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-x ir"; Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ); @@ -1347,42 +1347,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, << "ARC migration" << "ObjC migration"; } - InputKind DashX = IK_None; + InputKind DashX(InputKind::Unknown); if (const Arg *A = Args.getLastArg(OPT_x)) { - DashX = llvm::StringSwitch(A->getValue()) - .Case("c", IK_C) - .Case("cl", IK_OpenCL) - .Case("cuda", IK_CUDA) - .Case("c++", IK_CXX) - .Case("objective-c", IK_ObjC) - .Case("objective-c++", IK_ObjCXX) - .Case("cpp-output", IK_PreprocessedC) - .Case("assembler-with-cpp", IK_Asm) - .Case("c++-cpp-output", IK_PreprocessedCXX) - .Case("cuda-cpp-output", IK_PreprocessedCuda) - .Case("objective-c-cpp-output", IK_PreprocessedObjC) - .Case("objc-cpp-output", IK_PreprocessedObjC) - .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) - .Case("objc++-cpp-output", IK_PreprocessedObjCXX) - .Case("c-header", IK_C) - .Case("cl-header", IK_OpenCL) - .Case("objective-c-header", IK_ObjC) - .Case("c++-header", IK_CXX) - .Case("objective-c++-header", IK_ObjCXX) - .Cases("ast", "pcm", IK_AST) - .Case("ir", IK_LLVM_IR) - .Case("renderscript", IK_RenderScript) - .Default(IK_None); - if (DashX == IK_None) + StringRef XValue = A->getValue(); + + // Parse suffixes: '(-header|[-module-map][-cpp-output])'. + // FIXME: Supporting '-header-cpp-output' would be useful. + bool Preprocessed = XValue.consume_back("-cpp-output"); + bool ModuleMap = XValue.consume_back("-module-map"); + IsHeaderFile = + !Preprocessed && !ModuleMap && XValue.consume_back("-header"); + + // Principal languages. + DashX = llvm::StringSwitch(XValue) + .Case("c", InputKind::C) + .Case("cl", InputKind::OpenCL) + .Case("cuda", InputKind::CUDA) + .Case("c++", InputKind::CXX) + .Case("objective-c", InputKind::ObjC) + .Case("objective-c++", InputKind::ObjCXX) + .Case("renderscript", InputKind::RenderScript) + .Default(InputKind::Unknown); + + // "objc[++]-cpp-output" is an acceptable synonym for + // "objective-c[++]-cpp-output". + if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap) + DashX = llvm::StringSwitch(XValue) + .Case("objc", InputKind::ObjC) + .Case("objc++", InputKind::ObjCXX) + .Default(InputKind::Unknown); + + // Some special cases cannot be combined with suffixes. + if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile) + DashX = llvm::StringSwitch(XValue) + .Case("cpp-output", InputKind(InputKind::C).getPreprocessed()) + .Case("assembler-with-cpp", InputKind::Asm) + .Cases("ast", "pcm", + InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("ir", InputKind::LLVM_IR) + .Default(InputKind::Unknown); + + if (DashX.isUnknown()) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); - IsHeaderFile = llvm::StringSwitch(A->getValue()) - .Case("c-header", true) - .Case("cl-header", true) - .Case("objective-c-header", true) - .Case("c++-header", true) - .Case("objective-c++-header", true) - .Default(false); + + if (Preprocessed) + DashX = DashX.getPreprocessed(); + if (ModuleMap) + DashX = DashX.withFormat(InputKind::ModuleMap); } // '-' is the default input if none is given. @@ -1392,13 +1404,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Inputs.push_back("-"); for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { InputKind IK = DashX; - if (IK == IK_None) { + if (IK.isUnknown()) { IK = FrontendOptions::getInputKindForExtension( StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Warn on this? + if (IK.isUnknown()) + IK = InputKind::C; // FIXME: Remove this hack. if (i == 0) DashX = IK; } + + // The -emit-module action implicitly takes a module map. + if (Opts.ProgramAction == frontend::GenerateModule && + IK.getFormat() == InputKind::Source) + IK = IK.withFormat(InputKind::ModuleMap); + Opts.Inputs.emplace_back(std::move(Inputs[i]), IK); } @@ -1564,53 +1585,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. - if (IK == IK_Asm) { + // + // FIXME: Perhaps a better model would be for a single source file to have + // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std) + // simultaneously active? + if (IK.getLanguage() == InputKind::Asm) { Opts.AsmPreprocessor = 1; - } else if (IK == IK_ObjC || - IK == IK_ObjCXX || - IK == IK_PreprocessedObjC || - IK == IK_PreprocessedObjCXX) { + } else if (IK.isObjectiveC()) { Opts.ObjC1 = Opts.ObjC2 = 1; } if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. - switch (IK) { - case IK_None: - case IK_AST: - case IK_LLVM_IR: + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: llvm_unreachable("Invalid input kind!"); - case IK_OpenCL: - LangStd = LangStandard::lang_opencl; + case InputKind::OpenCL: + LangStd = LangStandard::lang_opencl10; break; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: LangStd = LangStandard::lang_cuda; break; - case IK_Asm: - case IK_C: - case IK_PreprocessedC: + case InputKind::Asm: + case InputKind::C: // The PS4 uses C99 as the default C standard. if (T.isPS4()) LangStd = LangStandard::lang_gnu99; else LangStd = LangStandard::lang_gnu11; break; - case IK_ObjC: - case IK_PreprocessedObjC: + case InputKind::ObjC: LangStd = LangStandard::lang_gnu11; break; - case IK_CXX: - case IK_PreprocessedCXX: - case IK_ObjCXX: - case IK_PreprocessedObjCXX: + case InputKind::CXX: + case InputKind::ObjCXX: // The PS4 uses C++11 as the default C++ standard. if (T.isPS4()) LangStd = LangStandard::lang_gnucxx11; else LangStd = LangStandard::lang_gnucxx98; break; - case IK_RenderScript: + case InputKind::RenderScript: LangStd = LangStandard::lang_c99; break; } @@ -1626,13 +1642,13 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.CPlusPlus1z = Std.isCPlusPlus1z(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); - Opts.GNUInline = Std.isC89(); + Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus; Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); // Set OpenCL Version. - Opts.OpenCL = Std.isOpenCL() || IK == IK_OpenCL; - if (LangStd == LangStandard::lang_opencl) + Opts.OpenCL = Std.isOpenCL(); + if (LangStd == LangStandard::lang_opencl10) Opts.OpenCLVersion = 100; else if (LangStd == LangStandard::lang_opencl11) Opts.OpenCLVersion = 110; @@ -1655,13 +1671,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } } - Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda || - LangStd == LangStandard::lang_cuda; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); - Opts.RenderScript = IK == IK_RenderScript; + Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript; if (Opts.RenderScript) { Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; @@ -1705,58 +1720,65 @@ static Visibility parseVisibility(Arg *arg, ArgList &args, /// Check if input file kind and language standard are compatible. static bool IsInputCompatibleWithStandard(InputKind IK, const LangStandard &S) { - switch (IK) { - case IK_C: - case IK_ObjC: - case IK_PreprocessedC: - case IK_PreprocessedObjC: - if (S.isC89() || S.isC99()) - return true; - break; - case IK_CXX: - case IK_ObjCXX: - case IK_PreprocessedCXX: - case IK_PreprocessedObjCXX: - if (S.isCPlusPlus()) - return true; - break; - case IK_OpenCL: - if (S.isOpenCL()) - return true; - break; - case IK_CUDA: - case IK_PreprocessedCuda: - if (S.isCPlusPlus()) - return true; - break; - default: - // For other inputs, accept (and ignore) all -std= values. + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: + llvm_unreachable("should not parse language flags for this input"); + + case InputKind::C: + case InputKind::ObjC: + case InputKind::RenderScript: + return S.getLanguage() == InputKind::C; + + case InputKind::OpenCL: + return S.getLanguage() == InputKind::OpenCL; + + case InputKind::CXX: + case InputKind::ObjCXX: + return S.getLanguage() == InputKind::CXX; + + case InputKind::CUDA: + // FIXME: What -std= values should be permitted for CUDA compilations? + return S.getLanguage() == InputKind::CUDA || + S.getLanguage() == InputKind::CXX; + + case InputKind::Asm: + // Accept (and ignore) all -std= values. + // FIXME: The -std= value is not ignored; it affects the tokenization + // and preprocessing rules if we're preprocessing this asm input. return true; } - return false; + + llvm_unreachable("unexpected input language"); } /// Get language name for given input kind. static const StringRef GetInputKindName(InputKind IK) { - switch (IK) { - case IK_C: - case IK_ObjC: - case IK_PreprocessedC: - case IK_PreprocessedObjC: - return "C/ObjC"; - case IK_CXX: - case IK_ObjCXX: - case IK_PreprocessedCXX: - case IK_PreprocessedObjCXX: - return "C++/ObjC++"; - case IK_OpenCL: + switch (IK.getLanguage()) { + case InputKind::C: + return "C"; + case InputKind::ObjC: + return "Objective-C"; + case InputKind::CXX: + return "C++"; + case InputKind::ObjCXX: + return "Objective-C++"; + case InputKind::OpenCL: return "OpenCL"; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: return "CUDA"; - default: - llvm_unreachable("Cannot decide on name for InputKind!"); + case InputKind::RenderScript: + return "RenderScript"; + + case InputKind::Asm: + return "Asm"; + case InputKind::LLVM_IR: + return "LLVM IR"; + + case InputKind::Unknown: + break; } + llvm_unreachable("unknown input language"); } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, @@ -1767,7 +1789,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { LangStd = llvm::StringSwitch(A->getValue()) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, LangStandard::lang_##id) #define LANGSTANDARD_ALIAS(id, alias) \ .Case(alias, LangStandard::lang_##id) @@ -1783,8 +1805,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, const LangStandard &Std = LangStandard::getLangStandardForKind( static_cast(KindValue)); if (IsInputCompatibleWithStandard(IK, Std)) { - Diags.Report(diag::note_drv_use_standard) - << Std.getName() << Std.getDescription(); + auto Diag = Diags.Report(diag::note_drv_use_standard); + Diag << Std.getName() << Std.getDescription(); + unsigned NumAliases = 0; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) ++NumAliases; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" + Diag << NumAliases; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) Diag << alias; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" } } } else { @@ -1803,7 +1837,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { LangStandard::Kind OpenCLLangStd = llvm::StringSwitch(A->getValue()) - .Cases("cl", "CL", LangStandard::lang_opencl) + .Cases("cl", "CL", LangStandard::lang_opencl10) .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) @@ -2533,7 +2567,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Res.getTargetOpts()); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Res.getFileSystemOpts().WorkingDir); - if (DashX == IK_AST || DashX == IK_LLVM_IR) { + if (DashX.getFormat() == InputKind::Precompiled || + DashX.getLanguage() == InputKind::LLVM_IR) { // ObjCAAutoRefCount and Sanitize LangOpts are used to setup the // PassManager in BackendUtil.cpp. They need to be initializd no matter // what the input type is. @@ -2547,8 +2582,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Diags, LangOpts.Sanitize); } else { // Other LangOpts are only initialzed when the input is not AST or LLVM IR. + // FIXME: Should we really be calling this for an InputKind::Asm input? ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), - Res.getPreprocessorOpts(), Diags); + Res.getPreprocessorOpts(), Diags); if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) LangOpts.ObjCExceptions = 1; } diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 0dd07d9..d26b693 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -224,6 +224,231 @@ static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) return true; } +static SmallVectorImpl & +operator+=(SmallVectorImpl &Includes, StringRef RHS) { + Includes.append(RHS.begin(), RHS.end()); + return Includes; +} + +static void addHeaderInclude(StringRef HeaderName, + SmallVectorImpl &Includes, + const LangOptions &LangOpts, + bool IsExternC) { + if (IsExternC && LangOpts.CPlusPlus) + Includes += "extern \"C\" {\n"; + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + + Includes += HeaderName; + + Includes += "\"\n"; + if (IsExternC && LangOpts.CPlusPlus) + Includes += "}\n"; +} + +/// \brief Collect the set of header includes needed to construct the given +/// module and update the TopHeaders file set of the module. +/// +/// \param Module The module we're collecting includes from. +/// +/// \param Includes Will be augmented with the set of \#includes or \#imports +/// needed to load all of the named headers. +static std::error_code +collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, + ModuleMap &ModMap, clang::Module *Module, + SmallVectorImpl &Includes) { + // Don't collect any headers for unavailable modules. + if (!Module->isAvailable()) + return std::error_code(); + + // Add includes for each of these headers. + 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. + addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); + } + } + // Note that Module->PrivateHeaders will not be a TopHeader. + + if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { + Module->addTopHeader(UmbrellaHeader.Entry); + if (Module->Parent) + // Include the umbrella header for submodules. + addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, + Module->IsExternC); + } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { + // Add all of the headers we find in this subdirectory. + std::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); + + vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); + for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; + Dir != End && !EC; Dir.increment(EC)) { + // Check whether this entry has an extension typically associated with + // headers. + if (!llvm::StringSwitch(llvm::sys::path::extension(Dir->getName())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + const FileEntry *Header = FileMgr.getFile(Dir->getName()); + // FIXME: This shouldn't happen unless there is a file system race. Is + // that worth diagnosing? + if (!Header) + continue; + + // If this header is marked 'unavailable' in this module, don't include + // it. + if (ModMap.isHeaderUnavailableInModule(Header, Module)) + continue; + + // Compute the relative path from the directory to this file. + SmallVector Components; + auto PathIt = llvm::sys::path::rbegin(Dir->getName()); + for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) + Components.push_back(*PathIt); + SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); + for (auto It = Components.rbegin(), End = Components.rend(); It != End; + ++It) + llvm::sys::path::append(RelativeHeader, *It); + + // Include this header as part of the umbrella directory. + Module->addTopHeader(Header); + addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); + } + + if (EC) + return EC; + } + + // Recurse into submodules. + for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), + SubEnd = Module->submodule_end(); + Sub != SubEnd; ++Sub) + if (std::error_code Err = collectModuleHeaderIncludes( + LangOpts, FileMgr, ModMap, *Sub, Includes)) + return Err; + + return std::error_code(); +} + +/// Parse a module map and compute the corresponding real input buffer that +/// should be used to build the module described by that module map and the +/// current module name. +static std::unique_ptr +getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, + bool IsSystem) { + // Find the module map file. + const FileEntry *ModuleMap = + CI.getFileManager().getFile(Filename, /*openFile*/true); + if (!ModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << Filename; + return nullptr; + } + + // Find the module map file from which it was generated, if different. + const FileEntry *OriginalModuleMap = ModuleMap; + StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; + if (!OriginalModuleMapName.empty()) { + OriginalModuleMap = CI.getFileManager().getFile(OriginalModuleMapName, + /*openFile*/ true); + if (!OriginalModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << OriginalModuleMapName; + return nullptr; + } + } + + // Parse the module map file. + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + if (HS.loadModuleMapFile(ModuleMap, IsSystem)) + return nullptr; + + if (CI.getLangOpts().CurrentModule.empty()) { + CI.getDiagnostics().Report(diag::err_missing_module_name); + + // FIXME: Eventually, we could consider asking whether there was just + // a single module described in the module map, and use that as a + // default. Then it would be fairly trivial to just "compile" a module + // map with a single module (the common case). + return nullptr; + } + + // 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. + SourceManager &SourceMgr = CI.getSourceManager(); + if (SourceMgr.getModuleBuildStack().empty()) + SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, + FullSourceLoc(SourceLocation(), SourceMgr)); + + // Dig out the module definition. + Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, + /*AllowSearch=*/false); + if (!M) { + CI.getDiagnostics().Report(diag::err_missing_module) + << CI.getLangOpts().CurrentModule << Filename; + + return nullptr; + } + + // Check whether we can build this module at all. + clang::Module::Requirement Requirement; + clang::Module::UnresolvedHeaderDirective MissingHeader; + if (!M->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, + MissingHeader)) { + if (MissingHeader.FileNameLoc.isValid()) { + CI.getDiagnostics().Report(MissingHeader.FileNameLoc, + diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + } else { + CI.getDiagnostics().Report(diag::err_module_unavailable) + << M->getFullModuleName() << Requirement.second << Requirement.first; + } + + return nullptr; + } + + if (OriginalModuleMap != ModuleMap) { + M->IsInferred = true; + HS.getModuleMap().setInferredModuleAllowedBy(M, OriginalModuleMap); + } + + FileManager &FileMgr = CI.getFileManager(); + + // Collect the set of #includes we need to build the module. + SmallString<256> HeaderContents; + std::error_code Err = std::error_code(); + if (Module::Header UmbrellaHeader = M->getUmbrellaHeader()) + addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, + CI.getLangOpts(), M->IsExternC); + Err = collectModuleHeaderIncludes( + CI.getLangOpts(), FileMgr, + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M, + HeaderContents); + + if (Err) { + CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) + << M->getFullModuleName() << Err.message(); + return nullptr; + } + + // Inform the preprocessor that includes from within the input buffer should + // be resolved relative to the build directory of the module map file. + CI.getPreprocessor().setMainFileDir(M->Directory); + + return llvm::MemoryBuffer::getMemBufferCopy( + HeaderContents, Module::getModuleInputBufferName()); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input) { assert(!Instance && "Already processing a source file!"); @@ -232,13 +457,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCompilerInstance(&CI); StringRef InputFile = Input.getFile(); + FrontendInputFile FileToProcess = Input; bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.getKind() == IK_AST) { + if (Input.getKind().getFormat() == InputKind::Precompiled) { + // FIXME: We should not be asserting on bad command-line arguments. assert(!usesPreprocessorOnly() && "Attempt to pass AST file to preprocessor only action!"); assert(hasASTFileSupport() && @@ -296,8 +523,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.hasSourceManager()) CI.createSourceManager(CI.getFileManager()); + // 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); + // IR files bypass the rest of initialization. - if (Input.getKind() == IK_LLVM_IR) { + if (Input.getKind().getLanguage() == InputKind::LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -359,13 +597,34 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; + // For module map files, we first parse the module map and synthesize a + // "" buffer before more conventional processing. + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); + + auto Buffer = getInputBufferForModuleMap(CI, InputFile, Input.isSystem()); + if (!Buffer) + goto failure; + + Module *CurrentModule = + CI.getPreprocessor().getHeaderSearchInfo().lookupModule( + CI.getLangOpts().CurrentModule, + /*AllowSearch=*/false); + assert(CurrentModule && "no module info for current module"); + + // The input that we end up processing is the generated buffer, not the + // module map file itself. + FileToProcess = FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem); + } + // Initialize the action. if (!BeginSourceFileAction(CI, InputFile)) goto failure; - // Initialize the main file entry. It is important that this occurs after - // BeginSourceFileAction, which may change CurrentInput during module builds. - if (!CI.InitializeSourceManager(CurrentInput)) + // Initialize the main file entry. + if (!CI.InitializeSourceManager(FileToProcess)) goto failure; // Create the AST context and consumer unless this is a preprocessor only @@ -497,6 +756,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); CI.clearOutputFiles(/*EraseFiles=*/true); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); setCurrentInput(FrontendInputFile()); setCompilerInstance(nullptr); return false; @@ -579,6 +839,7 @@ void FrontendAction::EndSourceFile() { setCompilerInstance(nullptr); setCurrentInput(FrontendInputFile()); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); } bool FrontendAction::shouldEraseOutputFiles() { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index e818038..dd7c12f 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -164,242 +164,9 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, return llvm::make_unique(std::move(Consumers)); } -bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { - // 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); - - return true; -} - - -static SmallVectorImpl & -operator+=(SmallVectorImpl &Includes, StringRef RHS) { - Includes.append(RHS.begin(), RHS.end()); - return Includes; -} - -static void addHeaderInclude(StringRef HeaderName, - SmallVectorImpl &Includes, - const LangOptions &LangOpts, - bool IsExternC) { - if (IsExternC && LangOpts.CPlusPlus) - Includes += "extern \"C\" {\n"; - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - - Includes += HeaderName; - - Includes += "\"\n"; - if (IsExternC && LangOpts.CPlusPlus) - Includes += "}\n"; -} - -/// \brief Collect the set of header includes needed to construct the given -/// module and update the TopHeaders file set of the module. -/// -/// \param Module The module we're collecting includes from. -/// -/// \param Includes Will be augmented with the set of \#includes or \#imports -/// needed to load all of the named headers. -static std::error_code -collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, - ModuleMap &ModMap, clang::Module *Module, - SmallVectorImpl &Includes) { - // Don't collect any headers for unavailable modules. - if (!Module->isAvailable()) - return std::error_code(); - - // Add includes for each of these headers. - 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. - addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); - } - } - // Note that Module->PrivateHeaders will not be a TopHeader. - - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->addTopHeader(UmbrellaHeader.Entry); - if (Module->Parent) - // Include the umbrella header for submodules. - addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, - Module->IsExternC); - } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { - // Add all of the headers we find in this subdirectory. - std::error_code EC; - SmallString<128> DirNative; - llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); - - vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); - for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; - Dir != End && !EC; Dir.increment(EC)) { - // Check whether this entry has an extension typically associated with - // headers. - if (!llvm::StringSwitch(llvm::sys::path::extension(Dir->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) - continue; - - const FileEntry *Header = FileMgr.getFile(Dir->getName()); - // FIXME: This shouldn't happen unless there is a file system race. Is - // that worth diagnosing? - if (!Header) - continue; - - // If this header is marked 'unavailable' in this module, don't include - // it. - if (ModMap.isHeaderUnavailableInModule(Header, Module)) - continue; - - // Compute the relative path from the directory to this file. - SmallVector Components; - auto PathIt = llvm::sys::path::rbegin(Dir->getName()); - for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) - Components.push_back(*PathIt); - SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); - for (auto It = Components.rbegin(), End = Components.rend(); It != End; - ++It) - llvm::sys::path::append(RelativeHeader, *It); - - // Include this header as part of the umbrella directory. - Module->addTopHeader(Header); - addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); - } - - if (EC) - return EC; - } - - // Recurse into submodules. - for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), - SubEnd = Module->submodule_end(); - Sub != SubEnd; ++Sub) - if (std::error_code Err = collectModuleHeaderIncludes( - LangOpts, FileMgr, ModMap, *Sub, Includes)) - return Err; - - return std::error_code(); -} - bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( CompilerInstance &CI, StringRef Filename) { - CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - - if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename)) - return false; - - // Find the module map file. - const FileEntry *ModuleMap = - CI.getFileManager().getFile(Filename, /*openFile*/true); - if (!ModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << Filename; - return false; - } - - // Parse the module map file. - HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - if (HS.loadModuleMapFile(ModuleMap, IsSystem)) - return false; - - if (CI.getLangOpts().CurrentModule.empty()) { - CI.getDiagnostics().Report(diag::err_missing_module_name); - - // FIXME: Eventually, we could consider asking whether there was just - // a single module described in the module map, and use that as a - // default. Then it would be fairly trivial to just "compile" a module - // map with a single module (the common case). - return false; - } - - // 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. - SourceManager &SourceMgr = CI.getSourceManager(); - if (SourceMgr.getModuleBuildStack().empty()) - SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, - FullSourceLoc(SourceLocation(), SourceMgr)); - - // Dig out the module definition. - Module = HS.lookupModule(CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); - if (!Module) { - CI.getDiagnostics().Report(diag::err_missing_module) - << CI.getLangOpts().CurrentModule << Filename; - - return false; - } - - // Check whether we can build this module at all. - clang::Module::Requirement Requirement; - clang::Module::UnresolvedHeaderDirective MissingHeader; - if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, - MissingHeader)) { - if (MissingHeader.FileNameLoc.isValid()) { - CI.getDiagnostics().Report(MissingHeader.FileNameLoc, - diag::err_module_header_missing) - << MissingHeader.IsUmbrella << MissingHeader.FileName; - } else { - CI.getDiagnostics().Report(diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first; - } - - return false; - } - - if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) { - Module->IsInferred = true; - HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing); - } else { - ModuleMapForUniquing = ModuleMap; - } - - FileManager &FileMgr = CI.getFileManager(); - - // Collect the set of #includes we need to build the module. - SmallString<256> HeaderContents; - std::error_code Err = std::error_code(); - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) - addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, - CI.getLangOpts(), Module->IsExternC); - Err = collectModuleHeaderIncludes( - CI.getLangOpts(), FileMgr, - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, - HeaderContents); - - if (Err) { - CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) - << Module->getFullModuleName() << Err.message(); - return false; - } - - // Inform the preprocessor that includes from within the input buffer should - // be resolved relative to the build directory of the module map file. - CI.getPreprocessor().setMainFileDir(Module->Directory); - - std::unique_ptr InputBuffer = - llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, - Module::getModuleInputBufferName()); - // Ownership of InputBuffer will be transferred to the SourceManager. - setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(), - Module->IsSystem)); - return true; + return GenerateModuleAction::BeginSourceFileAction(CI, Filename); } std::unique_ptr @@ -408,10 +175,13 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, // If no output file was provided, figure out where this module would go // in the module cache. if (CI.getFrontendOpts().OutputFile.empty()) { + StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap; + if (ModuleMapFile.empty()) + ModuleMapFile = InFile; + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); CI.getFrontendOpts().OutputFile = - HS.getModuleFileName(CI.getLangOpts().CurrentModule, - ModuleMapForUniquing->getName(), + HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile, /*UsePrebuiltPath=*/false); } @@ -777,29 +547,27 @@ void PrintPreprocessedAction::ExecuteAction() { } void PrintPreambleAction::ExecuteAction() { - switch (getCurrentFileKind()) { - case IK_C: - case IK_CXX: - case IK_ObjC: - case IK_ObjCXX: - case IK_OpenCL: - case IK_CUDA: + switch (getCurrentFileKind().getLanguage()) { + case InputKind::C: + case InputKind::CXX: + case InputKind::ObjC: + case InputKind::ObjCXX: + case InputKind::OpenCL: + case InputKind::CUDA: break; - case IK_None: - case IK_Asm: - case IK_PreprocessedC: - case IK_PreprocessedCuda: - case IK_PreprocessedCXX: - case IK_PreprocessedObjC: - case IK_PreprocessedObjCXX: - case IK_AST: - case IK_LLVM_IR: - case IK_RenderScript: + case InputKind::Unknown: + case InputKind::Asm: + case InputKind::LLVM_IR: + case InputKind::RenderScript: // We can't do anything with these. return; } + // We don't expect to find any #include directives in a preprocessed input. + if (getCurrentFileKind().isPreprocessed()) + return; + CompilerInstance &CI = getCompilerInstance(); auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 6a82084..dca4345 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -13,22 +13,22 @@ using namespace clang; InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch(Extension) - .Cases("ast", "pcm", IK_AST) - .Case("c", IK_C) - .Cases("S", "s", IK_Asm) - .Case("i", IK_PreprocessedC) - .Case("ii", IK_PreprocessedCXX) - .Case("cui", IK_PreprocessedCuda) - .Case("m", IK_ObjC) - .Case("mi", IK_PreprocessedObjC) - .Cases("mm", "M", IK_ObjCXX) - .Case("mii", IK_PreprocessedObjCXX) - .Cases("C", "cc", "cp", IK_CXX) - .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) - .Case("cppm", IK_CXX) - .Case("iim", IK_PreprocessedCXX) - .Case("cl", IK_OpenCL) - .Case("cu", IK_CUDA) - .Cases("ll", "bc", IK_LLVM_IR) - .Default(IK_C); + .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("c", InputKind::C) + .Cases("S", "s", InputKind::Asm) + .Case("i", InputKind(InputKind::C).getPreprocessed()) + .Case("ii", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cui", InputKind(InputKind::CUDA).getPreprocessed()) + .Case("m", InputKind::ObjC) + .Case("mi", InputKind(InputKind::ObjC).getPreprocessed()) + .Cases("mm", "M", InputKind::ObjCXX) + .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed()) + .Cases("C", "cc", "cp", InputKind::CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX) + .Case("cppm", InputKind::CXX) + .Case("iim", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cl", InputKind::OpenCL) + .Case("cu", InputKind::CUDA) + .Cases("ll", "bc", InputKind::LLVM_IR) + .Default(InputKind::Unknown); } diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 0dd04e8..9257dca 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -1041,6 +1041,8 @@ void clang::InitializePreprocessor( // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) { + // FIXME: This will create multiple definitions for most of the predefined + // macros. This is not the right way to handle this. if (LangOpts.CUDA && PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, Builder); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp index f133327..47023e5 100644 --- a/lib/Frontend/LangStandards.cpp +++ b/lib/Frontend/LangStandards.cpp @@ -13,15 +13,15 @@ using namespace clang; using namespace clang::frontend; -#define LANGSTANDARD(id, name, desc, features) \ - static const LangStandard Lang_##id = { name, desc, features }; +#define LANGSTANDARD(id, name, lang, desc, features) \ +static const LangStandard Lang_##id = { name, desc, features, InputKind::lang }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { case lang_unspecified: llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ case lang_##id: return Lang_##id; #include "clang/Frontend/LangStandards.def" } @@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch(Name) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, lang_##id) #include "clang/Frontend/LangStandards.def" .Default(lang_unspecified); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index d48b952..ffedf3c 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -172,7 +172,8 @@ public: /// MacroUndefined - This hook is called whenever a macro #undef is seen. void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override; + const MacroDefinition &MD, + const MacroDirective *Undef) override; }; } // end anonymous namespace @@ -323,43 +324,50 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, StringRef SearchPath, StringRef RelativePath, const Module *Imported) { - if (Imported) { - // When preprocessing, turn implicit imports into @imports. - // FIXME: This is a stop-gap until a more comprehensive "preprocessing with - // modules" solution is introduced. + // In -dI mode, dump #include directives prior to dumping their content or + // interpretation. + if (DumpIncludeDirectives) { startNewLineIfNeeded(); MoveToLine(HashLoc); - if (PP.getLangOpts().ObjC2) { - OS << "@import " << Imported->getFullModuleName() << ";" - << " /* clang -E: implicit import for \"" << File->getName() - << "\" */"; - } else { - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " - << (IsAngled ? '<' : '"') - << FileName - << (IsAngled ? '>' : '"') - << " /* clang -E: implicit import for module " - << Imported->getFullModuleName() << " */"; - } - // Since we want a newline after the @import, but not a #, start a new - // line immediately. - EmittedTokensOnThisLine = true; + const std::string TokenText = PP.getSpelling(IncludeTok); + assert(!TokenText.empty()); + OS << "#" << TokenText << " " + << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') + << " /* clang -E -dI */"; + setEmittedDirectiveOnThisLine(); startNewLineIfNeeded(); - } else { - // Not a module import; it's a more vanilla inclusion of some file using one - // of: #include, #import, #include_next, #include_macros. - if (DumpIncludeDirectives) { + } + + // When preprocessing, turn implicit imports into module import pragmas. + if (Imported) { + switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { + case tok::pp_include: + case tok::pp_import: + case tok::pp_include_next: startNewLineIfNeeded(); MoveToLine(HashLoc); - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " + OS << "#pragma clang module import " << Imported->getFullModuleName() + << " /* clang -E: implicit import for " + << "#" << PP.getSpelling(IncludeTok) << " " << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') - << " /* clang -E -dI */"; - setEmittedDirectiveOnThisLine(); + << " */"; + // Since we want a newline after the pragma, but not a #, start a + // new line immediately. + EmittedTokensOnThisLine = true; startNewLineIfNeeded(); + break; + + case tok::pp___include_macros: + // #__include_macros has no effect on a user of a preprocessed source + // file; the only effect is on preprocessing. + // + // FIXME: That's not *quite* true: it causes the module in question to + // be loaded, which can affect downstream diagnostics. + break; + + default: + llvm_unreachable("unknown include directive kind"); + break; } } } @@ -389,7 +397,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, } void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { // Only print out macro definitions in -dD mode. if (!DumpDefines) return; @@ -773,26 +782,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Expand macros in pragmas with -fms-extensions. The assumption is that // the majority of pragmas in such a file will be Microsoft pragmas. - PP.AddPragmaHandler(new UnknownPragmaHandler( - "#pragma", Callbacks, + // Remember the handlers we will add so that we can remove them later. + std::unique_ptr MicrosoftExtHandler( + new UnknownPragmaHandler( + "#pragma", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr GCCHandler(new UnknownPragmaHandler( + "#pragma GCC", Callbacks, /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "GCC", new UnknownPragmaHandler( - "#pragma GCC", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "clang", new UnknownPragmaHandler( - "#pragma clang", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr ClangHandler(new UnknownPragmaHandler( + "#pragma clang", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + PP.AddPragmaHandler(MicrosoftExtHandler.get()); + PP.AddPragmaHandler("GCC", GCCHandler.get()); + PP.AddPragmaHandler("clang", ClangHandler.get()); // The tokens after pragma omp need to be expanded. // // OpenMP [2.1, Directive format] // Preprocessing tokens following the #pragma omp are subject to macro // replacement. - PP.AddPragmaHandler("omp", - new UnknownPragmaHandler("#pragma omp", Callbacks, - /*RequireTokenExpansion=*/true)); + std::unique_ptr OpenMPHandler( + new UnknownPragmaHandler("#pragma omp", Callbacks, + /*RequireTokenExpansion=*/true)); + PP.AddPragmaHandler("omp", OpenMPHandler.get()); PP.addPPCallbacks(std::unique_ptr(Callbacks)); @@ -820,4 +836,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Read all the preprocessed tokens, printing them out to the stream. PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); *OS << '\n'; + + // Remove the handlers we just added to leave the preprocessor in a sane state + // so that it can be reused (for example by a clang::Parser instance). + PP.RemovePragmaHandler(MicrosoftExtHandler.get()); + PP.RemovePragmaHandler("GCC", GCCHandler.get()); + PP.RemovePragmaHandler("clang", ClangHandler.get()); + PP.RemovePragmaHandler("omp", OpenMPHandler.get()); } diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp index d953da2..ee61f76 100644 --- a/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -52,7 +52,7 @@ class InclusionRewriter : public PPCallbacks { public: InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, bool UseLineDirectives); - bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); + void Process(FileID FileId, SrcMgr::CharacteristicKind FileType); void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { PredefinesBuffer = Buf; } @@ -132,7 +132,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, } void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { - OS << "@import " << Mod->getFullModuleName() << ";" + OS << "#pragma clang module import " << Mod->getFullModuleName() << " /* clang -frewrite-includes: implicit import */" << MainEOL; } @@ -392,7 +392,7 @@ bool InclusionRewriter::HandleHasInclude( // FIXME: Why don't we call PP.LookupFile here? const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr, - nullptr, nullptr, nullptr, false); + nullptr, nullptr, nullptr, nullptr); FileExists = File != nullptr; return true; @@ -400,9 +400,8 @@ bool InclusionRewriter::HandleHasInclude( /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it /// and including content of included files recursively. -bool InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType) -{ +void InclusionRewriter::Process(FileID FileId, + SrcMgr::CharacteristicKind FileType) { bool Invalid; const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); assert(!Invalid && "Attempting to process invalid inclusion"); @@ -419,7 +418,7 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, 1, FileType, " 1"); if (SM.getFileIDSize(FileId) == 0) - return false; + return; // The next byte to be copied from the source file, which may be non-zero if // the lexer handled a BOM. @@ -450,19 +449,14 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, Line - 1, FileType, ""); StringRef LineInfoExtra; SourceLocation Loc = HashToken.getLocation(); - if (const Module *Mod = PP.getLangOpts().ObjC2 - ? FindModuleAtLocation(Loc) - : nullptr) + if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { - // include and recursively process the file - if (Process(Inc->Id, Inc->FileType)) { - // and set lineinfo back to this file, if the nested one was - // actually included - // `2' indicates returning to a file (after having included - // another file. - LineInfoExtra = " 2"; - } + // Include and recursively process the file. + Process(Inc->Id, Inc->FileType); + // Add line marker to indicate we're returning from an included + // file. + LineInfoExtra = " 2"; } // fix up lineinfo (since commented out directive changed line // numbers) for inclusions that were skipped due to header guards @@ -571,7 +565,6 @@ bool InclusionRewriter::Process(FileID FileId, OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, Line, /*EnsureNewline=*/true); - return true; } /// InclusionRewriterInInput - Implement -frewrite-includes mode. diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index ae16ea1..427d15e 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, const DirectoryLookup *CurDir; const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); if (!FE) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_file) << Filename << KindStr; diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h index d8535f7..b556d04 100644 --- a/lib/Headers/avx512fintrin.h +++ b/lib/Headers/avx512fintrin.h @@ -528,6 +528,116 @@ _mm512_mask2int(__mmask16 __a) return (int)__a; } +/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a +/// 128-bit floating-point vector of [2 x double]. The lower 128 bits +/// contain the value of the source vector. The upper 384 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [2 x double]. +/// \returns A 512-bit floating-point vector of [8 x double]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline __m512d __DEFAULT_FN_ATTRS +_mm512_zextpd128_pd512(__m128d __a) +{ + return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3, 2, 3, 2, 3); +} + +/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a +/// 256-bit floating-point vector of [4 x double]. The lower 256 bits +/// contain the value of the source vector. The upper 256 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x double]. +/// \returns A 512-bit floating-point vector of [8 x double]. The lower 256 bits +/// contain the value of the parameter. The upper 256 bits are set to zero. +static __inline __m512d __DEFAULT_FN_ATTRS +_mm512_zextpd256_pd512(__m256d __a) +{ + return __builtin_shufflevector((__v4df)__a, (__v4df)_mm256_setzero_pd(), 0, 1, 2, 3, 4, 5, 6, 7); +} + +/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a +/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain +/// the value of the source vector. The upper 384 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [4 x float]. +/// \returns A 512-bit floating-point vector of [16 x float]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline __m512 __DEFAULT_FN_ATTRS +_mm512_zextps128_ps512(__m128 __a) +{ + return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7); +} + +/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a +/// 256-bit floating-point vector of [8 x float]. The lower 256 bits contain +/// the value of the source vector. The upper 256 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x float]. +/// \returns A 512-bit floating-point vector of [16 x float]. The lower 256 bits +/// contain the value of the parameter. The upper 256 bits are set to zero. +static __inline __m512 __DEFAULT_FN_ATTRS +_mm512_zextps256_ps512(__m256 __a) +{ + return __builtin_shufflevector((__v8sf)__a, (__v8sf)_mm256_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); +} + +/// \brief Constructs a 512-bit integer vector from a 128-bit integer vector. +/// The lower 128 bits contain the value of the source vector. The upper +/// 384 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit integer vector. +/// \returns A 512-bit integer vector. The lower 128 bits contain the value of +/// the parameter. The upper 384 bits are set to zero. +static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_zextsi128_si512(__m128i __a) +{ + return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3, 2, 3, 2, 3); +} + +/// \brief Constructs a 512-bit integer vector from a 256-bit integer vector. +/// The lower 256 bits contain the value of the source vector. The upper +/// 256 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit integer vector. +/// \returns A 512-bit integer vector. The lower 256 bits contain the value of +/// the parameter. The upper 256 bits are set to zero. +static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_zextsi256_si512(__m256i __a) +{ + return __builtin_shufflevector((__v4di)__a, (__v4di)_mm256_setzero_si256(), 0, 1, 2, 3, 4, 5, 6, 7); +} + /* Bitwise operators */ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_and_epi32(__m512i __a, __m512i __b) diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h index 5381878..cdb7aa4 100644 --- a/lib/Headers/avxintrin.h +++ b/lib/Headers/avxintrin.h @@ -4523,6 +4523,61 @@ _mm256_castsi128_si256(__m128i __a) return __builtin_shufflevector((__v2di)__a, (__v2di)__a, 0, 1, -1, -1); } +/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a +/// 128-bit floating-point vector of [2 x double]. The lower 128 bits +/// contain the value of the source vector. The upper 128 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [2 x double]. +/// \returns A 256-bit floating-point vector of [4 x double]. The lower 128 bits +/// contain the value of the parameter. The upper 128 bits are set to zero. +static __inline __m256d __DEFAULT_FN_ATTRS +_mm256_zextpd128_pd256(__m128d __a) +{ + return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3); +} + +/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a +/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain +/// the value of the source vector. The upper 128 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [4 x float]. +/// \returns A 256-bit floating-point vector of [8 x float]. The lower 128 bits +/// contain the value of the parameter. The upper 128 bits are set to zero. +static __inline __m256 __DEFAULT_FN_ATTRS +_mm256_zextps128_ps256(__m128 __a) +{ + return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7); +} + +/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector. +/// The lower 128 bits contain the value of the source vector. The upper +/// 128 bits are set to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit integer vector. +/// \returns A 256-bit integer vector. The lower 128 bits contain the value of +/// the parameter. The upper 128 bits are set to zero. +static __inline __m256i __DEFAULT_FN_ATTRS +_mm256_zextsi128_si256(__m128i __a) +{ + return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3); +} + /* Vector insert. We use macros rather than inlines because we only want to accept diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h index 488eb2d..e590cf8 100644 --- a/lib/Headers/bmiintrin.h +++ b/lib/Headers/bmiintrin.h @@ -28,107 +28,17 @@ #ifndef __BMIINTRIN_H #define __BMIINTRIN_H -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile -/// -/// \code -/// unsigned short _tzcnt_u16(unsigned short a); -/// \endcode -/// -/// This intrinsic corresponds to the TZCNT instruction. -/// -/// \param a -/// An unsigned 16-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 16-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u16(a) (__tzcnt_u16((a))) -/// \brief Performs a bitwise AND of the second operand with the one's -/// complement of the first operand. -/// -/// \headerfile -/// -/// \code -/// unsigned int _andn_u32(unsigned int a, unsigned int b); -/// \endcode -/// -/// This intrinsic corresponds to the ANDN instruction. -/// -/// \param a -/// An unsigned integer containing one of the operands. -/// \param b -/// An unsigned integer containing one of the operands. -/// \returns An unsigned integer containing the bitwise AND of the second -/// operand with the one's complement of the first operand. #define _andn_u32(a, b) (__andn_u32((a), (b))) /* _bextr_u32 != __bextr_u32 */ -/// \brief Clears all bits in the source except for the least significant bit -/// containing a value of 1 and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned int _blsi_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSI instruction. -/// -/// \param a -/// An unsigned integer whose bits are to be cleared. -/// \returns An unsigned integer containing the result of clearing the bits from -/// the source operand. #define _blsi_u32(a) (__blsi_u32((a))) -/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and -/// including the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned int _blsmsk_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSMSK instruction. -/// -/// \param a -/// An unsigned integer used to create the mask. -/// \returns An unsigned integer containing the newly created mask. #define _blsmsk_u32(a) (__blsmsk_u32((a))) -/// \brief Clears the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned int _blsr_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSR instruction. -/// -/// \param a -/// An unsigned integer containing the operand to be cleared. -/// \returns An unsigned integer containing the result of clearing the source -/// operand. #define _blsr_u32(a) (__blsr_u32((a))) -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile -/// -/// \code -/// unsigned int _tzcnt_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the TZCNT instruction. -/// -/// \param a -/// An unsigned 32-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 32-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u32(a) (__tzcnt_u32((a))) /* Define the default attributes for the functions in this file. */ @@ -305,91 +215,15 @@ _mm_tzcnt_32(unsigned int __X) #ifdef __x86_64__ -/// \brief Performs a bitwise AND of the second operand with the one's -/// complement of the first operand. -/// -/// \headerfile -/// -/// \code -/// unsigned long long _andn_u64 (unsigned long long a, unsigned long long b); -/// \endcode -/// -/// This intrinsic corresponds to the ANDN instruction. -/// -/// \param a -/// An unsigned 64-bit integer containing one of the operands. -/// \param b -/// An unsigned 64-bit integer containing one of the operands. -/// \returns An unsigned 64-bit integer containing the bitwise AND of the second -/// operand with the one's complement of the first operand. #define _andn_u64(a, b) (__andn_u64((a), (b))) /* _bextr_u64 != __bextr_u64 */ -/// \brief Clears all bits in the source except for the least significant bit -/// containing a value of 1 and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned long long _blsi_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSI instruction. -/// -/// \param a -/// An unsigned 64-bit integer whose bits are to be cleared. -/// \returns An unsigned 64-bit integer containing the result of clearing the -/// bits from the source operand. #define _blsi_u64(a) (__blsi_u64((a))) -/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and -/// including the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned long long _blsmsk_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSMSK instruction. -/// -/// \param a -/// An unsigned 64-bit integer used to create the mask. -/// \returns A unsigned 64-bit integer containing the newly created mask. #define _blsmsk_u64(a) (__blsmsk_u64((a))) -/// \brief Clears the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile -/// -/// \code -/// unsigned long long _blsr_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the BLSR instruction. -/// -/// \param a -/// An unsigned 64-bit integer containing the operand to be cleared. -/// \returns An unsigned 64-bit integer containing the result of clearing the -/// source operand. #define _blsr_u64(a) (__blsr_u64((a))) -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile -/// -/// \code -/// unsigned long long _tzcnt_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the TZCNT instruction. -/// -/// \param a -/// An unsigned 64-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 64-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u64(a) (__tzcnt_u64((a))) /// \brief Performs a bitwise AND of the second operand with the one's diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index 0dfa6a9..13b0db2 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -1750,6 +1750,24 @@ _mm_set1_pd(double __w) return (__m128d){ __w, __w }; } +/// \brief Constructs a 128-bit floating-point vector of [2 x double], with each +/// of the two double-precision floating-point vector elements set to the +/// specified double-precision floating-point value. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VMOVDDUP / MOVLHPS instruction. +/// +/// \param __w +/// A double-precision floating-point value used to initialize each vector +/// element of the result. +/// \returns An initialized 128-bit floating-point vector of [2 x double]. +static __inline__ __m128d __DEFAULT_FN_ATTRS +_mm_set_pd1(double __w) +{ + return _mm_set1_pd(__w); +} + /// \brief Constructs a 128-bit floating-point vector of [2 x double] /// initialized with the specified double-precision floating-point values. /// diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index 3f2fcbc..c488153 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -255,19 +255,16 @@ typedef __uint_least8_t uint_fast8_t; */ #define __stdint_join3(a,b,c) a ## b ## c -#define __intn_t(n) __stdint_join3( int, n, _t) -#define __uintn_t(n) __stdint_join3(uint, n, _t) - #ifndef _INTPTR_T #ifndef __intptr_t_defined -typedef __intn_t(__INTPTR_WIDTH__) intptr_t; +typedef __INTPTR_TYPE__ intptr_t; #define __intptr_t_defined #define _INTPTR_T #endif #endif #ifndef _UINTPTR_T -typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; #define _UINTPTR_T #endif @@ -659,12 +656,12 @@ typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ -#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__) -#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__) -#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__) -#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__) -#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__) -#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__) +#define INTPTR_MIN (-__INTPTR_MAX__-1) +#define INTPTR_MAX __INTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1) +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ /* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ * is enabled. */ @@ -673,9 +670,9 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* C99 7.18.2.5 Limits of greatest-width integer types. */ -#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__) -#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__) -#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__) +#define INTMAX_MIN (-__INTMAX_MAX__-1) +#define INTMAX_MAX __INTMAX_MAX__ +#define UINTMAX_MAX __UINTMAX_MAX__ /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) @@ -700,8 +697,8 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v) -#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v) +#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__) +#define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__) #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index c1eed16..e8b2f10 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -481,17 +481,17 @@ public: return true; assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); + SymbolRoleSet AccessorMethodRoles = + SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) - IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, - Container); + IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) - IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, - Container); + IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { if (IvarD->getSynthesize()) { diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp index ed469f6..044edf7 100644 --- a/lib/Index/USRGeneration.cpp +++ b/lib/Index/USRGeneration.cpp @@ -811,7 +811,13 @@ void USRGenerator::VisitType(QualType T) { T = InjT->getInjectedSpecializationType(); continue; } - + if (const auto *VT = T->getAs()) { + Out << (T->isExtVectorType() ? ']' : '['); + Out << VT->getNumElements(); + T = VT->getElementType(); + continue; + } + // Unhandled type. Out << ' '; break; diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 4ee3871..bd425a0 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -624,7 +624,10 @@ const FileEntry *HeaderSearch::LookupFile( ArrayRef> Includers, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache, bool BuildSystemModule) { + bool *IsMapped, bool SkipCache, bool BuildSystemModule) { + if (IsMapped) + *IsMapped = false; + if (SuggestedModule) *SuggestedModule = ModuleMap::KnownHeader(); @@ -754,8 +757,11 @@ const FileEntry *HeaderSearch::LookupFile( if (!SkipCache && CacheLookup.StartIdx == i+1) { // Skip querying potentially lots of directories for this lookup. i = CacheLookup.HitIdx; - if (CacheLookup.MappedName) + if (CacheLookup.MappedName) { Filename = CacheLookup.MappedName; + if (IsMapped) + *IsMapped = true; + } } else { // Otherwise, this is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime the @@ -776,6 +782,8 @@ const FileEntry *HeaderSearch::LookupFile( if (HasBeenMapped) { CacheLookup.MappedName = copyString(Filename, LookupFileCache.getAllocator()); + if (IsMapped) + *IsMapped = true; } if (!FE) continue; @@ -839,7 +847,7 @@ const FileEntry *HeaderSearch::LookupFile( const FileEntry *FE = LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, Includers.front(), SearchPath, RelativePath, - RequestingModule, SuggestedModule); + RequestingModule, SuggestedModule, IsMapped); if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { if (SuggestedModule) diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index 924613d..bec4340 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -33,7 +33,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) UsedForHeaderGuard(false) { } -unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { +unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const { assert(!IsDefinitionLengthCached); IsDefinitionLengthCached = true; diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 8a56ddf..4826e39 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -752,16 +752,11 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc, } const FileEntry *Preprocessor::LookupFile( - SourceLocation FilenameLoc, - StringRef Filename, - bool isAngled, - const DirectoryLookup *FromDir, - const FileEntry *FromFile, - const DirectoryLookup *&CurDir, - SmallVectorImpl *SearchPath, + SourceLocation FilenameLoc, StringRef Filename, bool isAngled, + const DirectoryLookup *FromDir, const FileEntry *FromFile, + const DirectoryLookup *&CurDir, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache) { + ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool SkipCache) { Module *RequestingModule = getModuleForLocation(FilenameLoc); bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc); @@ -819,7 +814,7 @@ const FileEntry *Preprocessor::LookupFile( while (const FileEntry *FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir, Includers, SearchPath, RelativePath, RequestingModule, - SuggestedModule, SkipCache)) { + SuggestedModule, /*IsMapped=*/nullptr, SkipCache)) { // Keep looking as if this file did a #include_next. TmpFromDir = TmpCurDir; ++TmpFromDir; @@ -835,7 +830,7 @@ const FileEntry *Preprocessor::LookupFile( // Do a standard file entry lookup. const FileEntry *FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath, - RelativePath, RequestingModule, SuggestedModule, SkipCache, + RelativePath, RequestingModule, SuggestedModule, IsMapped, SkipCache, BuildSystemModule); if (FE) { if (SuggestedModule && !LangOpts.AsmPreprocessor) @@ -1593,18 +1588,18 @@ bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer, } /// \brief Push a token onto the token stream containing an annotation. -static void EnterAnnotationToken(Preprocessor &PP, - SourceLocation Begin, SourceLocation End, - tok::TokenKind Kind, void *AnnotationVal) { +void Preprocessor::EnterAnnotationToken(SourceRange Range, + tok::TokenKind Kind, + void *AnnotationVal) { // FIXME: Produce this as the current token directly, rather than // allocating a new token for it. auto Tok = llvm::make_unique(1); Tok[0].startToken(); Tok[0].setKind(Kind); - Tok[0].setLocation(Begin); - Tok[0].setAnnotationEndLoc(End); + Tok[0].setLocation(Range.getBegin()); + Tok[0].setAnnotationEndLoc(Range.getEnd()); Tok[0].setAnnotationValue(AnnotationVal); - PP.EnterTokenStream(std::move(Tok), 1, true); + EnterTokenStream(std::move(Tok), 1, true); } /// \brief Produce a diagnostic informing the user that a #include or similar @@ -1783,6 +1778,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } // Search include directories. + bool IsMapped = false; const DirectoryLookup *CurDir; SmallString<1024> SearchPath; SmallString<1024> RelativePath; @@ -1801,7 +1797,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, LookupFrom, LookupFromFile, CurDir, Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr, - &SuggestedModule); + &SuggestedModule, &IsMapped); if (!File) { if (Callbacks) { @@ -1818,7 +1814,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, LookupFrom, LookupFromFile, CurDir, nullptr, nullptr, - &SuggestedModule, /*SkipCache*/ true); + &SuggestedModule, &IsMapped, /*SkipCache*/ true); } } } @@ -1833,8 +1829,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false, LookupFrom, LookupFromFile, CurDir, Callbacks ? &SearchPath : nullptr, - Callbacks ? &RelativePath : nullptr, - &SuggestedModule); + Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped); if (File) { SourceRange Range(FilenameTok.getLocation(), CharEnd); Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) << @@ -1964,7 +1959,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // Issue a diagnostic if the name of the file on disk has a different case // than the one we're about to open. const bool CheckIncludePathPortability = - File && !File->tryGetRealPathName().empty(); + !IsMapped && File && !File->tryGetRealPathName().empty(); if (CheckIncludePathPortability) { StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename; @@ -2026,7 +2021,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, if (IncludeTok.getIdentifierInfo()->getPPKeywordID() != tok::pp___include_macros) - EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, M); + EnterAnnotationToken(SourceRange(HashLoc, End), + tok::annot_module_include, M); } return; } @@ -2064,7 +2060,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // submodule. // FIXME: There's no point doing this if we're handling a #__include_macros // directive. - EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, M); + EnterAnnotationToken(SourceRange(HashLoc, End), tok::annot_module_begin, M); } } @@ -2592,25 +2588,26 @@ void Preprocessor::HandleUndefDirective() { // Okay, we have a valid identifier to undef. auto *II = MacroNameTok.getIdentifierInfo(); auto MD = getMacroDefinition(II); + UndefMacroDirective *Undef = nullptr; + + // If the macro is not defined, this is a noop undef. + if (const MacroInfo *MI = MD.getMacroInfo()) { + if (!MI->isUsed() && MI->isWarnIfUnused()) + Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); + + if (MI->isWarnIfUnused()) + WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + + Undef = AllocateUndefMacroDirective(MacroNameTok.getLocation()); + } // If the callbacks want to know, tell them about the macro #undef. // Note: no matter if the macro was defined or not. if (Callbacks) - Callbacks->MacroUndefined(MacroNameTok, MD); - - // If the macro is not defined, this is a noop undef, just return. - const MacroInfo *MI = MD.getMacroInfo(); - if (!MI) - return; - - if (!MI->isUsed() && MI->isWarnIfUnused()) - Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); - - if (MI->isWarnIfUnused()) - WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + Callbacks->MacroUndefined(MacroNameTok, MD, Undef); - appendMacroDirective(MacroNameTok.getIdentifierInfo(), - AllocateUndefMacroDirective(MacroNameTok.getLocation())); + if (Undef) + appendMacroDirective(II, Undef); } //===----------------------------------------------------------------------===// diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index cf0c953..fcc49b3 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -287,6 +287,48 @@ const char *Preprocessor::getCurLexerEndPos() { return EndPos; } +static void collectAllSubModulesWithUmbrellaHeader( + const Module &Mod, SmallVectorImpl &SubMods) { + if (Mod.getUmbrellaHeader()) + SubMods.push_back(&Mod); + for (auto *M : Mod.submodules()) + collectAllSubModulesWithUmbrellaHeader(*M, SubMods); +} + +void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) { + assert(Mod.getUmbrellaHeader() && "Module must use umbrella header"); + SourceLocation StartLoc = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc)) + return; + + ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap(); + const DirectoryEntry *Dir = Mod.getUmbrellaDir().Entry; + vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); + std::error_code EC; + for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End; + Entry != End && !EC; Entry.increment(EC)) { + using llvm::StringSwitch; + + // Check whether this entry has an extension typically associated with + // headers. + if (!StringSwitch(llvm::sys::path::extension(Entry->getName())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + if (const FileEntry *Header = getFileManager().getFile(Entry->getName())) + if (!getSourceManager().hasFileInfo(Header)) { + if (!ModMap.isHeaderInUnavailableModule(Header)) { + // Find the relative path that would access this header. + SmallString<128> RelativePath; + computeRelativePath(FileMgr, Dir, Header, RelativePath); + Diag(StartLoc, diag::warn_uncovered_module_header) + << Mod.getFullModuleName() << RelativePath; + } + } + } +} /// HandleEndOfFile - This callback is invoked when the lexer hits the end of /// the current file. This either returns the EOF token or pops a level off @@ -473,44 +515,14 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { } // If we are building a module that has an umbrella header, make sure that - // each of the headers within the directory covered by the umbrella header - // was actually included by the umbrella header. + // each of the headers within the directory, including all submodules, is + // covered by the umbrella header was actually included by the umbrella + // header. if (Module *Mod = getCurrentModule()) { - if (Mod->getUmbrellaHeader()) { - SourceLocation StartLoc - = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); - - if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header, - StartLoc)) { - ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap(); - const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry; - vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); - std::error_code EC; - for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End; - Entry != End && !EC; Entry.increment(EC)) { - using llvm::StringSwitch; - - // Check whether this entry has an extension typically associated with - // headers. - if (!StringSwitch(llvm::sys::path::extension(Entry->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) - continue; - - if (const FileEntry *Header = - getFileManager().getFile(Entry->getName())) - if (!getSourceManager().hasFileInfo(Header)) { - if (!ModMap.isHeaderInUnavailableModule(Header)) { - // Find the relative path that would access this header. - SmallString<128> RelativePath; - computeRelativePath(FileMgr, Dir, Header, RelativePath); - Diag(StartLoc, diag::warn_uncovered_module_header) - << Mod->getFullModuleName() << RelativePath; - } - } - } - } - } + llvm::SmallVector AllMods; + collectAllSubModulesWithUmbrellaHeader(*Mod, AllMods); + for (auto *M : AllMods) + diagnoseMissingHeaderInUmbrellaDir(*M); } return true; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 358c96a..1962239 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1422,7 +1422,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, const DirectoryLookup *CurDir; const FileEntry *File = PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile, - CurDir, nullptr, nullptr, nullptr); + CurDir, nullptr, nullptr, nullptr, nullptr); // Get the result value. A result of true means the file exists. return File != nullptr; diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 87e105d..576151a 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -508,7 +508,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { const DirectoryLookup *CurDir; const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, - nullptr, CurDir, nullptr, nullptr, nullptr); + nullptr, CurDir, nullptr, nullptr, nullptr, nullptr); if (!File) { if (!SuppressIncludeNotFoundError) Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; @@ -534,6 +534,47 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } +void Preprocessor::HandlePragmaModuleImport(Token &ImportTok) { + SourceLocation ImportLoc = ImportTok.getLocation(); + + Token Tok; + + llvm::SmallVector, 8> ModuleName; + while (true) { + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), + diag::err_pragma_module_import_expected_module_name) << 0; + return; + } + + ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation()); + + LexUnexpandedToken(Tok); + assert(Tok.isNot(tok::eof)); + if (Tok.is(tok::eod)) + break; + if (Tok.isNot(tok::period)) { + Diag(Tok.getLocation(), + diag::err_pragma_module_import_expected_module_name) << 1; + return; + } + } + + // If we have a non-empty module path, load the named module. + Module *Imported = + TheModuleLoader.loadModule(ImportLoc, ModuleName, Module::Hidden, + /*IsIncludeDirective=*/false); + if (!Imported) + return; + + makeModuleVisible(Imported, ImportLoc); + EnterAnnotationToken(SourceRange(ImportLoc, Tok.getLocation()), + tok::annot_module_include, Imported); + if (Callbacks) + Callbacks->moduleImport(ImportLoc, ModuleName, Imported); +} + /// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { @@ -1301,6 +1342,19 @@ public: } }; +/// Handle the clang \#pragma module import extension. The syntax is: +/// \code +/// #pragma clang module import some.module.name +/// \endcode +struct PragmaModuleImportHandler : public PragmaHandler { + PragmaModuleImportHandler() : PragmaHandler("import") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &ImportTok) override { + PP.HandlePragmaModuleImport(ImportTok); + } +}; + /// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the /// macro on the top of the stack. struct PragmaPushMacroHandler : public PragmaHandler { @@ -1524,6 +1578,11 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); + // #pragma clang module ... + auto *ModuleHandler = new PragmaNamespace("module"); + AddPragmaHandler("clang", ModuleHandler); + ModuleHandler->AddPragma(new PragmaModuleImportHandler()); + AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler()); AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler()); AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler()); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 13e15f3..03c4cbe 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -422,7 +422,8 @@ void PreprocessingRecord::MacroDefined(const Token &Id, } void PreprocessingRecord::MacroUndefined(const Token &Id, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); }); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 044ec74..b3ba86e 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -9866,25 +9866,6 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { ::CheckBoolLikeConversion(*this, E, CC); } -/// Diagnose when expression is an integer constant expression and its evaluation -/// results in integer overflow -void Sema::CheckForIntOverflow (Expr *E) { - // Use a work list to deal with nested struct initializers. - SmallVector Exprs(1, E); - - do { - Expr *E = Exprs.pop_back_val(); - - if (isa(E->IgnoreParenCasts())) { - E->IgnoreParenCasts()->EvaluateForOverflow(Context); - continue; - } - - if (auto InitList = dyn_cast(E)) - Exprs.append(InitList->inits().begin(), InitList->inits().end()); - } while (!Exprs.empty()); -} - namespace { /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. @@ -10386,7 +10367,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) - CheckForIntOverflow(E); + E->EvaluateForOverflow(Context); DiagnoseMisalignedMembers(); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f838c9a..054ccb6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2960,6 +2960,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, RequiresAdjustment = true; } + if (OldTypeInfo.getNoCallerSavedRegs() != + NewTypeInfo.getNoCallerSavedRegs()) { + if (NewTypeInfo.getNoCallerSavedRegs()) { + AnyX86NoCallerSavedRegistersAttr *Attr = + New->getAttr(); + Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr; + Diag(OldLocation, diag::note_previous_declaration); + return true; + } + + NewTypeInfo = NewTypeInfo.withNoCallerSavedRegs(true); + RequiresAdjustment = true; + } + if (RequiresAdjustment) { const FunctionType *AdjustedType = New->getType()->getAs(); AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo); @@ -7410,6 +7424,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback { } // end anonymous namespace +void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { + TypoCorrectedFunctionDefinitions.insert(F); +} + /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid @@ -7507,6 +7525,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( if ((*I)->getCanonicalDecl() == Canonical) Correction.setCorrectionDecl(*I); + // Let Sema know about the correction. + SemaRef.MarkTypoCorrectedFunctionDefinition(Result); SemaRef.diagnoseTypo( Correction, SemaRef.PDiag(IsLocalFriend @@ -11718,6 +11738,11 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, if (canRedefineFunction(Definition, getLangOpts())) return; + // Don't emit an error when this is redifinition of a typo-corrected + // definition. + if (TypoCorrectedFunctionDefinitions.count(Definition)) + return; + // If we don't have a visible definition of the function, and it's inline or // a template, skip the new definition. if (SkipBody && !hasVisibleDefinition(Definition) && diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 17c6975..bb5434a 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1941,17 +1941,26 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(attr)) return; + if (S.CheckNoReturnAttr(attr)) + return; if (!isa(D)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedFunctionOrMethod; + << attr.getName() << ExpectedFunctionOrMethod; return; } - D->addAttr(::new (S.Context) - NoReturnAttr(attr.getRange(), S.Context, - attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoReturnAttr( + attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); +} + +static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (S.CheckNoCallerSavedRegsAttr(Attr)) + return; + + D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { @@ -1963,6 +1972,22 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) { return false; } +bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { + // Check whether the attribute is valid on the current target. + if (!Attr.existsInTarget(Context.getTargetInfo())) { + Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); + Attr.setInvalid(); + return true; + } + + if (!checkAttributeNumArgs(*this, Attr, 0)) { + Attr.setInvalid(); + return true; + } + + return false; +} + static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -6428,6 +6453,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; + case AttributeList::AT_AnyX86NoCallerSavedRegisters: + handleNoCallerSavedRegsAttr(S, D, Attr); + break; case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute(S, D, Attr); break; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 4f51cd3..fe9ba6f 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -4313,6 +4313,51 @@ static void mergeInterfaceMethodToImpl(Sema &S, } } +/// Verify that the method parameters/return value have types that are supported +/// by the x86 target. +static void checkObjCMethodX86VectorTypes(Sema &SemaRef, + const ObjCMethodDecl *Method) { + assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() == + llvm::Triple::x86 && + "x86-specific check invoked for a different target"); + SourceLocation Loc; + QualType T; + for (const ParmVarDecl *P : Method->parameters()) { + if (P->getType()->isVectorType()) { + Loc = P->getLocStart(); + T = P->getType(); + break; + } + } + if (Loc.isInvalid()) { + if (Method->getReturnType()->isVectorType()) { + Loc = Method->getReturnTypeSourceRange().getBegin(); + T = Method->getReturnType(); + } else + return; + } + + // Vector parameters/return values are not supported by objc_msgSend on x86 in + // iOS < 9 and macOS < 10.11. + const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple(); + VersionTuple AcceptedInVersion; + if (Triple.getOS() == llvm::Triple::IOS) + AcceptedInVersion = VersionTuple(/*Major=*/9); + else if (Triple.isMacOSX()) + AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11); + else + return; + VersionTuple MethodVersion = Method->getVersionIntroduced(); + if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >= + AcceptedInVersion && + (MethodVersion.empty() || MethodVersion >= AcceptedInVersion)) + return; + SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type) + << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1 + : /*parameter*/ 0) + << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, @@ -4534,6 +4579,10 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethod->SetRelatedResultType(); } + if (MethodDefinition && + Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) + checkObjCMethodX86VectorTypes(*this, ObjCMethod); + ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 00480f8..f7307f3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5275,8 +5275,7 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic for if there'Scope an '&' - // involved. + // We aren't supposed to apply this logic if there's an '&' involved. if (!find.HasFormOfMemberPointer) { OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast(ovl)) @@ -6432,14 +6431,13 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return S.Context .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals) .withCVRQualifiers(MergedCVRQual); - } else - return CompositeTy.withCVRQualifiers(MergedCVRQual); + } + return CompositeTy.withCVRQualifiers(MergedCVRQual); }(); if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); - else { + else ResultTy = S.Context.getPointerType(ResultTy); - } LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 9cc443e..a44e924 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -595,7 +595,6 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { break; } } - CheckForIntOverflow(ValueExpr); // FIXME: Do I need to do anything special with BoolTy expressions? // Look for the appropriate method within NSNumber. diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index fb13669..43fd055 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -824,21 +824,18 @@ DSAStackTy::hasDSA(ValueDecl *D, if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.back().first.rbegin()); + auto I = (FromParent && Stack.back().first.size() > 1) + ? std::next(Stack.back().first.rbegin()) + : Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); - if (FromParent && StartI != EndI) - StartI = std::next(StartI); - if (StartI == EndI) - return {}; - auto I = std::prev(StartI); - do { - ++I; + while (std::distance(I, EndI) > 1) { + std::advance(I, 1); if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; DSAVarData DVar = getDSA(I, D); if (CPred(DVar.CKind)) return DVar; - } while (I != EndI); + } return {}; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 29ba344..782c377 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11426,6 +11426,10 @@ static void AddOverloadedCallCandidate(Sema &S, assert(!KnownValid && "Explicit template arguments?"); return; } + // Prevent ill-formed function decls to be added as overload candidates. + if (!dyn_cast(Func->getType()->getAs())) + return; + S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet, /*SuppressUsedConversions=*/false, PartialOverloading); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 279b9ec..bcc66bb 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -119,8 +119,9 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_NoReturn: \ - case AttributeList::AT_Regparm: \ + case AttributeList::AT_NoReturn: \ + case AttributeList::AT_Regparm: \ + case AttributeList::AT_AnyX86NoCallerSavedRegisters: \ CALLING_CONV_ATTRS_CASELIST // Microsoft-specific type qualifiers. @@ -6371,6 +6372,20 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } + if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) { + if (S.CheckNoCallerSavedRegsAttr(attr)) + return true; + + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + + FunctionType::ExtInfo EI = + unwrapped.get()->getExtInfo().withNoCallerSavedRegs(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + if (attr.getKind() == AttributeList::AT_Regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 7b1edc0..5312ad1 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3765,6 +3765,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, SourceMgr.getLoadedSLocEntryByID(Index); } + // Map the original source file ID into the ID space of the current + // compilation. + if (F.OriginalSourceFileID.isValid()) { + F.OriginalSourceFileID = FileID::get( + F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1); + } + // Preload all the pending interesting identifiers by marking them out of // date. for (auto Offset : F.PreloadIdentifierOffsets) { @@ -3873,10 +3880,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); if (PrimaryModule.OriginalSourceFileID.isValid()) { - PrimaryModule.OriginalSourceFileID - = FileID::get(PrimaryModule.SLocEntryBaseID - + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); - // If this AST file is a precompiled preamble, then set the // preamble file ID of the source manager to the file source file // from which the preamble was built. @@ -5575,6 +5578,13 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { FirstState = ReadDiagState( F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState, SourceLocation(), F.isModule()); + + // For an explicit module, set up the root buffer of the module to start + // with the initial diagnostic state of the module itself, to cover files + // that contain no explicit transitions. + if (F.isModule()) + Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID] + .StateTransitions.push_back({FirstState, 0}); } // Read the state transitions. @@ -5801,13 +5811,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) { } case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 6) { + if (Record.size() != 7) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = readType(*Loc.F, Record, Idx); FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], - (CallingConv)Record[4], Record[5]); + (CallingConv)Record[4], Record[5], Record[6]); return Context.getFunctionNoProtoType(ResultType, Info); } @@ -5819,9 +5829,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) { /*hasregparm*/ Record[2], /*regparm*/ Record[3], static_cast(Record[4]), - /*produces*/ Record[5]); + /*produces*/ Record[5], + /*nocallersavedregs*/ Record[6]); - unsigned Idx = 6; + unsigned Idx = 7; EPI.Variadic = Record[Idx++]; EPI.HasTrailingReturn = Record[Idx++]; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 84d2420..80bf656 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -255,6 +255,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { // FIXME: need to stabilize encoding of calling convention... Record.push_back(C.getCC()); Record.push_back(C.getProducesResult()); + Record.push_back(C.getNoCallerSavedRegs()); if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult()) AbbrevToUse = 0; @@ -839,6 +840,7 @@ void ASTWriter::WriteTypeAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // RegParm Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult + Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs // FunctionProtoType Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 5730517..9a7e83c 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -401,6 +401,9 @@ private: void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range, SymbolRef Sym) const; + void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, const Expr *FreeExpr) const; + /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, @@ -1564,6 +1567,11 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, } } + if (SymBase->getType()->isFunctionPointerType()) { + ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); + return nullptr; + } + ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero()); @@ -2024,10 +2032,45 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, } } +void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, + const Expr *FreeExpr) const { + if (!ChecksEnabled[CK_MallocChecker]) + return; + + Optional CheckKind = getCheckIfTracked(C, FreeExpr); + if (!CheckKind.hasValue()) + return; + + if (ExplodedNode *N = C.generateErrorNode()) { + if (!BT_BadFree[*CheckKind]) + BT_BadFree[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); + + SmallString<100> Buf; + llvm::raw_svector_ostream Os(Buf); + + const MemRegion *MR = ArgVal.getAsRegion(); + while (const ElementRegion *ER = dyn_cast_or_null(MR)) + MR = ER->getSuperRegion(); + + Os << "Argument to "; + if (!printAllocDeallocName(Os, C, FreeExpr)) + Os << "deallocator"; + + Os << " is a function pointer"; + + auto R = llvm::make_unique(*BT_BadFree[*CheckKind], Os.str(), N); + R->markInteresting(MR); + R->addRange(Range); + C.emitReport(std::move(R)); + } +} + ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C, const CallExpr *CE, bool FreesOnFail, - ProgramStateRef State, + ProgramStateRef State, bool SuffixWithN) const { if (!State) return nullptr; diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index c6f3baa..cdb1ed9 100644 --- a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -65,7 +65,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { auto Invocation = std::make_shared(CI.getInvocation()); FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); - InputKind IK = IK_CXX; // FIXME + InputKind IK = InputKind::CXX; // FIXME FrontendOpts.Inputs.clear(); FrontendOpts.Inputs.emplace_back(fileName, IK); FrontendOpts.DisableFree = true; diff --git a/test/ARCMT/remap-applying.c b/test/ARCMT/remap-applying.c new file mode 100644 index 0000000..dee2e39 --- /dev/null +++ b/test/ARCMT/remap-applying.c @@ -0,0 +1,4 @@ +a bc + +// RUN: echo "[{\"file\": \"%/s\", \"offset\": 1, \"remove\": 2, }]" > %t.remap +// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result diff --git a/test/ARCMT/remap-applying.c.result b/test/ARCMT/remap-applying.c.result new file mode 100644 index 0000000..514e9c2 --- /dev/null +++ b/test/ARCMT/remap-applying.c.result @@ -0,0 +1,4 @@ +ac + +// RUN: echo "[{\"file\": \"%/s\", \"offset\": 1, \"remove\": 2, }]" > %t.remap +// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index d5f2cfe..4c364eb 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -1774,6 +1774,16 @@ int testNoCheckerDataPropogationFromLogicalOpOperandToOpResult(void) { return ok; // no warning } +void (*fnptr)(int); +void freeIndirectFunctionPtr() { + void *p = (void *)fnptr; + free(p); // expected-warning {{Argument to free() is a function pointer}} +} + +void freeFunctionPtr() { + free((void *)fnptr); // expected-warning {{Argument to free() is a function pointer}} +} + // ---------------------------------------------------------------------------- // False negatives. diff --git a/test/CodeGen/atomic-ops-libcall.c b/test/CodeGen/atomic-ops-libcall.c index 0093a8c..c673b07 100644 --- a/test/CodeGen/atomic-ops-libcall.c +++ b/test/CodeGen/atomic-ops-libcall.c @@ -1,5 +1,8 @@ // RUN: %clang_cc1 < %s -triple armv5e-none-linux-gnueabi -emit-llvm -O1 | FileCheck %s +// FIXME: This file should not be checking -O1 output. +// Ie, it is testing many IR optimizer passes as part of front-end verification. + enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst @@ -110,7 +113,8 @@ int test_atomic_xor_fetch(int *p) { int test_atomic_nand_fetch(int *p) { // CHECK: test_atomic_nand_fetch // 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 + // FIXME: We should not be checking optimized IR. It changes independently of clang. + // FIXME-CHECK: [[AND:%[^ ]*]] = and i32 [[CALL]], 55 + // FIXME-CHECK: {{%[^ ]*}} = xor i32 [[AND]], -1 return __atomic_nand_fetch(p, 55, memory_order_seq_cst); } diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c index 4832664..90f428e 100644 --- a/test/CodeGen/avx-builtins.c +++ b/test/CodeGen/avx-builtins.c @@ -1386,6 +1386,27 @@ void test_mm256_zeroupper() { return _mm256_zeroupper(); } +__m256d test_mm256_zextpd128_pd256(__m128d A) { + // CHECK-LABEL: test_mm256_zextpd128_pd256 + // CHECK: store <2 x double> zeroinitializer + // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> + return _mm256_zextpd128_pd256(A); +} + +__m256 test_mm256_zextps128_ps256(__m128 A) { + // CHECK-LABEL: test_mm256_zextps128_ps256 + // CHECK: store <4 x float> zeroinitializer + // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> + return _mm256_zextps128_ps256(A); +} + +__m256i test_mm256_zextsi128_si256(__m128i A) { + // CHECK-LABEL: test_mm256_zextsi128_si256 + // CHECK: store <2 x i64> zeroinitializer + // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> + return _mm256_zextsi128_si256(A); +} + double test_mm256_cvtsd_f64(__m256d __a) { // CHECK-LABEL: @test_mm256_cvtsd_f64 diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c index 3ae8014..c66d836 100644 --- a/test/CodeGen/avx512f-builtins.c +++ b/test/CodeGen/avx512f-builtins.c @@ -8387,3 +8387,44 @@ __m512 test_mm512_mask_abs_ps(__m512 __W, __mmask16 __U, __m512 __A){ return _mm512_mask_abs_ps( __W, __U, __A); } +__m512d test_mm512_zextpd128_pd512(__m128d A) { + // CHECK-LABEL: test_mm512_zextpd128_pd512 + // CHECK: store <2 x double> zeroinitializer + // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <8 x i32> + return _mm512_zextpd128_pd512(A); +} + +__m512d test_mm512_zextpd256_pd512(__m256d A) { + // CHECK-LABEL: test_mm512_zextpd256_pd512 + // CHECK: store <4 x double> zeroinitializer + // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <8 x i32> + return _mm512_zextpd256_pd512(A); +} + +__m512 test_mm512_zextps128_ps512(__m128 A) { + // CHECK-LABEL: test_mm512_zextps128_ps512 + // CHECK: store <4 x float> zeroinitializer + // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <16 x i32> + return _mm512_zextps128_ps512(A); +} + +__m512 test_mm512_zextps256_ps512(__m256 A) { + // CHECK-LABEL: test_mm512_zextps256_ps512 + // CHECK: store <8 x float> zeroinitializer + // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <16 x i32> + return _mm512_zextps256_ps512(A); +} + +__m512i test_mm512_zextsi128_si512(__m128i A) { + // CHECK-LABEL: test_mm512_zextsi128_si512 + // CHECK: store <2 x i64> zeroinitializer + // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <8 x i32> + return _mm512_zextsi128_si512(A); +} + +__m512i test_mm512_zextsi256_si512(__m256i A) { + // CHECK-LABEL: test_mm512_zextsi256_si512 + // CHECK: store <4 x i64> zeroinitializer + // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <8 x i32> + return _mm512_zextsi256_si512(A); +} diff --git a/test/CodeGen/sse2-builtins.c b/test/CodeGen/sse2-builtins.c index a140a6c..ca51314 100644 --- a/test/CodeGen/sse2-builtins.c +++ b/test/CodeGen/sse2-builtins.c @@ -951,6 +951,13 @@ __m128d test_mm_set_pd(double A, double B) { return _mm_set_pd(A, B); } +__m128d test_mm_set_pd1(double A) { + // CHECK-LABEL: test_mm_set_pd1 + // CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 0 + // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1 + return _mm_set_pd1(A); +} + __m128d test_mm_set_sd(double A) { // CHECK-LABEL: test_mm_set_sd // CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 0 diff --git a/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp b/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp new file mode 100644 index 0000000..f583f16 --- /dev/null +++ b/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s + +// CHECK: foo{{[^#]*}}#[[ATTRS:[0-9]+]] +__attribute__((no_caller_saved_registers)) void foo() {} +namespace S { +// CHECK: bar{{[^#]*}}#[[ATTRS]] +__attribute__((no_caller_saved_registers)) void bar(int *a) { foo(); } +} + +struct St { + static void baz(int *a) __attribute__((no_caller_saved_registers)) { S::bar(a); } +}; + +__attribute((no_caller_saved_registers)) void (*foobar)(void); + +// CHECK-LABEL: @main +int main(int argc, char **argv) { + St::baz(&argc); + // CHECK: [[FOOBAR:%.+]] = load void ()*, void ()** @{{.*}}foobar{{.*}}, + // CHECK-NEXT: call void [[FOOBAR]]() #[[ATTRS1:.+]] + foobar(); + return 0; +} + +// CHECK: baz{{[^#]*}}#[[ATTRS]] + +// CHECK: attributes #[[ATTRS]] = { +// CHECK-SAME: "no_caller_saved_registers" +// CHECK-SAME: } +// CHECK: attributes #[[ATTRS1]] = { "no_caller_saved_registers" } diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp index c75c407..5b81197 100644 --- a/test/CodeGenCXX/debug-info-namespace.cpp +++ b/test/CodeGenCXX/debug-info-namespace.cpp @@ -53,24 +53,30 @@ inline namespace I { int var_i; } } -void B::func_fwd() {} +namespace { +int anonymous; +} +void B::func_fwd() { + anonymous = 0; +} + // This should work even if 'i' and 'func' were declarations & not definitions, // but it doesn't yet. // CHECK: [[I:![0-9]+]] = distinct !DIGlobalVariable(name: "i",{{.*}} scope: [[NS:![0-9]+]], -// CHECK: [[NS]] = !DINamespace(name: "B", scope: [[CTXT:![0-9]+]], file: [[FOOCPP:![0-9]+]], line: 1) -// CHECK: [[FOOCPP]] = !DIFile(filename: "foo.cpp" -// CHECK: [[CTXT]] = !DINamespace(name: "A", scope: null, file: [[FILE:![0-9]+]], line: 5) -// CHECK: [[FILE]] = !DIFile(filename: "{{.*}}debug-info-namespace.cpp", +// CHECK: [[NS]] = !DINamespace(name: "B", scope: [[CTXT:![0-9]+]]) +// CHECK: [[CTXT]] = !DINamespace(name: "A", scope: null) +// CHECK: [[FOOCPP:.*]] = !DIFile(filename: "foo.cpp" // CHECK: [[VAR_FWD:![0-9]+]] = distinct !DIGlobalVariable(name: "var_fwd",{{.*}} scope: [[NS]], // CHECK-SAME: line: 44 // CHECK-SAME: isDefinition: true // CHECK: distinct !DIGlobalVariable(name: "var_i",{{.*}} scope: [[INLINE:![0-9]+]], -// CHECK: [[INLINE]] = !DINamespace(name: "I", scope: [[CTXT]], file: [[FOOCPP]], line: 46, exportSymbols: true) +// CHECK: [[INLINE]] = !DINamespace(name: "I", scope: [[CTXT]], exportSymbols: true) +// CHECK: !DINamespace(scope: null) // CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit( // CHECK-SAME: imports: [[MODULES:![0-9]*]] -// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]} +// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]] // CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], line: 15) // CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]], @@ -106,7 +112,7 @@ void B::func_fwd() {} // CHECK-SAME: scope: [[NS]], file: [[FOOCPP]], line: 9 // CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]] // CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]] -// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 50,{{.*}} isDefinition: true +// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} isDefinition: true // CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]] // CHECK-GMLT: [[CU:![0-9]+]] = distinct !DICompileUnit( diff --git a/test/CodeGenCXX/ubsan-nullability-assign.cpp b/test/CodeGenCXX/ubsan-nullability-assign.cpp new file mode 100644 index 0000000..3f85c88 --- /dev/null +++ b/test/CodeGenCXX/ubsan-nullability-assign.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=nullability-assign | FileCheck %s + +struct S1 { + int *_Nonnull p; +}; + +struct S2 { + S1 s1; +}; + +union U1 { + S1 s1; + S2 s2; +}; + +// CHECK-LABEL: define void @{{.*}}f1 +void f1(int *p) { + U1 u; + + // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize + // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize + // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize + // CHECK: store + u.s1.p = p; + + // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize + // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize + // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize + // CHECK: store + u.s2.s1.p = p; + + // CHECK-NOT: __ubsan_handle_type_mismatch + // CHECK-NOT: store + // CHECK: ret void +} diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index 4bb618c..69cd7bb 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -298,15 +298,11 @@ void test7(void) { // CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[SELF]], -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* -// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) -// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]* -// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]] +// CHECK-NEXT: store %0* [[T1]], %0** [[T0]] // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK: call void @test8_helper( -// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]] -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T2]]) +// CHECK-NEXT: [[T2:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]] +// CHECK-NEXT: call void (...) @clang.arc.use([[TEST8]]* [[T2]]) // CHECK: ret void extern void test8_helper(void (^)(void)); @@ -741,5 +737,31 @@ void test19(void (^b)(void)) { // CHECK-NEXT: ret void } +// CHECK-LABEL: define void @test20( +// CHECK: [[XADDR:%.*]] = alloca i8* +// CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]> +// CHECK-NEXT: [[RETAINEDX:%.*]] = call i8* @objc_retain(i8* %{{.*}}) +// CHECK-NEXT: store i8* [[RETAINEDX]], i8** [[XADDR]] +// CHECK-NEXT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 +// CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 +// CHECK: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]] +// CHECK: store i8* [[CAPTURED]], i8** [[BLOCKCAPTURED]] +// CHECK: [[CAPTURE:%.*]] = load i8*, i8** [[CAPTUREFIELD]] +// CHECK-NEXT: call void (...) @clang.arc.use(i8* [[CAPTURE]]) +// CHECK-NEXT: [[X:%.*]] = load i8*, i8** [[XADDR]] +// CHECK-NEXT: call void @objc_release(i8* [[X]]) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define internal void @__copy_helper_block +// CHECK: [[BLOCKSOURCE:%.*]] = bitcast i8* %{{.*}} to <[[BLOCKTY]]>* +// CHECK: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCKSOURCE]], i32 0, i32 5 +// CHECK: [[BLOCKCOPYSRC:%.*]] = load i8*, i8** [[CAPTUREFIELD]] +// CHECK: call i8* @objc_retain(i8* [[BLOCKCOPYSRC]]) + +void test20_callee(void (^)()); +void test20(const id x) { + test20_callee(^{ (void)x; }); +} + // CHECK: attributes [[NUW]] = { nounwind } // CHECK-UNOPT: attributes [[NUW]] = { nounwind } diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index db150e8..e344457 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -63,11 +63,11 @@ void test0(NSArray *array) { // CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8*, i8** [[X]] -// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) -// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]] -// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] -// CHECK-LP64: call void @use_block( -// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null) +// CHECK-LP64-NEXT: store i8* [[T1]], i8** [[T0]] +// CHECK-LP64-NEXT: [[BLOCK1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] +// CHECK-LP64-NEXT: call void @use_block(void ()* [[BLOCK1]]) +// CHECK-LP64-NEXT: [[CAPTURE:%.*]] = load i8*, i8** [[D0]] +// CHECK-LP64: call void (...) @clang.arc.use(i8* [[CAPTURE]]) // CHECK-LP64: [[T0:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8* @@ -200,13 +200,10 @@ NSArray *array4; // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[BC:%.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T1:%.*]] = load [[TY]]*, [[TY]]** [[SELF_ADDR]] -// CHECK-LP64: [[T2:%.*]] = bitcast [[TY]]* [[T1]] to i8* -// CHECK-LP64: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) -// CHECK-LP64: [[T4:%.*]] = bitcast i8* [[T3]] to [[TY]]* -// CHECK-LP64: store [[TY]]* [[T4]], [[TY]]** [[BC]] +// CHECK-LP64: store [[TY]]* [[T1]], [[TY]]** [[BC]] -// CHECK-LP64: [[T5:%.*]] = bitcast [[TY]]** [[T0]] to i8** -// CHECK-LP64: call void @objc_storeStrong(i8** [[T5]], i8* null) +// CHECK-LP64: [[T5:%.*]] = load [[TY]]*, [[TY]]** [[T0]] +// CHECK-LP64: call void (...) @clang.arc.use([[TY]]* [[T5]]) // CHECK-LP64: switch i32 {{%.*}}, label %[[UNREACHABLE:.*]] [ // CHECK-LP64-NEXT: i32 0, label %[[CLEANUP_CONT:.*]] // CHECK-LP64-NEXT: i32 2, label %[[FORCOLL_END:.*]] diff --git a/test/CodeGenObjC/ubsan-nullability.m b/test/CodeGenObjC/ubsan-nullability.m index 457f071..7f53ea6 100644 --- a/test/CodeGenObjC/ubsan-nullability.m +++ b/test/CodeGenObjC/ubsan-nullability.m @@ -1,19 +1,22 @@ // REQUIRES: asserts // RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s +// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s // CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 109, i32 1 {{.*}} i32 100, i32 6 // CHECK: [[NONNULL_ARG_LOC:@.*]] = private unnamed_addr global {{.*}} i32 204, i32 15 {{.*}} i32 190, i32 23 // CHECK: [[NONNULL_ASSIGN1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 305, i32 9 // CHECK: [[NONNULL_ASSIGN2_LOC:@.*]] = private unnamed_addr global {{.*}} i32 405, i32 10 -// CHECK: [[NONNULL_ASSIGN3_LOC:@.*]] = private unnamed_addr global {{.*}} i32 505, i32 10 +// CHECK: [[NONNULL_ASSIGN3_LOC:@.*]] = private unnamed_addr global {{.*}} i32 506, i32 10 // CHECK: [[NONNULL_INIT1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 604, i32 25 // CHECK: [[NONNULL_INIT2_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 26 // CHECK: [[NONNULL_INIT2_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 29 // CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 817, i32 1 {{.*}} i32 800, i32 6 #define NULL ((void *)0) +#define INULL ((int *)NULL) +#define INNULL ((int *_Nonnull)NULL) -// CHECK-LABEL: define i32* @nonnull_retval1 +// CHECK-LABEL: define i32* @{{.*}}nonnull_retval1 #line 100 int *_Nonnull nonnull_retval1(int *p) { // CHECK: br i1 true, label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize @@ -29,7 +32,7 @@ int *_Nonnull nonnull_retval1(int *p) { #line 190 void nonnull_arg(int *_Nonnull p) {} -// CHECK-LABEL: define void @call_func_with_nonnull_arg +// CHECK-LABEL: define void @{{.*}}call_func_with_nonnull_arg #line 200 void call_func_with_nonnull_arg(int *_Nonnull p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize @@ -38,7 +41,7 @@ void call_func_with_nonnull_arg(int *_Nonnull p) { nonnull_arg(p); } -// CHECK-LABEL: define void @nonnull_assign1 +// CHECK-LABEL: define void @{{.*}}nonnull_assign1 #line 300 void nonnull_assign1(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize @@ -48,7 +51,7 @@ void nonnull_assign1(int *p) { local = p; } -// CHECK-LABEL: define void @nonnull_assign2 +// CHECK-LABEL: define void @{{.*}}nonnull_assign2 #line 400 void nonnull_assign2(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -62,17 +65,18 @@ struct S1 { int *_Nonnull mptr; }; -// CHECK-LABEL: define void @nonnull_assign3 +// CHECK-LABEL: define void @{{.*}}nonnull_assign3 #line 500 void nonnull_assign3(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN3_LOC]] + // CHECK-NOT: call void @__ubsan_handle_type_mismatch struct S1 s; s.mptr = p; } -// CHECK-LABEL: define void @nonnull_init1 +// CHECK-LABEL: define void @{{.*}}nonnull_init1 #line 600 void nonnull_init1(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -81,7 +85,7 @@ void nonnull_init1(int *p) { int *_Nonnull local = p; } -// CHECK-LABEL: define void @nonnull_init2 +// CHECK-LABEL: define void @{{.*}}nonnull_init2 #line 700 void nonnull_init2(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -93,7 +97,7 @@ void nonnull_init2(int *p) { int *_Nonnull arr[] = {p, p}; } -// CHECK-LABEL: define i32* @nonnull_retval2 +// CHECK-LABEL: define i32* @{{.*}}nonnull_retval2 #line 800 int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this. int *_Nonnull arg2, //< Test this. @@ -150,7 +154,7 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this. } @end -// CHECK-LABEL: define void @call_A +// CHECK-LABEL: define void @{{.*}}call_A void call_A(A *a, int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P1:%.*]], null, !nosanitize // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize @@ -168,15 +172,15 @@ void call_A(A *a, int *p) { void dont_crash(int *_Nonnull p, ...) {} int main() { - nonnull_retval1(NULL); - nonnull_retval2(NULL, NULL, NULL, NULL, 0, 0, 0, 0); - call_func_with_nonnull_arg(NULL); - nonnull_assign1(NULL); - nonnull_assign2(NULL); - nonnull_assign3(NULL); - nonnull_init1(NULL); - nonnull_init2(NULL); - call_A(NULL, NULL); - dont_crash(NULL, NULL); + nonnull_retval1(INULL); + nonnull_retval2(INNULL, INNULL, INULL, (int *_Nullable)NULL, 0, 0, 0, 0); + call_func_with_nonnull_arg(INNULL); + nonnull_assign1(INULL); + nonnull_assign2(INULL); + nonnull_assign3(INULL); + nonnull_init1(INULL); + nonnull_init2(INULL); + call_A((A *)NULL, INULL); + dont_crash(INNULL, NULL); return 0; } diff --git a/test/CodeGenObjCXX/boxing.mm b/test/CodeGenObjCXX/boxing.mm new file mode 100644 index 0000000..dc35360 --- /dev/null +++ b/test/CodeGenObjCXX/boxing.mm @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +@interface NSNumber ++ (id)numberWithInt:(int)n; +@end + +int n = 1; +int m = (@(n++), 0); + +// CHECK: define {{.*}} @__cxx_global_var_init() +// CHECK: load i32, i32* @n +// CHECK: store i32 %{{.*}}, i32* @n diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index ddfb3cb..870378a 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -14,6 +14,9 @@ // C_P: "-E" // C_P: "-C" +// RUN: %clang_cl /d1reportAllClassLayout -### -- %s 2>&1 | FileCheck -check-prefix=d1reportAllClassLayout %s +// d1reportAllClassLayout: -fdump-record-layouts + // 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" diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c index c12164b..52f53d3 100644 --- a/test/Driver/split-debug.c +++ b/test/Driver/split-debug.c @@ -40,6 +40,13 @@ // CHECK-GMLT-WITH-SPLIT: "-debug-info-kind=line-tables-only" // CHECK-GMLT-WITH-SPLIT: "-split-dwarf-file" +// RUN: %clang -target x86_64-unknown-linux-gnu -g -fno-split-dwarf-inlining -S -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-NOINLINE-WITHOUT-SPLIT < %t %s +// +// CHECK-NOINLINE-WITHOUT-SPLIT-NOT: "-enable-split-dwarf" +// CHECK-NOINLINE-WITHOUT-SPLIT: "-fno-split-dwarf-inlining" +// CHECK-NOINLINE-WITHOUT-SPLIT: "-debug-info-kind=limited" + // RUN: %clang -target x86_64-unknown-linux-gnu -gmlt -gsplit-dwarf -fno-split-dwarf-inlining -S -### %s 2> %t // RUN: FileCheck -check-prefix=CHECK-SPLIT-WITH-GMLT < %t %s // diff --git a/test/Driver/unknown-std.c b/test/Driver/unknown-std.c index ba3035f..41736ec 100644 --- a/test/Driver/unknown-std.c +++ b/test/Driver/unknown-std.c @@ -2,32 +2,18 @@ // When user selects invalid language standard // print out supported values with short description. -// RUN: not %clang %s -std=foobar -c 2>&1 | \ -// RUN: FileCheck --match-full-lines %s +// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x objective-c %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x renderscript %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s // CHECK: error: invalid value 'foobar' in '-std=foobar' -// CHECK-NEXT: note: use 'c89' for 'ISO C 1990' standard -// CHECK-NEXT: note: use 'c90' for 'ISO C 1990' standard -// CHECK-NEXT: note: use 'iso9899:1990' for 'ISO C 1990' standard +// CHECK-NEXT: note: use 'c89', 'c90', or 'iso9899:1990' for 'ISO C 1990' standard // CHECK-NEXT: note: use 'iso9899:199409' for 'ISO C 1990 with amendment 1' standard -// CHECK-NEXT: note: use 'gnu89' for 'ISO C 1990 with GNU extensions' standard -// CHECK-NEXT: note: use 'gnu90' for 'ISO C 1990 with GNU extensions' standard -// CHECK-NEXT: note: use 'c99' for 'ISO C 1999' standard -// CHECK-NEXT: note: use 'c9x' for 'ISO C 1999' standard -// CHECK-NEXT: note: use 'iso9899:1999' for 'ISO C 1999' standard -// CHECK-NEXT: note: use 'iso9899:199x' for 'ISO C 1999' standard +// CHECK-NEXT: note: use 'gnu89' or 'gnu90' for 'ISO C 1990 with GNU extensions' standard +// CHECK-NEXT: note: use 'c99' or 'iso9899:1999' for 'ISO C 1999' standard // CHECK-NEXT: note: use 'gnu99' for 'ISO C 1999 with GNU extensions' standard -// CHECK-NEXT: note: use 'gnu9x' for 'ISO C 1999 with GNU extensions' standard -// CHECK-NEXT: note: use 'c11' for 'ISO C 2011' standard -// CHECK-NEXT: note: use 'c1x' for 'ISO C 2011' standard -// CHECK-NEXT: note: use 'iso9899:2011' for 'ISO C 2011' standard -// CHECK-NEXT: note: use 'iso9899:201x' for 'ISO C 2011' standard +// CHECK-NEXT: note: use 'c11' or 'iso9899:2011' for 'ISO C 2011' standard // CHECK-NEXT: note: use 'gnu11' for 'ISO C 2011 with GNU extensions' standard -// CHECK-NEXT: note: use 'gnu1x' for 'ISO C 2011 with GNU extensions' standard -// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard -// CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard -// CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard -// CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard // Make sure that no other output is present. // CHECK-NOT: {{^.+$}} diff --git a/test/Driver/unknown-std.cl b/test/Driver/unknown-std.cl index b87a8c8..71c478a 100644 --- a/test/Driver/unknown-std.cl +++ b/test/Driver/unknown-std.cl @@ -6,7 +6,7 @@ // RUN: FileCheck --match-full-lines %s // CHECK: error: invalid value 'foobar' in '-std=foobar' -// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard +// CHECK-NEXT: note: use 'cl1.0' for 'OpenCL 1.0' standard // CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard // CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard // CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard diff --git a/test/Driver/unknown-std.cpp b/test/Driver/unknown-std.cpp index faeb2cb..4f7a5e6 100644 --- a/test/Driver/unknown-std.cpp +++ b/test/Driver/unknown-std.cpp @@ -2,24 +2,20 @@ // When user selects invalid language standard // print out supported values with short description. -// RUN: not %clang %s -std=foobar -c 2>&1 | \ -// RUN: FileCheck --match-full-lines %s +// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x objective-c++ %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x cuda -nocudainc -nocudalib %s -std=foobar -c 2>&1 | FileCheck --match-full-lines --check-prefix=CHECK --check-prefix=CUDA %s // CHECK: error: invalid value 'foobar' in '-std=foobar' -// CHECK-NEXT: note: use 'c++98' for 'ISO C++ 1998 with amendments' standard -// CHECK-NEXT: note: use 'c++03' for 'ISO C++ 1998 with amendments' standard -// CHECK-NEXT: note: use 'gnu++98' for 'ISO C++ 1998 with amendments and GNU extensions' standard -// CHECK-NEXT: note: use 'c++0x' for 'ISO C++ 2011 with amendments' standard +// CHECK-NEXT: note: use 'c++98' or 'c++03' for 'ISO C++ 1998 with amendments' standard +// CHECK-NEXT: note: use 'gnu++98' or 'gnu++03' for 'ISO C++ 1998 with amendments and GNU extensions' standard // CHECK-NEXT: note: use 'c++11' for 'ISO C++ 2011 with amendments' standard -// CHECK-NEXT: note: use 'gnu++0x' for 'ISO C++ 2011 with amendments and GNU extensions' standard // CHECK-NEXT: note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard -// CHECK-NEXT: note: use 'c++1y' for 'ISO C++ 2014 with amendments' standard // CHECK-NEXT: note: use 'c++14' for 'ISO C++ 2014 with amendments' standard -// CHECK-NEXT: note: use 'gnu++1y' for 'ISO C++ 2014 with amendments and GNU extensions' standard // CHECK-NEXT: note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard // CHECK-NEXT: note: use 'c++1z' for 'Working draft for ISO C++ 2017' standard // CHECK-NEXT: note: use 'gnu++1z' for 'Working draft for ISO C++ 2017 with GNU extensions' standard -// CHECK-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard +// CUDA-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard // Make sure that no other output is present. // CHECK-NOT: {{^.+$}} diff --git a/test/Frontend/Inputs/empty.h b/test/Frontend/Inputs/empty.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/Frontend/Inputs/empty.h diff --git a/test/Frontend/gnu-inline.c b/test/Frontend/gnu-inline.c index 0272df7..75d4fe6 100644 --- a/test/Frontend/gnu-inline.c +++ b/test/Frontend/gnu-inline.c @@ -3,8 +3,10 @@ // RUN: %clang_cc1 -std=c99 -fgnu89-inline -fsyntax-only -x c -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s // RUN: %clang_cc1 -fsyntax-only -x c++ -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s // RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x c++ %s 2>&1 | FileCheck --check-prefix=CXX %s +// RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x objective-c++ %s 2>&1 | FileCheck --check-prefix=OBJCXX %s -// CXX: '-fgnu89-inline' not allowed with 'C++/ObjC++' +// CXX: '-fgnu89-inline' not allowed with 'C++' +// OBJCXX: '-fgnu89-inline' not allowed with 'Objective-C++' // STDC-INLINE-NOT: __GNUC_GNU_INLINE__ // STDC-INLINE: #define __GNUC_STDC_INLINE__ 1 diff --git a/test/Frontend/rewrite-includes-line-markers.c b/test/Frontend/rewrite-includes-line-markers.c index 14692a1..f5fb627 100644 --- a/test/Frontend/rewrite-includes-line-markers.c +++ b/test/Frontend/rewrite-includes-line-markers.c @@ -3,6 +3,8 @@ #include "test.h" int f() { return x; } +#include "empty.h" + // GNU: {{^}}# 1 "{{.*}}rewrite-includes-line-markers.c" // GNU: {{^}}#include "test.h" // GNU: {{^}}# 1 "{{.*}}test.h" @@ -11,6 +13,9 @@ int f() { return x; } // GNU: {{^}}int x; // GNU: {{^}}# 4 "{{.*}}rewrite-includes-line-markers.c" 2 // GNU: {{^}}int f() { return x; } +// GNU: {{^}} +// GNU: {{^}}# 1 "{{.*}}empty.h" 1 +// GNU: {{^}}# 7 "{{.*}}rewrite-includes-line-markers.c" 2 // LINE: {{^}}#line 1 "{{.*}}rewrite-includes-line-markers.c" // LINE: {{^}}#include "test.h" @@ -20,3 +25,6 @@ int f() { return x; } // LINE: {{^}}int x; // LINE: {{^}}#line 4 "{{.*}}rewrite-includes-line-markers.c" // LINE: {{^}}int f() { return x; } +// LINE: {{^}} +// LINE: {{^}}#line 1 "{{.*}}empty.h" +// LINE: {{^}}#line 7 "{{.*}}rewrite-includes-line-markers.c" diff --git a/test/Frontend/rewrite-includes-modules.c b/test/Frontend/rewrite-includes-modules.c index 613609d..e70fe0d 100644 --- a/test/Frontend/rewrite-includes-modules.c +++ b/test/Frontend/rewrite-includes-modules.c @@ -1,22 +1,27 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c %s -F %S/../Modules/Inputs -E -frewrite-includes -o - | FileCheck %s +// RUN: mkdir %t +// RUN: echo 'extern int dummy;' > %t/dummy.h +// RUN: echo 'module dummy { header "dummy.h" }' > %t/module.modulemap +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -I%t -E -frewrite-includes -o - | FileCheck %s +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c %s -I%t -E -frewrite-includes -o - | FileCheck %s +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ %s -I%t -E -frewrite-includes -o - | FileCheck %s int bar(); -#include +#include "dummy.h" int foo(); -#include +#include "dummy.h" // CHECK: int bar();{{$}} // CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}} -// CHECK-NEXT: #include {{$}} +// CHECK-NEXT: #include "dummy.h"{{$}} // CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}} -// CHECK-NEXT: # 5 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} -// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}} -// CHECK-NEXT: # 6 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} +// CHECK-NEXT: # 10 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} +// CHECK-NEXT: #pragma clang module import dummy /* clang -frewrite-includes: implicit import */{{$}} +// CHECK-NEXT: # 11 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} // CHECK-NEXT: int foo();{{$}} // CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}} -// CHECK-NEXT: #include {{$}} +// CHECK-NEXT: #include "dummy.h"{{$}} // CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}} -// CHECK-NEXT: # 7 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} -// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}} -// CHECK-NEXT: # 8 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} +// CHECK-NEXT: # 12 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} +// CHECK-NEXT: #pragma clang module import dummy /* clang -frewrite-includes: implicit import */{{$}} +// CHECK-NEXT: # 13 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}} diff --git a/test/Headers/stdint-typeof-MINMAX.cpp b/test/Headers/stdint-typeof-MINMAX.cpp new file mode 100644 index 0000000..7014259 --- /dev/null +++ b/test/Headers/stdint-typeof-MINMAX.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=aarch64-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=arm-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=i386-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=mips-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=mips64-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=msp430-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc64-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc64-none-netbsd +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=s390x-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=sparc-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=tce-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=x86_64-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=x86_64-pc-linux-gnu +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=i386-mingw32 +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=xcore-none-none +// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only + +#include +#include + +static_assert(__is_same(__typeof__(INTPTR_MIN), intptr_t)); +static_assert(__is_same(__typeof__(INTPTR_MAX), intptr_t)); +static_assert(__is_same(__typeof__(UINTPTR_MAX), uintptr_t)); +static_assert(__is_same(__typeof__(PTRDIFF_MIN), ptrdiff_t)); +static_assert(__is_same(__typeof__(PTRDIFF_MAX), ptrdiff_t)); +static_assert(__is_same(__typeof__(SIZE_MAX), size_t)); +static_assert(__is_same(__typeof__(INTMAX_MIN), intmax_t)); +static_assert(__is_same(__typeof__(INTMAX_MAX), intmax_t)); +static_assert(__is_same(__typeof__(UINTMAX_MAX), uintmax_t)); +static_assert(__is_same(__typeof__(INTMAX_C(5)), intmax_t)); +static_assert(__is_same(__typeof__(UINTMAX_C(5)), uintmax_t)); diff --git a/test/Import/in-class-initializer/Inputs/S.cpp b/test/Import/in-class-initializer/Inputs/S.cpp new file mode 100644 index 0000000..28e6310 --- /dev/null +++ b/test/Import/in-class-initializer/Inputs/S.cpp @@ -0,0 +1,3 @@ +struct S { + int a = 3; +}; diff --git a/test/Import/in-class-initializer/test.cpp b/test/Import/in-class-initializer/test.cpp new file mode 100644 index 0000000..eaaac2a --- /dev/null +++ b/test/Import/in-class-initializer/test.cpp @@ -0,0 +1,5 @@ +// RUN: clang-import-test -import %S/Inputs/S.cpp -expression %s +void expr() { + S MyS; + int b = MyS.a + MyS.a; +} diff --git a/test/Index/Core/index-source.m b/test/Index/Core/index-source.m index a2eef89..041753b 100644 --- a/test/Index/Core/index-source.m +++ b/test/Index/Core/index-source.m @@ -150,9 +150,9 @@ extern int setjmp(jmp_buf); // CHECK: [[@LINE+9]]:13 | instance-property/ObjC | prop | [[I2_prop_USR:.*]] | | Def,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK-NEXT: RelAcc | _prop | c:objc(cs)I2@_prop -// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I2 | [[I2_USR]] -// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK: [[@LINE+2]]:20 | field/ObjC | _prop | c:objc(cs)I2@_prop | | Def,RelChild | rel: 1 // CHECK-NEXT: RelChild | I2 | [[I2_USR]] @@ -214,8 +214,8 @@ extern int setjmp(jmp_buf); // CHECK: [[@LINE+5]]:13 | instance-property/ObjC | prop | c:objc(cs)I3(py)prop | | Def,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I3 | c:objc(cs)I3 // CHECK-NEXT: RelAcc | _prop | c:objc(cs)I3@_prop -// CHECK: [[@LINE+2]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,Impl,RelChild | rel: 1 -// CHECK: [[@LINE+1]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE+2]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,Dyn,Impl,RelChild | rel: 1 +// CHECK: [[@LINE+1]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,Dyn,Impl,RelChild | rel: 1 @synthesize prop = _prop; @end @@ -275,9 +275,9 @@ typedef MyGenCls MyEnumerator; // CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I4(py)foo | | Def,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I4 | c:objc(cs)I4 // CHECK-NEXT: RelAcc | _blahfoo | c:objc(cs)I4@_blahfoo -// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I4(im)foo | -[I4 foo] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I4(im)foo | -[I4 foo] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I4 | c:objc(cs)I4 -// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I4(im)setFoo: | -[I4 setFoo:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I4(im)setFoo: | -[I4 setFoo:] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I4 | c:objc(cs)I4 // CHECK: [[@LINE-8]]:19 | field/ObjC | _blahfoo | c:objc(cs)I4@_blahfoo | | Ref | rel: 0 @@ -296,9 +296,9 @@ typedef MyGenCls MyEnumerator; // CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I5(py)foo | | Def,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I5 | c:objc(cs)I5 // CHECK-NEXT: RelAcc | _blahfoo | c:objc(cs)I5@_blahfoo -// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I5(im)foo | -[I5 foo] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I5(im)foo | -[I5 foo] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I5 | c:objc(cs)I5 -// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I5(im)setFoo: | -[I5 setFoo:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I5(im)setFoo: | -[I5 setFoo:] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I5 | c:objc(cs)I5 // CHECK: [[@LINE-8]]:19 | field/ObjC | _blahfoo | c:objc(cs)I5@_blahfoo | | Def,RelChild | rel: 1 @@ -317,9 +317,9 @@ typedef MyGenCls MyEnumerator; // CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I6(py)foo | | Def,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I6 | c:objc(cs)I6 // CHECK-NEXT: RelAcc | foo | c:objc(cs)I6@foo -// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I6(im)foo | -[I6 foo] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I6(im)foo | -[I6 foo] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I6 | c:objc(cs)I6 -// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I6(im)setFoo: | -[I6 setFoo:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I6(im)setFoo: | -[I6 setFoo:] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I6 | c:objc(cs)I6 // CHECK: [[@LINE-8]]:13 | field/ObjC | foo | c:objc(cs)I6@foo | | Def,Impl,RelChild | rel: 1 @@ -337,9 +337,9 @@ typedef MyGenCls MyEnumerator; // CHECK: [[@LINE-1]]:17 | instance-property/ObjC | foo | c:objc(cs)I7(py)foo | | Def,Impl,RelChild,RelAcc | rel: 2 // CHECK-NEXT: RelChild | I7 | c:objc(cs)I7 // CHECK-NEXT: RelAcc | _foo | c:objc(cs)I7@_foo -// CHECK: [[@LINE-4]]:17 | instance-method/acc-get/ObjC | foo | c:objc(cs)I7(im)foo | -[I7 foo] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-4]]:17 | instance-method/acc-get/ObjC | foo | c:objc(cs)I7(im)foo | -[I7 foo] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I7 | c:objc(cs)I7 -// CHECK: [[@LINE-6]]:17 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I7(im)setFoo: | -[I7 setFoo:] | Def,Impl,RelChild | rel: 1 +// CHECK: [[@LINE-6]]:17 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I7(im)setFoo: | -[I7 setFoo:] | Def,Dyn,Impl,RelChild | rel: 1 // CHECK-NEXT: RelChild | I7 | c:objc(cs)I7 // CHECK: [[@LINE-8]]:17 | field/ObjC | _foo | c:objc(cs)I7@_foo | | Def,Impl,RelChild | rel: 1 diff --git a/test/Index/allow-editor-placeholders.cpp b/test/Index/allow-editor-placeholders.cpp new file mode 100644 index 0000000..5a7207d --- /dev/null +++ b/test/Index/allow-editor-placeholders.cpp @@ -0,0 +1,5 @@ +// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s + +<#placeholder#>; + +// CHECK-NOT: error diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm index a926c3d..33d1c68 100644 --- a/test/Index/cursor-dynamic-call.mm +++ b/test/Index/cursor-dynamic-call.mm @@ -49,6 +49,14 @@ void test2() { id o = [[Test alloc] init]; } +@interface Test2 : NSObject +@property (assign) id someProp; +@end + +void test3(Test2 *o) { + id v = o.someProp; +} + // RUN: c-index-test -cursor-at=%s:8:11 \ // RUN: -cursor-at=%s:9:11 \ // RUN: -cursor-at=%s:25:11 \ @@ -59,6 +67,7 @@ void test2() { // RUN: -cursor-at=%s:36:9 \ // RUN: -cursor-at=%s:37:9 \ // RUN: -cursor-at=%s:49:26 \ +// RUN: -cursor-at=%s:57:12 \ // RUN: %s | FileCheck %s // CHECK: 8:11 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call @@ -67,9 +76,10 @@ void test2() { // CHECK-NOT: 26:3 {{.*}} Dynamic-call // CHECK-NOT: 29:3 {{.*}} Dynamic-call // CHECK: 29:3 {{.*}} Receiver-type=ObjCInterface -// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call +// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call Receiver-type=Pointer // CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer // CHECK-NOT: 36:3 {{.*}} Dynamic-call // CHECK: 36:3 {{.*}} Receiver-type=ObjCInterface // CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call Receiver-type=ObjCClass // CHECK-NOT: 49:10 {{.*}} Dynamic-call +// CHECK: 57:12 MemberRefExpr=someProp:53:23 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer diff --git a/test/Index/index-module.m b/test/Index/index-module.m index 51faea2..6f3d848 100644 --- a/test/Index/index-module.m +++ b/test/Index/index-module.m @@ -28,7 +28,7 @@ int glob; // CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_OTHER_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]other\.h]] | {{.*}} | hash loc: | {{.*}} | module: DependsOnModule // CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_NOT_CXX_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]not_cxx\.h]] | {{.*}} | hash loc: | {{.*}} | module: DependsOnModule.NotCXX // CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: | {{.*}} | module: DependsOnModule.SubFramework -// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_OTHER_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]Frameworks/SubFramework\.framework/Headers/Other\.h]] | name: "SubFramework/Other.h" | hash loc: [[DMOD_SUB_H]]:1:1 | isImport: 0 | isAngled: 0 | isModule: 0 | module: DependsOnModule.SubFramework.Other +// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_OTHER_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]Other\.h]] | name: "SubFramework/Other.h" | hash loc: [[DMOD_SUB_H]]:1:1 | isImport: 0 | isAngled: 0 | isModule: 0 | module: DependsOnModule.SubFramework.Other // CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_PRIVATE_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]PrivateHeaders[/\\]DependsOnModulePrivate.h]] | {{.*}} | hash loc: | {{.*}} | module: DependsOnModule.Private.DependsOnModule // CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache{{(.sys)?[/\\]}}Module.pcm | loc: [[DMOD_MODULE_H]]:1:1 | name: "Module" | isImplicit: 1 // CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_other | {{.*}} | loc: [[DMOD_OTHER_H]]:1:5 diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp index ff150f7..e152a7e 100644 --- a/test/Index/print-type.cpp +++ b/test/Index/print-type.cpp @@ -71,10 +71,9 @@ struct Specialization; Specialization& > templRefParam; auto autoTemplRefParam = templRefParam; -template -struct DefaultedTypeExample {}; - -typedef DefaultedTypeExample DefaultedTypeAlias; +template struct A {}; +template using C = T; +using baz = C>; // RUN: c-index-test -test-print-type %s -std=c++14 | FileCheck %s // CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0] @@ -120,7 +119,7 @@ typedef DefaultedTypeExample DefaultedTypeAlias; // CHECK: TemplateRef=Baz:9:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0] -// CHECK: FieldDecl=qux:29:38 (Definition) [type=Qux, outer::inner::Bar::FooType>] [typekind=Unexposed] [templateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo] [typekind=Record] [type=int] [typekind=Int]] [canonicaltype=outer::Qux, int>] [canonicaltypekind=Record] [canonicaltemplateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo] [typekind=Record] [type=int] [typekind=Int]] [isPOD=1] +// CHECK: FieldDecl=qux:29:38 (Definition) [type=Qux, outer::inner::Bar::FooType>] [typekind=Unexposed] [templateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo] [typekind=Unexposed] [type=outer::inner::Bar::FooType] [typekind=Typedef]] [canonicaltype=outer::Qux, int>] [canonicaltypekind=Record] [canonicaltemplateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo] [typekind=Record] [type=int] [typekind=Int]] [isPOD=1] // CHECK: TemplateRef=Qux:12:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: FunctionTemplate=tbar:36:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0] @@ -182,4 +181,4 @@ typedef DefaultedTypeExample DefaultedTypeAlias; // CHECK: VarDecl=autoTemplRefParam:72:6 (Definition) [type=Specialization &>] [typekind=Auto] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] // CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=const Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] // CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization &>] [typekind=Unexposed] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] -// CHECK: TypedefDecl=DefaultedTypeAlias:77:35 (Definition) [type=DefaultedTypeAlias] [typekind=Typedef] [templateargs/2= [type=int] [typekind=Int] [type=int] [typekind=Int]] [canonicaltype=DefaultedTypeExample] [canonicaltypekind=Record] [canonicaltemplateargs/2= [type=int] [typekind=Int] [type=int] [typekind=Int]] [isPOD=0] +// CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A] [typekind=Unexposed]] [canonicaltype=A] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0] diff --git a/test/Index/target-info.c b/test/Index/target-info.c new file mode 100644 index 0000000..98a3ca3 --- /dev/null +++ b/test/Index/target-info.c @@ -0,0 +1,6 @@ +// RUN: c-index-test -test-print-target-info %s --target=i386-unknown-linux-gnu | FileCheck %s +// RUN: c-index-test -test-print-target-info %s --target=x86_64-unknown-linux-gnu | FileCheck --check-prefix=CHECK-1 %s +// CHECK: TargetTriple: i386-unknown-linux-gnu +// CHECK: PointerWidth: 32 +// CHECK-1: TargetTriple: x86_64-unknown-linux-gnu +// CHECK-1: PointerWidth: 64 diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp index 8ad1702..2bd5744 100644 --- a/test/Index/usrs.cpp +++ b/test/Index/usrs.cpp @@ -95,6 +95,14 @@ class TC1 { void meth(TC1); }; +typedef __attribute__((__ext_vector_type__(3))) float float3; + +typedef float __m128 __attribute__((__vector_size__(16))); + +float3 vectorOverload(float3 f); + +__m128 vectorOverload(__m128 f); + // RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck %s // CHECK: usrs.cpp c:@N@foo Extent=[1:1 - 4:2] // CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8] @@ -172,3 +180,6 @@ class TC1 { // CHECK: usrs.cpp c:usrs.cpp@S@usrs.cpp@1510@FI@x Extent=[91:10 - 91:15] // CHECK: usrs.cpp c:@ST>1#T@TC1@F@meth#>@ST>1#T@TC11t0.0# Extent=[95:3 - 95:17] + +// CHECK: usrs.cpp c:@F@vectorOverload#]3f# Extent=[102:1 - 102:32] +// CHECK: usrs.cpp c:@F@vectorOverload#[4f# Extent=[104:1 - 104:32] diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp index 3bd58a3..fd3bb94 100644 --- a/test/Modules/ExtDebugInfo.cpp +++ b/test/Modules/ExtDebugInfo.cpp @@ -76,7 +76,7 @@ void foo() { // CHECK-SAME: flags: DIFlagFwdDecl, // CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE") -// CHECK: ![[NS]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]], +// CHECK: ![[NS]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]]) // CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugCXX // This type is anchored in the module by an explicit template instantiation. diff --git a/test/Modules/Inputs/diag_flags.h b/test/Modules/Inputs/diag_flags.h new file mode 100644 index 0000000..3b85c84 --- /dev/null +++ b/test/Modules/Inputs/diag_flags.h @@ -0,0 +1 @@ +struct Padded { char x; int y; }; diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h new file mode 100644 index 0000000..fb5da09 --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h @@ -0,0 +1 @@ +#define BAR_PUBLIC 1 diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h new file mode 100644 index 0000000..cbbb44f --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h @@ -0,0 +1 @@ +// FooPublic.h diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap new file mode 100644 index 0000000..af67e65 --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module Foo { + umbrella header "FooPublic.h" + requires objc + export * +} diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap new file mode 100644 index 0000000..f6d9dfd --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap @@ -0,0 +1,5 @@ +explicit module Foo.Private { + umbrella header "Foo.h" + requires objc + export * +} diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h new file mode 100644 index 0000000..98064e0 --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h @@ -0,0 +1 @@ +#define BAZ_PRIVATE 1 diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h new file mode 100644 index 0000000..9381133 --- /dev/null +++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h @@ -0,0 +1 @@ +// Foo.h diff --git a/test/Modules/Inputs/malformed-overload/X.h b/test/Modules/Inputs/malformed-overload/X.h new file mode 100644 index 0000000..b659406 --- /dev/null +++ b/test/Modules/Inputs/malformed-overload/X.h @@ -0,0 +1,2 @@ +@class NSString; +extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))) __attribute__((not_tail_called)); diff --git a/test/Modules/Inputs/malformed-overload/module.modulemap b/test/Modules/Inputs/malformed-overload/module.modulemap new file mode 100644 index 0000000..8fe4c92 --- /dev/null +++ b/test/Modules/Inputs/malformed-overload/module.modulemap @@ -0,0 +1,4 @@ +module X { + header "X.h" + export * +} diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index b95eec3..7416d70 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -261,6 +261,10 @@ module config { config_macros [exhaustive] WANT_FOO, WANT_BAR } +module diag_flags { + header "diag_flags.h" +} + module diag_pragma { header "diag_pragma.h" } diff --git a/test/Modules/crash-vfs-path-emptydir-entries.m b/test/Modules/crash-vfs-path-emptydir-entries.m index e44714b..d96adbb 100644 --- a/test/Modules/crash-vfs-path-emptydir-entries.m +++ b/test/Modules/crash-vfs-path-emptydir-entries.m @@ -27,7 +27,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" diff --git a/test/Modules/crash-vfs-path-symlink-component.m b/test/Modules/crash-vfs-path-symlink-component.m index 5be4925..4723a77 100644 --- a/test/Modules/crash-vfs-path-symlink-component.m +++ b/test/Modules/crash-vfs-path-symlink-component.m @@ -28,7 +28,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" @@ -65,4 +65,4 @@ // RUN: -fmodules-cache-path=%t/m/ 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECKOVERLAY -// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/i/usr/x/../stdio.h" */ +// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import diff --git a/test/Modules/crash-vfs-path-symlink-topheader.m b/test/Modules/crash-vfs-path-symlink-topheader.m index 51a14c6..8e0c2d4 100644 --- a/test/Modules/crash-vfs-path-symlink-topheader.m +++ b/test/Modules/crash-vfs-path-symlink-topheader.m @@ -29,7 +29,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" diff --git a/test/Modules/crash-vfs-path-traversal.m b/test/Modules/crash-vfs-path-traversal.m index cc56e53..cd12cad 100644 --- a/test/Modules/crash-vfs-path-traversal.m +++ b/test/Modules/crash-vfs-path-traversal.m @@ -25,7 +25,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" @@ -62,4 +62,4 @@ // RUN: -fmodules-cache-path=%t/m/ 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECKOVERLAY -// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/usr/././//////include/../include/./././../include/stdio.h" */ +// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import diff --git a/test/Modules/crash-vfs-relative-incdir.m b/test/Modules/crash-vfs-relative-incdir.m index 63cd982..ed02de8 100644 --- a/test/Modules/crash-vfs-relative-incdir.m +++ b/test/Modules/crash-vfs-relative-incdir.m @@ -21,7 +21,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" diff --git a/test/Modules/crash-vfs-relative-overlay.m b/test/Modules/crash-vfs-relative-overlay.m index 54ba13b..e55f4c8 100644 --- a/test/Modules/crash-vfs-relative-overlay.m +++ b/test/Modules/crash-vfs-relative-overlay.m @@ -24,7 +24,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" @@ -58,4 +58,4 @@ // RUN: -fmodules-cache-path=%t/m/ 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECKOVERLAY -// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/usr/include/stdio.h" */ +// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import diff --git a/test/Modules/crash-vfs-run-reproducer.m b/test/Modules/crash-vfs-run-reproducer.m index 72771a2..eba56c5 100644 --- a/test/Modules/crash-vfs-run-reproducer.m +++ b/test/Modules/crash-vfs-run-reproducer.m @@ -21,7 +21,7 @@ // CHECK-NEXT: note: diagnostic msg: {{.*}}.m // CHECK-NEXT: note: diagnostic msg: {{.*}}.cache -// CHECKSRC: @import cstd.stdio; +// CHECKSRC: #pragma clang module import cstd.stdio // CHECKSH: # Crash reproducer // CHECKSH-NEXT: # Driver args: "-fsyntax-only" diff --git a/test/Modules/diag-flags.cpp b/test/Modules/diag-flags.cpp new file mode 100644 index 0000000..adbbd08 --- /dev/null +++ b/test/Modules/diag-flags.cpp @@ -0,0 +1,22 @@ +// RUN: rm -rf %t +// +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DIMPLICIT_FLAG -Werror=padded +// +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/explicit.pcm -Werror=string-plus-int -Wpadded +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm -Werror=padded + +import diag_flags; + +// Diagnostic flags from the module user make no difference to diagnostics +// emitted within the module when using an explicitly-loaded module. +#ifdef IMPLICIT_FLAG +// expected-error@diag_flags.h:14 {{padding struct}} +#elif defined(EXPLICIT_FLAG) +// expected-warning@diag_flags.h:14 {{padding struct}} +#else +// expected-no-diagnostics +#endif +unsigned n = sizeof(Padded); diff --git a/test/Modules/import-syntax.c b/test/Modules/import-syntax.c new file mode 100644 index 0000000..a29e07a --- /dev/null +++ b/test/Modules/import-syntax.c @@ -0,0 +1,35 @@ +// RUN: rm -rf %t +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c -DINCLUDE %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DINCLUDE %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -DINCLUDE %s +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DAT_IMPORT=1 %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c++ -DAT_IMPORT=1 %s +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -fmodules-ts -DIMPORT=1 %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c++ -fmodules-ts -DIMPORT=1 %s +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c -DPRAGMA %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DPRAGMA %s +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -DPRAGMA %s + +// expected-no-diagnostics + +// All forms of module import should make both declarations and macros visible. + +#if INCLUDE +#include "dummy.h" +#elif AT_IMPORT +@import dummy; +#elif IMPORT +import dummy; +#elif PRAGMA +#pragma clang module import dummy +#endif + +#ifndef DUMMY_H +#error "macros not visible" +#endif + +void *p = &dummy1; diff --git a/test/Modules/incomplete-umbrella.m b/test/Modules/incomplete-umbrella.m new file mode 100644 index 0000000..8760b81 --- /dev/null +++ b/test/Modules/incomplete-umbrella.m @@ -0,0 +1,15 @@ +// RUN: rm -rf %t +// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F%S/Inputs/incomplete-umbrella -fsyntax-only %s 2>&1 | FileCheck %s + +#import +#import +#import +@import Foo.Private; + +// CHECK: warning: umbrella header for module 'Foo' does not include header 'Bar.h' +// CHECK: warning: umbrella header for module 'Foo.Private' does not include header 'Baz.h' +int foo() { + int a = BAR_PUBLIC; + int b = BAZ_PRIVATE; + return 0; +} diff --git a/test/Modules/malformed-overload.m b/test/Modules/malformed-overload.m new file mode 100644 index 0000000..e080201 --- /dev/null +++ b/test/Modules/malformed-overload.m @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fsyntax-only -I%S/Inputs/malformed-overload -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify %s +NSLog(@"%@", path); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-warning {{incompatible redeclaration}} expected-note {{to match this '('}} expected-note {{'NSLog' is a builtin with type}} +#import "X.h" + +@class NSString; +void f(NSString *a) { + NSLog(@"***** failed to get URL for %@", a); +} diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 2ec8005..e57c36f 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -887,6 +887,52 @@ Bravo golf; #endif } +namespace DifferentParameterNameInTemplate { +#if defined(FIRST) || defined(SECOND) +template +struct S { + typedef T Type; + + static void Run(const Type *name_one); +}; + +template +void S::Run(const T *name_two) {} + +template +struct Foo { + ~Foo() { Handler::Run(nullptr); } + Foo() {} + + class Handler : public S {}; + + void Get(typename Handler::Type *x = nullptr) {} + void Add() { Handler::Run(nullptr); } +}; +#endif + +#if defined(FIRST) +struct Beta; + +struct Alpha { + Alpha(); + void Go() { betas.Get(); } + Foo betas; +}; + +#elif defined(SECOND) +struct Beta {}; + +struct BetaHelper { + void add_Beta() { betas.Add(); } + Foo betas; +}; + +#else +Alpha::Alpha() {} +#endif +} + // Keep macros contained to one file. #ifdef FIRST #undef FIRST diff --git a/test/Modules/preprocess-module.cpp b/test/Modules/preprocess-module.cpp new file mode 100644 index 0000000..99fe8cf --- /dev/null +++ b/test/Modules/preprocess-module.cpp @@ -0,0 +1,12 @@ +// RUN: rm -rf %t + +// RUN: not %clang_cc1 -fmodules -fmodule-name=file -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E 2>&1 | FileCheck %s --check-prefix=MISSING-FWD +// MISSING-FWD: module 'fwd' is needed + +// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodules-cache-path=%t -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E | FileCheck %s +// CHECK: # 1 "" +// CHECK: # 1 "{{.*}}file.h" 1 +// CHECK: struct __FILE; +// CHECK: #pragma clang module import fwd /* clang -E: implicit import for #include "fwd.h" */ +// CHECK: typedef struct __FILE FILE; +// CHECK: # 2 "" 2 diff --git a/test/Modules/preprocess.cpp b/test/Modules/preprocess.cpp index 0615331..d855fed 100644 --- a/test/Modules/preprocess.cpp +++ b/test/Modules/preprocess.cpp @@ -1,24 +1,30 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x c++ -E %s | \ -// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=CXX --check-prefix=CXX-DASHE +// RUN: FileCheck -strict-whitespace %s // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x objective-c -E %s | \ -// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=OBJC +// RUN: FileCheck -strict-whitespace %s // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x c++ -E -frewrite-includes %s | \ -// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=CXX +// RUN: FileCheck -strict-whitespace %s --check-prefix=REWRITE // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x objective-c -E -frewrite-includes %s | \ -// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=OBJC +// RUN: FileCheck -strict-whitespace %s --check-prefix=REWRITE #include "dummy.h" #include "dummy.h" foo bar baz -// The weird {{ }} here is to prevent the -frewrite-includes test from matching its own CHECK lines. +// EOF marker to ensure -frewrite-includes doesn't match its own CHECK lines. -// CXX: #include{{ }}"dummy.h" -// CXX-DASHE-SAME: /* clang -E: implicit import for module dummy */ -// CXX: #include{{ }}"dummy.h" -// CXX-DASHE-SAME: /* clang -E: implicit import for module dummy */ -// CXX: foo bar baz +// REWRITE: #if 0 +// REWRITE: #include{{ }}"dummy.h" +// REWRITE: #endif -// OBJC: @import{{ }}dummy; /* clang -// OBJC: @import{{ }}dummy; /* clang -// OBJC: foo bar baz +// CHECK: #pragma clang module import dummy /* clang {{.*}} implicit import + +// REWRITE: #if 0 +// REWRITE: #include{{ }}"dummy.h" +// REWRITE: #endif + +// CHECK: #pragma clang module import dummy /* clang {{.*}} implicit import + +// CHECK: foo bar baz + +// REWRITE: // {{EOF}} marker diff --git a/test/Modules/preprocess.m b/test/Modules/preprocess.m index 8d740d1..37a6815 100644 --- a/test/Modules/preprocess.m +++ b/test/Modules/preprocess.m @@ -16,11 +16,11 @@ void test() { // CHECK: int left_and_right(int *);{{$}} -// CHECK-NEXT: @import diamond_left; /* clang -E: implicit import for "{{.*}}diamond_left.h" */{{$}} +// CHECK-NEXT: #pragma clang module import diamond_left /* clang -E: implicit import for #import "diamond_left.h" */{{$}} -// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}} -// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}} -// CHECK: @import file; /* clang -E: implicit import for "{{.*}}file.h" */{{$}} +// CHECK: #pragma clang module import diamond_right /* clang -E: implicit import for #import "diamond_right.h" */{{$}} +// CHECK: #pragma clang module import diamond_right /* clang -E: implicit import for #import "diamond_right.h" */{{$}} +// CHECK: #pragma clang module import file /* clang -E: implicit import for #include "file.h" */{{$}} // CHECK-NEXT: void test() {{{$}} // CHECK-NEXT: top_left_before();{{$}} // CHECK-NEXT: left_and_right();{{$}} diff --git a/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp index f865e0b..2d99d7d 100644 --- a/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp +++ b/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp @@ -134,9 +134,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target diff --git a/test/OpenMP/distribute_simd_aligned_messages.cpp b/test/OpenMP/distribute_simd_aligned_messages.cpp index 10beb71..21b1bc9 100644 --- a/test/OpenMP/distribute_simd_aligned_messages.cpp +++ b/test/OpenMP/distribute_simd_aligned_messages.cpp @@ -134,9 +134,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target diff --git a/test/OpenMP/for_simd_aligned_messages.cpp b/test/OpenMP/for_simd_aligned_messages.cpp index 1d0918e..3ff2587 100644 --- a/test/OpenMP/for_simd_aligned_messages.cpp +++ b/test/OpenMP/for_simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp for simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/parallel_for_simd_aligned_messages.cpp b/test/OpenMP/parallel_for_simd_aligned_messages.cpp index fc0f88c..eed8017 100644 --- a/test/OpenMP/parallel_for_simd_aligned_messages.cpp +++ b/test/OpenMP/parallel_for_simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp parallel for simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/simd_aligned_messages.cpp b/test/OpenMP/simd_aligned_messages.cpp index 81aec96..d936fed 100644 --- a/test/OpenMP/simd_aligned_messages.cpp +++ b/test/OpenMP/simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp index 538d65b..655f906 100644 --- a/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp +++ b/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target parallel for simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/target_simd_aligned_messages.cpp b/test/OpenMP/target_simd_aligned_messages.cpp index ae2859d..76a37f6 100644 --- a/test/OpenMP/target_simd_aligned_messages.cpp +++ b/test/OpenMP/target_simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp index df5468c..f121512 100644 --- a/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp +++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp @@ -110,9 +110,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target teams distribute parallel for simd aligned // expected-error {{expected '(' after 'aligned'}} diff --git a/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp b/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp index e9df563..d91cfa9 100644 --- a/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp +++ b/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp @@ -110,9 +110,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target teams distribute simd aligned // expected-error {{expected '(' after 'aligned'}} diff --git a/test/OpenMP/taskloop_simd_aligned_messages.cpp b/test/OpenMP/taskloop_simd_aligned_messages.cpp index 6085660..c4c41eb 100644 --- a/test/OpenMP/taskloop_simd_aligned_messages.cpp +++ b/test/OpenMP/taskloop_simd_aligned_messages.cpp @@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp taskloop simd aligned // expected-error {{expected '(' after 'aligned'}} for (I k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp index 6740577..97b200b 100644 --- a/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp +++ b/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp @@ -123,9 +123,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target diff --git a/test/OpenMP/teams_distribute_simd_aligned_messages.cpp b/test/OpenMP/teams_distribute_simd_aligned_messages.cpp index 95a85b2..885432b 100644 --- a/test/OpenMP/teams_distribute_simd_aligned_messages.cpp +++ b/test/OpenMP/teams_distribute_simd_aligned_messages.cpp @@ -123,9 +123,8 @@ S3 h; // expected-note 2 {{'h' defined here}} template 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 i; // expected-note {{'i' defined here}} + // expected-note@+1 {{declared here}} int &j = i; #pragma omp target diff --git a/test/Preprocessor/Inputs/nonportable-hmaps/foo.hmap b/test/Preprocessor/Inputs/nonportable-hmaps/foo.hmap new file mode 100644 index 0000000..9036f20 Binary files /dev/null and b/test/Preprocessor/Inputs/nonportable-hmaps/foo.hmap differ diff --git a/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h b/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index 5fb2011..36ef9b2 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -9690,3 +9690,12 @@ // MSVC-X64-NEXT:#define __CLANG_ATOMIC_SHORT_LOCK_FREE 2 // MSVC-X64-NEXT:#define __CLANG_ATOMIC_WCHAR_T_LOCK_FREE 2 // MSVC-X86-NOT:#define __GCC_ATOMIC{{.*}} + +// RUN: %clang_cc1 -E -dM -ffreestanding \ +// RUN: -triple=aarch64-apple-ios9 < /dev/null \ +// RUN: | FileCheck -check-prefix=DARWIN %s +// RUN: %clang_cc1 -E -dM -ffreestanding \ +// RUN: -triple=aarch64-apple-macosx10.12 < /dev/null \ +// RUN: | FileCheck -check-prefix=DARWIN %s + +// DARWIN:#define __STDC_NO_THREADS__ 1 diff --git a/test/Preprocessor/nonportable-include-with-hmap.c b/test/Preprocessor/nonportable-include-with-hmap.c new file mode 100644 index 0000000..fc958e7 --- /dev/null +++ b/test/Preprocessor/nonportable-include-with-hmap.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -Eonly \ +// RUN: -I%S/Inputs/nonportable-hmaps/foo.hmap \ +// RUN: -I%S/Inputs/nonportable-hmaps \ +// RUN: %s -verify +// +// foo.hmap contains: Foo/Foo.h -> headers/foo/Foo.h +// +// Header search of "Foo/Foo.h" follows this path: +// 1. Look for "Foo/Foo.h". +// 2. Find "Foo/Foo.h" in "nonportable-hmaps/foo.hmap". +// 3. Look for "headers/foo/Foo.h". +// 4. Find "headers/foo/Foo.h" in "nonportable-hmaps". +// 5. Return. +// +// There is nothing nonportable; -Wnonportable-include-path should not fire. +#include "Foo/Foo.h" // expected-no-diagnostics diff --git a/test/Preprocessor/pp-modules.c b/test/Preprocessor/pp-modules.c index 09f3eee..8c283c6 100644 --- a/test/Preprocessor/pp-modules.c +++ b/test/Preprocessor/pp-modules.c @@ -3,13 +3,13 @@ // CHECK: int bar(); int bar(); -// CHECK: @import Module; /* clang -E: implicit import for "{{.*Headers[/\\]Module.h}}" */ +// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include */{{$}} #include // CHECK: int foo(); int foo(); -// CHECK: @import Module; /* clang -E: implicit import for "{{.*Headers[/\\]Module.h}}" */ +// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include */{{$}} #include #include "pp-modules.h" // CHECK: # 1 "{{.*}}pp-modules.h" 1 -// CHECK: @import Module; /* clang -E: implicit import for "{{.*}}Module.h" */{{$}} +// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include */{{$}} // CHECK: # 14 "{{.*}}pp-modules.c" 2 diff --git a/test/Preprocessor/pragma_diagnostic.c b/test/Preprocessor/pragma_diagnostic.c index 3970dbb..63d5907 100644 --- a/test/Preprocessor/pragma_diagnostic.c +++ b/test/Preprocessor/pragma_diagnostic.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef -Wno-unknown-warning-option -DAVOID_UNKNOWN_WARNING %s // rdar://2362963 #if FOO // ok. @@ -28,8 +29,10 @@ #pragma GCC diagnostic error "-Wundef" 42 // expected-warning {{unexpected token in pragma diagnostic}} #pragma GCC diagnostic error "invalid-name" // expected-warning {{pragma diagnostic expected option name (e.g. "-Wundef")}} -#pragma GCC diagnostic error "-Winvalid-name" // expected-warning {{unknown warning group '-Winvalid-name', ignored}} - +#pragma GCC diagnostic error "-Winvalid-name" +#ifndef AVOID_UNKNOWN_WARNING +// expected-warning@-2 {{unknown warning group '-Winvalid-name', ignored}} +#endif // Testing pragma clang diagnostic with -Weverything void ppo(){} // First test that we do not diagnose on this. diff --git a/test/Preprocessor/pragma_module.c b/test/Preprocessor/pragma_module.c new file mode 100644 index 0000000..d734f66 --- /dev/null +++ b/test/Preprocessor/pragma_module.c @@ -0,0 +1,11 @@ +// RUN: %clang -cc1 -E -fmodules %s -verify + +// Just checking the syntax here; the semantics are tested elsewhere. +#pragma clang module import // expected-error {{expected identifier in module name}} +#pragma clang module import ! // expected-error {{expected identifier in module name}} +#pragma clang module import if // expected-error {{expected identifier in module name}} +#pragma clang module import foo ? bar // expected-error {{expected '.' or end of directive after module name}} +#pragma clang module import foo. // expected-error {{expected identifier}} +#pragma clang module import foo.bar.baz.quux // expected-error {{module 'foo' not found}} + +#error here // expected-error {{here}} diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c index 28ccfef..01b0da7 100644 --- a/test/Preprocessor/stdint.c +++ b/test/Preprocessor/stdint.c @@ -28,8 +28,8 @@ // ARM:typedef int8_t int_fast8_t; // ARM:typedef uint8_t uint_fast8_t; // -// ARM:typedef int32_t intptr_t; -// ARM:typedef uint32_t uintptr_t; +// ARM:typedef long int intptr_t; +// ARM:typedef long unsigned int uintptr_t; // // ARM:typedef long long int intmax_t; // ARM:typedef long long unsigned int uintmax_t; @@ -74,9 +74,9 @@ // ARM:INT_FAST64_MAX_ 9223372036854775807LL // ARM:UINT_FAST64_MAX_ 18446744073709551615ULL // -// ARM:INTPTR_MIN_ (-2147483647 -1) -// ARM:INTPTR_MAX_ 2147483647 -// ARM:UINTPTR_MAX_ 4294967295U +// ARM:INTPTR_MIN_ (-2147483647L -1) +// ARM:INTPTR_MAX_ 2147483647L +// ARM:UINTPTR_MAX_ 4294967295UL // ARM:PTRDIFF_MIN_ (-2147483647 -1) // ARM:PTRDIFF_MAX_ 2147483647 // ARM:SIZE_MAX_ 4294967295U @@ -136,8 +136,8 @@ // I386:typedef int8_t int_fast8_t; // I386:typedef uint8_t uint_fast8_t; // -// I386:typedef int32_t intptr_t; -// I386:typedef uint32_t uintptr_t; +// I386:typedef int intptr_t; +// I386:typedef unsigned int uintptr_t; // // I386:typedef long long int intmax_t; // I386:typedef long long unsigned int uintmax_t; @@ -243,8 +243,8 @@ // MIPS:typedef int8_t int_fast8_t; // MIPS:typedef uint8_t uint_fast8_t; // -// MIPS:typedef int32_t intptr_t; -// MIPS:typedef uint32_t uintptr_t; +// MIPS:typedef long int intptr_t; +// MIPS:typedef long unsigned int uintptr_t; // // MIPS:typedef long long int intmax_t; // MIPS:typedef long long unsigned int uintmax_t; @@ -289,9 +289,9 @@ // MIPS:INT_FAST64_MAX_ 9223372036854775807LL // MIPS:UINT_FAST64_MAX_ 18446744073709551615ULL // -// MIPS:INTPTR_MIN_ (-2147483647 -1) -// MIPS:INTPTR_MAX_ 2147483647 -// MIPS:UINTPTR_MAX_ 4294967295U +// MIPS:INTPTR_MIN_ (-2147483647L -1) +// MIPS:INTPTR_MAX_ 2147483647L +// MIPS:UINTPTR_MAX_ 4294967295UL // MIPS:PTRDIFF_MIN_ (-2147483647 -1) // MIPS:PTRDIFF_MAX_ 2147483647 // MIPS:SIZE_MAX_ 4294967295U @@ -350,8 +350,8 @@ // MIPS64:typedef int8_t int_fast8_t; // MIPS64:typedef uint8_t uint_fast8_t; // -// MIPS64:typedef int64_t intptr_t; -// MIPS64:typedef uint64_t uintptr_t; +// MIPS64:typedef long int intptr_t; +// MIPS64:typedef long unsigned int uintptr_t; // // MIPS64:typedef long int intmax_t; // MIPS64:typedef long unsigned int uintmax_t; @@ -450,8 +450,8 @@ // MSP430:typedef int8_t int_fast8_t; // MSP430:typedef uint8_t uint_fast8_t; // -// MSP430:typedef int16_t intptr_t; -// MSP430:typedef uint16_t uintptr_t; +// MSP430:typedef int intptr_t; +// MSP430:typedef unsigned int uintptr_t; // // MSP430:typedef long long int intmax_t; // MSP430:typedef long long unsigned int uintmax_t; @@ -557,8 +557,8 @@ // PPC64:typedef int8_t int_fast8_t; // PPC64:typedef uint8_t uint_fast8_t; // -// PPC64:typedef int64_t intptr_t; -// PPC64:typedef uint64_t uintptr_t; +// PPC64:typedef long int intptr_t; +// PPC64:typedef long unsigned int uintptr_t; // // PPC64:typedef long int intmax_t; // PPC64:typedef long unsigned int uintmax_t; @@ -664,8 +664,8 @@ // PPC64-NETBSD:typedef int8_t int_fast8_t; // PPC64-NETBSD:typedef uint8_t uint_fast8_t; // -// PPC64-NETBSD:typedef int64_t intptr_t; -// PPC64-NETBSD:typedef uint64_t uintptr_t; +// PPC64-NETBSD:typedef long int intptr_t; +// PPC64-NETBSD:typedef long unsigned int uintptr_t; // // PPC64-NETBSD:typedef long long int intmax_t; // PPC64-NETBSD:typedef long long unsigned int uintmax_t; @@ -710,12 +710,12 @@ // PPC64-NETBSD:INT_FAST64_MAX_ 9223372036854775807LL // PPC64-NETBSD:UINT_FAST64_MAX_ 18446744073709551615ULL // -// PPC64-NETBSD:INTPTR_MIN_ (-9223372036854775807LL -1) -// PPC64-NETBSD:INTPTR_MAX_ 9223372036854775807LL -// PPC64-NETBSD:UINTPTR_MAX_ 18446744073709551615ULL -// PPC64-NETBSD:PTRDIFF_MIN_ (-9223372036854775807LL -1) -// PPC64-NETBSD:PTRDIFF_MAX_ 9223372036854775807LL -// PPC64-NETBSD:SIZE_MAX_ 18446744073709551615ULL +// PPC64-NETBSD:INTPTR_MIN_ (-9223372036854775807L -1) +// PPC64-NETBSD:INTPTR_MAX_ 9223372036854775807L +// PPC64-NETBSD:UINTPTR_MAX_ 18446744073709551615UL +// PPC64-NETBSD:PTRDIFF_MIN_ (-9223372036854775807L -1) +// PPC64-NETBSD:PTRDIFF_MAX_ 9223372036854775807L +// PPC64-NETBSD:SIZE_MAX_ 18446744073709551615UL // // PPC64-NETBSD:INTMAX_MIN_ (-9223372036854775807LL -1) // PPC64-NETBSD:INTMAX_MAX_ 9223372036854775807LL @@ -772,8 +772,8 @@ // PPC:typedef int8_t int_fast8_t; // PPC:typedef uint8_t uint_fast8_t; // -// PPC:typedef int32_t intptr_t; -// PPC:typedef uint32_t uintptr_t; +// PPC:typedef long int intptr_t; +// PPC:typedef long unsigned int uintptr_t; // // PPC:typedef long long int intmax_t; // PPC:typedef long long unsigned int uintmax_t; @@ -818,12 +818,12 @@ // PPC:INT_FAST64_MAX_ 9223372036854775807LL // PPC:UINT_FAST64_MAX_ 18446744073709551615ULL // -// PPC:INTPTR_MIN_ (-2147483647 -1) -// PPC:INTPTR_MAX_ 2147483647 -// PPC:UINTPTR_MAX_ 4294967295U -// PPC:PTRDIFF_MIN_ (-2147483647 -1) -// PPC:PTRDIFF_MAX_ 2147483647 -// PPC:SIZE_MAX_ 4294967295U +// PPC:INTPTR_MIN_ (-2147483647L -1) +// PPC:INTPTR_MAX_ 2147483647L +// PPC:UINTPTR_MAX_ 4294967295UL +// PPC:PTRDIFF_MIN_ (-2147483647L -1) +// PPC:PTRDIFF_MAX_ 2147483647L +// PPC:SIZE_MAX_ 4294967295UL // // PPC:INTMAX_MIN_ (-9223372036854775807LL -1) // PPC:INTMAX_MAX_ 9223372036854775807LL @@ -879,8 +879,8 @@ // S390X:typedef int8_t int_fast8_t; // S390X:typedef uint8_t uint_fast8_t; // -// S390X:typedef int64_t intptr_t; -// S390X:typedef uint64_t uintptr_t; +// S390X:typedef long int intptr_t; +// S390X:typedef long unsigned int uintptr_t; // // S390X:typedef long int intmax_t; // S390X:typedef long unsigned int uintmax_t; @@ -986,8 +986,8 @@ // SPARC:typedef int8_t int_fast8_t; // SPARC:typedef uint8_t uint_fast8_t; // -// SPARC:typedef int32_t intptr_t; -// SPARC:typedef uint32_t uintptr_t; +// SPARC:typedef int intptr_t; +// SPARC:typedef unsigned int uintptr_t; // // SPARC:typedef long long int intmax_t; // SPARC:typedef long long unsigned int uintmax_t; @@ -1086,8 +1086,8 @@ // TCE:typedef int8_t int_fast8_t; // TCE:typedef uint8_t uint_fast8_t; // -// TCE:typedef int32_t intptr_t; -// TCE:typedef uint32_t uintptr_t; +// TCE:typedef int intptr_t; +// TCE:typedef unsigned int uintptr_t; // // TCE:typedef long int intmax_t; // TCE:typedef long unsigned int uintmax_t; @@ -1139,9 +1139,9 @@ // TCE:PTRDIFF_MAX_ 2147483647 // TCE:SIZE_MAX_ 4294967295U // -// TCE:INTMAX_MIN_ (-2147483647 -1) -// TCE:INTMAX_MAX_ 2147483647 -// TCE:UINTMAX_MAX_ 4294967295U +// TCE:INTMAX_MIN_ (-2147483647L -1) +// TCE:INTMAX_MAX_ 2147483647L +// TCE:UINTMAX_MAX_ 4294967295UL // // TCE:SIG_ATOMIC_MIN_ (-2147483647 -1) // TCE:SIG_ATOMIC_MAX_ 2147483647 @@ -1194,8 +1194,8 @@ // X86_64:typedef int8_t int_fast8_t; // X86_64:typedef uint8_t uint_fast8_t; // -// X86_64:typedef int64_t intptr_t; -// X86_64:typedef uint64_t uintptr_t; +// X86_64:typedef long int intptr_t; +// X86_64:typedef long unsigned int uintptr_t; // // X86_64:typedef long int intmax_t; // X86_64:typedef long unsigned int uintmax_t; @@ -1314,8 +1314,8 @@ // XCORE:typedef int8_t int_fast8_t; // XCORE:typedef uint8_t uint_fast8_t; // -// XCORE:typedef int32_t intptr_t; -// XCORE:typedef uint32_t uintptr_t; +// XCORE:typedef int intptr_t; +// XCORE:typedef unsigned int uintptr_t; // // XCORE:typedef long long int intmax_t; // XCORE:typedef long long unsigned int uintmax_t; @@ -1398,9 +1398,14 @@ // the identifiers used in the operations (int, uint, _t, INT, UINT, _MIN, // _MAX, and _C(v)) are themselves macros. // -// RUN: %clang_cc1 -E -ffreestanding -U__UINTMAX_TYPE__ -U__INTMAX_TYPE__ -Dint=a -Duint=b -D_t=c -DINT=d -DUINT=e -D_MIN=f -D_MAX=g '-D_C(v)=h' -triple=i386-none-none %s | FileCheck -check-prefix JOIN %s -// JOIN:typedef int32_t intptr_t; -// JOIN:typedef uint32_t uintptr_t; +// RUN: %clang_cc1 -E -ffreestanding \ +// RUN: -U__UINTPTR_TYPE__ -U__INTPTR_TYPE__ \ +// RUN: -U__UINTMAX_TYPE__ -U__INTMAX_TYPE__ \ +// RUN: -Dint=a -Duint=b -D_t=c -DINT=d -DUINT=e -D_MIN=f -D_MAX=g \ +// RUN: '-D_C(v)=h' -triple=i386-none-none %s \ +// RUN: | FileCheck -check-prefix JOIN %s +// JOIN:typedef __INTPTR_TYPE__ intptr_t; +// JOIN:typedef __UINTPTR_TYPE__ uintptr_t; // JOIN:typedef __INTMAX_TYPE__ intmax_t; // JOIN:typedef __UINTMAX_TYPE__ uintmax_t; // JOIN:INTPTR_MIN_ (-2147483647 -1) diff --git a/test/Profile/c-outdated-data.c b/test/Profile/c-outdated-data.c index e61ad02..b686f94 100644 --- a/test/Profile/c-outdated-data.c +++ b/test/Profile/c-outdated-data.c @@ -4,23 +4,23 @@ // doesn't play well with warnings that have no line number. // RUN: llvm-profdata merge %S/Inputs/c-outdated-data.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata -Wprofile-instr-dropped 2>&1 | FileCheck %s -// CHECK: warning: profile data may be out of date: of 3 functions, 1 has no data and 1 has mismatched data that will be ignored +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING + +// NO_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored +// NO_MISSING-NOT: 1 has no data + +// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored +// WITH_MISSING: warning: profile data may be incomplete: of 3 functions, 1 has no data void no_usable_data() { int i = 0; if (i) {} - -#ifdef GENERATE_OUTDATED_DATA - if (i) {} -#endif } -#ifndef GENERATE_OUTDATED_DATA void no_data() { } -#endif int main(int argc, const char *argv[]) { no_usable_data(); diff --git a/test/Sema/integer-overflow.c b/test/Sema/integer-overflow.c index e74bc11..62ee33e 100644 --- a/test/Sema/integer-overflow.c +++ b/test/Sema/integer-overflow.c @@ -147,6 +147,19 @@ uint64_t check_integer_overflows(int i) { uint64_t a[10]; a[4608 * 1024 * 1024] = 1i; +// expected-warning@+2 {{overflow in expression; result is 536870912 with type 'int'}} + uint64_t *b; + uint64_t b2 = b[4608 * 1024 * 1024] + 1; + +// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} + int j1 = i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024); + +// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} + int j2 = -(4608 * 1024 * 1024); + +// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} + uint64_t j3 = b[4608 * 1024 * 1024]; + // expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024))); } diff --git a/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp b/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp new file mode 100644 index 0000000..00fa5bd --- /dev/null +++ b/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=c++11 -triple armv7-unknown-linux-gnueabi -fsyntax-only -verify %s + +struct a { + int __attribute__((no_caller_saved_registers)) b; // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + static void foo(int *a) __attribute__((no_caller_saved_registers)) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} +}; + +struct a test __attribute__((no_caller_saved_registers)); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +__attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +__attribute__((no_caller_saved_registers)) void foo(int *){} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +typedef void (*foo5)(int *); + +int (*foo4)(double a, __attribute__((no_caller_saved_registers)) float b); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + +int main(int argc, char **argv) { + void (*fp)(int *) = foo; + a::foo(&argc); + foo3 func = foo2; + func(&argc); + foo5 __attribute__((no_caller_saved_registers)) func2 = foo2; // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} + return 0; +} diff --git a/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp new file mode 100644 index 0000000..48ccdec --- /dev/null +++ b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s + +struct a { + int b __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'int'}} + static void foo(int *a) __attribute__((no_caller_saved_registers)) {} +}; + +struct a test __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'struct a'}} + +__attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-error {{'no_caller_saved_registers' attribute takes no arguments}} + +void __attribute__((no_caller_saved_registers)) foo(int *){} + +[[gnu::no_caller_saved_registers]] void foo2(int *) {} + +typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *); + +int (*foo4)(double a, __attribute__((no_caller_saved_registers)) float b); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'float'}} + +typedef void (*foo5)(int *); + +void foo6(){} // expected-note {{previous declaration is here}} + +void __attribute__((no_caller_saved_registers)) foo6(); // expected-error {{function declared with 'no_caller_saved_registers' attribute was previously declared without the 'no_caller_saved_registers' attribute}} + +int main(int argc, char **argv) { + void (*fp)(int *) = foo; // expected-error {{cannot initialize a variable of type 'void (*)(int *)' with an lvalue of type 'void (int *)__attribute__((no_caller_saved_registers))'}} + a::foo(&argc); + foo3 func = foo2; + func(&argc); + foo5 __attribute__((no_caller_saved_registers)) func2 = foo2; + return 0; +} diff --git a/test/SemaCXX/constexpr-array-unknown-bound.cpp b/test/SemaCXX/constexpr-array-unknown-bound.cpp new file mode 100644 index 0000000..1d14623 --- /dev/null +++ b/test/SemaCXX/constexpr-array-unknown-bound.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++1z -fsyntax-only -verify + +const extern int arr[]; +constexpr auto p = arr; // ok +constexpr int f(int i) {return p[i];} // expected-note {{read of dereferenced one-past-the-end pointer}} + +constexpr int arr[] {1, 2, 3}; +constexpr auto p2 = arr + 2; // ok +constexpr int x = f(2); // ok +constexpr int y = f(3); // expected-error {{constant expression}} +// expected-note-re@-1 {{in call to 'f({{.*}})'}} + +struct A {int m[];} a; +constexpr auto p3 = a.m; // ok +constexpr auto p4 = a.m + 1; // expected-error {{constant expression}} expected-note {{constant bound}} + +void g(int i) { + int arr[i]; + constexpr auto *p = arr + 2; // expected-error {{constant expression}} expected-note {{constant bound}} + + // FIXME: Give a better diagnostic here. The issue is that computing + // sizeof(*arr2) within the array indexing fails due to the VLA. + int arr2[2][i]; + constexpr int m = ((void)arr2[2], 0); // expected-error {{constant expression}} +} diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp index 48597de..c59ee61 100644 --- a/test/SemaCXX/typo-correction.cpp +++ b/test/SemaCXX/typo-correction.cpp @@ -679,3 +679,30 @@ int g() { sizeof(c0is0)]; // expected-error {{use of undeclared identifier}} }; } + +namespace avoidRedundantRedefinitionErrors { +class Class { + void function(int pid); // expected-note {{'function' declared here}} +}; + +void Class::function2(int pid) { // expected-error {{out-of-line definition of 'function2' does not match any declaration in 'avoidRedundantRedefinitionErrors::Class'; did you mean 'function'?}} +} + +// Expected no redefinition error here. +void Class::function(int pid) { // expected-note {{previous definition is here}} +} + +void Class::function(int pid) { // expected-error {{redefinition of 'function'}} +} + +namespace ns { +void create_test(); // expected-note {{'create_test' declared here}} +} + +void ns::create_test2() { // expected-error {{out-of-line definition of 'create_test2' does not match any declaration in namespace 'avoidRedundantRedefinitionErrors::ns'; did you mean 'create_test'?}} +} + +// Expected no redefinition error here. +void ns::create_test() { +} +} diff --git a/test/SemaObjC/x86-method-vector-values.m b/test/SemaObjC/x86-method-vector-values.m new file mode 100644 index 0000000..6c5189d --- /dev/null +++ b/test/SemaObjC/x86-method-vector-values.m @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.10 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.4 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-darwin14 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -triple=i686-apple-ios8 -Wno-objc-root-class %s + +// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-macosx10.11 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-darwin15 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DIOS -triple=i686-apple-ios9 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-watchos -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-tvos -Wno-objc-root-class %s + +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=x86_64-apple-macosx10.10 -Wno-objc-root-class %s + +// rdar://21662309 + +typedef __attribute__((__ext_vector_type__(3))) float float3; + +typedef float __m128 __attribute__((__vector_size__(16))); + +struct Aggregate { __m128 v; }; +struct AggregateFloat { float v; }; + +#define AVAILABLE_MACOS_10_10 __attribute__((availability(macos, introduced = 10.10))) +#define AVAILABLE_MACOS_10_11 __attribute__((availability(macos, introduced = 10.11))) + +#define AVAILABLE_IOS_8 __attribute__((availability(ios, introduced = 8.0))) +#define AVAILABLE_IOS_9 __attribute__((availability(ios, introduced = 9.0))) + +@interface VectorMethods + +-(void)takeVector:(float3)v; // there should be no diagnostic at declaration +-(void)takeM128:(__m128)v; + +@end + +@implementation VectorMethods + +#ifndef ALLOW + +-(void)takeVector:(float3)v { +#ifdef MAC + // expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in macOS 10.11}} +#else + // expected-error@-4 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in iOS 9}} +#endif +} + +-(float3)retVector { // expected-error {{'float3' (vector of 3 'float' values) return type is unsupported}} +} + +-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +- (__m128)retM128 { // expected-error {{'__m128' (vector of 4 'float' values) return type is unsupported}} +} + +- (void)takeM128:(__m128)v { // expected-error {{'__m128' (vector of 4 'float' values) parameter type is unsupported}} +} + +#else + +-(void)takeVector:(float3)v { +} + +-(float3)retVector { + return 0; +} + +- (__m128)retM128 { + __m128 value; + return value; +} + +- (void)takeM128:(__m128)v { +} + +-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { +#ifdef MAC +// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +#endif +} + +- (__m128)retM128_2 AVAILABLE_MACOS_10_10 { +#ifdef MAC +// expected-error@-2 {{'__m128' (vector of 4 'float' values) return type is unsupported}} +#endif + __m128 value; + return value; +} + +-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // no error +} + +-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { +#ifdef IOS + // expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +#endif +} + +-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // no error +} + +#ifdef OTHER +// expected-no-diagnostics +#endif + +#endif + +-(void)doStuff:(int)m { // no error +} + +-(struct Aggregate)takesAndRetVectorInAggregate:(struct Aggregate)f { // no error + struct Aggregate result; + return result; +} + +-(struct AggregateFloat)takesAndRetFloatInAggregate:(struct AggregateFloat)f { // no error + struct AggregateFloat result; + return result; +} + + +@end diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index e8763ff..1179fbf 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1560,6 +1560,51 @@ static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Target information testing. */ +/******************************************************************************/ + +static int print_target_info(int argc, const char **argv) { + CXIndex Idx; + CXTranslationUnit TU; + CXTargetInfo TargetInfo; + CXString Triple; + const char *FileName; + enum CXErrorCode Err; + int PointerWidth; + + if (argc == 0) { + fprintf(stderr, "No filename specified\n"); + return 1; + } + + FileName = argv[1]; + + Idx = clang_createIndex(0, 1); + Err = clang_parseTranslationUnit2(Idx, FileName, argv, argc, NULL, 0, + getDefaultParsingOptions(), &TU); + if (Err != CXError_Success) { + fprintf(stderr, "Couldn't parse translation unit!\n"); + describeLibclangFailure(Err); + clang_disposeIndex(Idx); + return 1; + } + + TargetInfo = clang_getTranslationUnitTargetInfo(TU); + + Triple = clang_TargetInfo_getTriple(TargetInfo); + printf("TargetTriple: %s\n", clang_getCString(Triple)); + clang_disposeString(Triple); + + PointerWidth = clang_TargetInfo_getPointerWidth(TargetInfo); + printf("PointerWidth: %d\n", PointerWidth); + + clang_TargetInfo_dispose(TargetInfo); + clang_disposeTranslationUnit(TU); + clang_disposeIndex(Idx); + return 0; +} + +/******************************************************************************/ /* Loading ASTs/source. */ /******************************************************************************/ @@ -2437,11 +2482,14 @@ static void inspect_print_cursor(CXCursor Cursor) { clang_Cursor_getObjCSelectorIndex(Cursor)); if (clang_Cursor_isDynamicCall(Cursor)) printf(" Dynamic-call"); - if (Cursor.kind == CXCursor_ObjCMessageExpr) { + if (Cursor.kind == CXCursor_ObjCMessageExpr || + Cursor.kind == CXCursor_MemberRefExpr) { CXType T = clang_Cursor_getReceiverType(Cursor); - CXString S = clang_getTypeKindSpelling(T.kind); - printf(" Receiver-type=%s", clang_getCString(S)); - clang_disposeString(S); + if (T.kind != CXType_Invalid) { + CXString S = clang_getTypeKindSpelling(T.kind); + printf(" Receiver-type=%s", clang_getCString(S)); + clang_disposeString(S); + } } { @@ -4298,11 +4346,12 @@ static void print_usage(void) { " c-index-test -test-print-type {}*\n" " c-index-test -test-print-type-size {}*\n" " c-index-test -test-print-bitwidth {}*\n" + " c-index-test -test-print-target-info {}*\n" " c-index-test -test-print-type-declaration {}*\n" " c-index-test -print-usr [ {}]*\n" - " c-index-test -print-usr-file \n" - " c-index-test -write-pch \n"); + " c-index-test -print-usr-file \n"); fprintf(stderr, + " c-index-test -write-pch \n" " c-index-test -compilation-db [lookup ] database\n"); fprintf(stderr, " c-index-test -print-build-session-timestamp\n"); @@ -4408,6 +4457,8 @@ int cindextest_main(int argc, const char **argv) { 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 > 2 && strcmp(argv[1], "-test-print-target-info") == 0) + return print_target_info(argc - 2, argv + 2); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { if (argc > 2) return print_usrs(argv + 2, argv + argc); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 216322b..86f1047 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticCategories.h" #include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" @@ -3371,7 +3372,10 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, Args->push_back("-Xclang"); Args->push_back("-detailed-preprocessing-record"); } - + + // Suppress any editor placeholder diagnostics. + Args->push_back("-fallow-editor-placeholders"); + unsigned NumErrors = Diags->getClient()->getNumErrors(); std::unique_ptr ErrUnit; // Unless the user specified that they want the preamble on the first parse @@ -4015,6 +4019,50 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU); } +CXTargetInfo clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit) { + if (isNotUsableTU(CTUnit)) { + LOG_BAD_TU(CTUnit); + return nullptr; + } + + CXTargetInfoImpl* impl = new CXTargetInfoImpl(); + impl->TranslationUnit = CTUnit; + return impl; +} + +CXString clang_TargetInfo_getTriple(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return cxstring::createEmpty(); + + CXTranslationUnit CTUnit = TargetInfo->TranslationUnit; + assert(!isNotUsableTU(CTUnit) && + "Unexpected unusable translation unit in TargetInfo"); + + ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit); + std::string Triple = + CXXUnit->getASTContext().getTargetInfo().getTriple().normalize(); + return cxstring::createDup(Triple); +} + +int clang_TargetInfo_getPointerWidth(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return -1; + + CXTranslationUnit CTUnit = TargetInfo->TranslationUnit; + assert(!isNotUsableTU(CTUnit) && + "Unexpected unusable translation unit in TargetInfo"); + + ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit); + return CXXUnit->getASTContext().getTargetInfo().getMaxPointerWidth(); +} + +void clang_TargetInfo_dispose(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return; + + delete TargetInfo; +} + //===----------------------------------------------------------------------===// // CXFile Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index c19aa65..fb61249 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -1523,6 +1523,10 @@ int clang_Cursor_isDynamicCall(CXCursor C) { return true; } + if (auto *PropRefE = dyn_cast(E)) { + return !PropRefE->isSuperReceiver(); + } + const MemberExpr *ME = nullptr; if (isa(E)) ME = cast(E); @@ -1532,7 +1536,9 @@ int clang_Cursor_isDynamicCall(CXCursor C) { if (ME) { if (const CXXMethodDecl * MD = dyn_cast_or_null(ME->getMemberDecl())) - return MD->isVirtual() && !ME->hasQualifier(); + return MD->isVirtual() && + ME->performsVirtualDispatch( + cxcursor::getCursorContext(C).getLangOpts()); } return 0; @@ -1547,5 +1553,23 @@ CXType clang_Cursor_getReceiverType(CXCursor C) { if (const ObjCMessageExpr *MsgE = dyn_cast_or_null(E)) return cxtype::MakeCXType(MsgE->getReceiverType(), TU); + if (auto *PropRefE = dyn_cast(E)) { + return cxtype::MakeCXType( + PropRefE->getReceiverType(cxcursor::getCursorContext(C)), TU); + } + + const MemberExpr *ME = nullptr; + if (isa(E)) + ME = cast(E); + else if (const CallExpr *CE = dyn_cast(E)) + ME = dyn_cast_or_null(CE->getCallee()); + + if (ME) { + if (dyn_cast_or_null(ME->getMemberDecl())) { + auto receiverTy = ME->getBase()->IgnoreImpCasts()->getType(); + return cxtype::MakeCXType(receiverTy, TU); + } + } + return cxtype::MakeCXType(QualType(), TU); } diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h index 67c31d2..ce8469b 100644 --- a/tools/libclang/CXTranslationUnit.h +++ b/tools/libclang/CXTranslationUnit.h @@ -35,6 +35,10 @@ struct CXTranslationUnitImpl { clang::index::CommentToXMLConverter *CommentToXML; }; +struct CXTargetInfoImpl { + CXTranslationUnit TranslationUnit; +}; + namespace clang { namespace cxtu { diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp index fce7ef2..16e993e 100644 --- a/tools/libclang/CXType.cpp +++ b/tools/libclang/CXType.cpp @@ -147,6 +147,9 @@ static inline CXTranslationUnit GetTU(CXType CT) { static Optional> GetTemplateArguments(QualType Type) { assert(!Type.isNull()); + if (const auto *Specialization = Type->getAs()) + return Specialization->template_arguments(); + if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) { const auto *TemplateDecl = dyn_cast(RecordDecl); @@ -154,9 +157,6 @@ GetTemplateArguments(QualType Type) { return TemplateDecl->getTemplateArgs().asArray(); } - if (const auto *Specialization = Type->getAs()) - return Specialization->template_arguments(); - return None; } diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index f98b258..5312b7c 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -262,7 +262,8 @@ public: /// MacroUndefined - This hook is called whenever a macro #undef is seen. /// MI is released immediately following this callback. void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override {} + const MacroDefinition &MD, + const MacroDirective *UD) override {} /// MacroExpands - This is called by when a macro invocation is found. void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 38eceda..895dd80 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -79,6 +79,9 @@ clang_TParamCommandComment_getParamName clang_TParamCommandComment_isParamPositionValid clang_TParamCommandComment_getDepth clang_TParamCommandComment_getIndex +clang_TargetInfo_dispose +clang_TargetInfo_getPointerWidth +clang_TargetInfo_getTriple clang_Type_getAlignOf clang_Type_getClassType clang_Type_getSizeOf @@ -250,6 +253,7 @@ clang_getTokenLocation clang_getTokenSpelling clang_getTranslationUnitCursor clang_getTranslationUnitSpelling +clang_getTranslationUnitTargetInfo clang_getTypeDeclaration clang_getTypeKindSpelling clang_getTypeSpelling diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp index dddc3f9..aa15e16 100644 --- a/unittests/Basic/SourceManagerTest.cpp +++ b/unittests/Basic/SourceManagerTest.cpp @@ -249,12 +249,18 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { namespace { struct MacroAction { + enum Kind { kExpansion, kDefinition, kUnDefinition}; + SourceLocation Loc; std::string Name; - bool isDefinition; // if false, it is expansion. - - MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) - : Loc(Loc), Name(Name), isDefinition(isDefinition) { } + unsigned MAKind : 3; + + MacroAction(SourceLocation Loc, StringRef Name, unsigned K) + : Loc(Loc), Name(Name), MAKind(K) { } + + bool isExpansion() const { return MAKind == kExpansion; } + bool isDefinition() const { return MAKind & kDefinition; } + bool isUnDefinition() const { return MAKind & kUnDefinition; } }; class MacroTracker : public PPCallbacks { @@ -267,13 +273,22 @@ public: const MacroDirective *MD) override { Macros.push_back(MacroAction(MD->getLocation(), MacroNameTok.getIdentifierInfo()->getName(), - true)); + MacroAction::kDefinition)); + } + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD, + const MacroDirective *UD) override { + Macros.push_back( + MacroAction(UD ? UD->getLocation() : SourceLocation(), + MacroNameTok.getIdentifierInfo()->getName(), + UD ? MacroAction::kDefinition | MacroAction::kUnDefinition + : MacroAction::kUnDefinition)); } void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override { Macros.push_back(MacroAction(MacroNameTok.getLocation(), MacroNameTok.getIdentifierInfo()->getName(), - false)); + MacroAction::kExpansion)); } }; @@ -281,7 +296,10 @@ public: TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { const char *header = - "#define MACRO_IN_INCLUDE 0\n"; + "#define MACRO_IN_INCLUDE 0\n" + "#define MACRO_DEFINED\n" + "#undef MACRO_DEFINED\n" + "#undef MACRO_UNDEFINED\n"; const char *main = "#define M(x) x\n" @@ -327,34 +345,46 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { // Make sure we got the tokens that we expected. ASSERT_EQ(0U, toks.size()); - ASSERT_EQ(9U, Macros.size()); + ASSERT_EQ(15U, Macros.size()); // #define M(x) x - ASSERT_TRUE(Macros[0].isDefinition); + ASSERT_TRUE(Macros[0].isDefinition()); ASSERT_EQ("M", Macros[0].Name); // #define INC "/test-header.h" - ASSERT_TRUE(Macros[1].isDefinition); + ASSERT_TRUE(Macros[1].isDefinition()); ASSERT_EQ("INC", Macros[1].Name); // M expansion in #include M(INC) - ASSERT_FALSE(Macros[2].isDefinition); + ASSERT_FALSE(Macros[2].isDefinition()); ASSERT_EQ("M", Macros[2].Name); // INC expansion in #include M(INC) - ASSERT_FALSE(Macros[3].isDefinition); + ASSERT_TRUE(Macros[3].isExpansion()); ASSERT_EQ("INC", Macros[3].Name); // #define MACRO_IN_INCLUDE 0 - ASSERT_TRUE(Macros[4].isDefinition); + ASSERT_TRUE(Macros[4].isDefinition()); ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); + // #define MACRO_DEFINED + ASSERT_TRUE(Macros[5].isDefinition()); + ASSERT_FALSE(Macros[5].isUnDefinition()); + ASSERT_EQ("MACRO_DEFINED", Macros[5].Name); + // #undef MACRO_DEFINED + ASSERT_TRUE(Macros[6].isDefinition()); + ASSERT_TRUE(Macros[6].isUnDefinition()); + ASSERT_EQ("MACRO_DEFINED", Macros[6].Name); + // #undef MACRO_UNDEFINED + ASSERT_FALSE(Macros[7].isDefinition()); + ASSERT_TRUE(Macros[7].isUnDefinition()); + ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name); // #define INC2 - ASSERT_TRUE(Macros[5].isDefinition); - ASSERT_EQ("INC2", Macros[5].Name); + ASSERT_TRUE(Macros[8].isDefinition()); + ASSERT_EQ("INC2", Macros[8].Name); // M expansion in #include M(INC2) - ASSERT_FALSE(Macros[6].isDefinition); - ASSERT_EQ("M", Macros[6].Name); + ASSERT_FALSE(Macros[9].isDefinition()); + ASSERT_EQ("M", Macros[9].Name); // INC2 expansion in #include M(INC2) - ASSERT_FALSE(Macros[7].isDefinition); - ASSERT_EQ("INC2", Macros[7].Name); + ASSERT_TRUE(Macros[10].isExpansion()); + ASSERT_EQ("INC2", Macros[10].Name); // #define MACRO_IN_INCLUDE 0 - ASSERT_TRUE(Macros[8].isDefinition); - ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); + ASSERT_TRUE(Macros[11].isDefinition()); + ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name); // The INC expansion in #include M(INC) comes before the first // MACRO_IN_INCLUDE definition of the included file. @@ -362,7 +392,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { // The INC2 expansion in #include M(INC2) comes before the second // MACRO_IN_INCLUDE definition of the included file. - EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); } #endif diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index 7886c4f..eda9e0a 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -485,6 +485,20 @@ TEST_F(FormatTestJS, AsyncFunctions) { " let x = 1;\n" " return fetch(x);\n" "}"); + verifyFormat("async function f() {\n" + " return 1;\n" + "}\n" + "\n" + "function a() {\n" + " return 1;\n" + "}\n", + " async function f() {\n" + " return 1;\n" + "}\n" + "\n" + " function a() {\n" + " return 1;\n" + "} \n"); verifyFormat("async function* f() {\n" " yield fetch(x);\n" "}"); @@ -492,6 +506,9 @@ TEST_F(FormatTestJS, AsyncFunctions) { " return fetch(x);\n" "}"); verifyFormat("let x = async () => f();"); + verifyFormat("let x = async function() {\n" + " f();\n" + "};"); verifyFormat("let x = async();"); verifyFormat("class X {\n" " async asyncMethod() {\n" diff --git a/unittests/Frontend/CodeGenActionTest.cpp b/unittests/Frontend/CodeGenActionTest.cpp index 1d2a50c..d90c2bc 100644 --- a/unittests/Frontend/CodeGenActionTest.cpp +++ b/unittests/Frontend/CodeGenActionTest.cpp @@ -46,7 +46,7 @@ TEST(CodeGenTest, TestNullCodeGen) { "test.cc", MemoryBuffer::getMemBuffer("").release()); Invocation->getFrontendOpts().Inputs.push_back( - FrontendInputFile("test.cc", IK_CXX)); + FrontendInputFile("test.cc", InputKind::CXX)); Invocation->getFrontendOpts().ProgramAction = EmitLLVM; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler; diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp index dd6be5f..68181c7 100644 --- a/unittests/Frontend/FrontendActionTest.cpp +++ b/unittests/Frontend/FrontendActionTest.cpp @@ -83,8 +83,8 @@ TEST(ASTFrontendAction, Sanity) { invocation->getPreprocessorOpts().addRemappedFile( "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }").release()); - invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", - IK_CXX)); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", InputKind::CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler; @@ -103,8 +103,8 @@ TEST(ASTFrontendAction, IncrementalParsing) { invocation->getPreprocessorOpts().addRemappedFile( "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }").release()); - invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", - IK_CXX)); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", InputKind::CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler; @@ -130,8 +130,8 @@ TEST(ASTFrontendAction, LateTemplateIncrementalParsing) { " B(B const& b): A(b.data) {}\n" "};\n" "B c() { return B(); }\n").release()); - invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", - IK_CXX)); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", InputKind::CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler; @@ -177,7 +177,7 @@ TEST(PreprocessorFrontendAction, EndSourceFile) { "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }").release()); Invocation->getFrontendOpts().Inputs.push_back( - FrontendInputFile("test.cc", IK_CXX)); + FrontendInputFile("test.cc", InputKind::CXX)); Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler; @@ -238,7 +238,7 @@ TEST(ASTFrontendAction, ExternalSemaSource) { "int main() { foo(); }") .release()); Invocation->getFrontendOpts().Inputs.push_back( - FrontendInputFile("test.cc", IK_CXX)); + FrontendInputFile("test.cc", InputKind::CXX)); Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler; diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 9814456..7efc9bc 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1670,7 +1670,7 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport( Records.getAllDerivedDefinitions("AttrSubjectMatcherRule"); auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, const Record *MetaSubject, - const Record *Constraint = nullptr) { + const Record *Constraint) { Rules.emplace_back(MetaSubject, Constraint); std::vector ApplicableSubjects = SubjectContainer->getValueAsListOfDefs("Subjects"); @@ -1688,7 +1688,7 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport( } }; for (const auto *MetaSubject : MetaSubjects) { - MapFromSubjectsToRules(MetaSubject, MetaSubject); + MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr); std::vector Constraints = MetaSubject->getValueAsListOfDefs("Constraints"); for (const auto *Constraint : Constraints)