diff options
author | Sylvestre Ledru <sylvestre@debian.org> | 2021-12-09 13:25:41 +0100 |
---|---|---|
committer | Sylvestre Ledru <sylvestre@debian.org> | 2021-12-09 13:25:41 +0100 |
commit | 559ffb6ea96510680eb37bbfd64808e4de3cc3f2 (patch) | |
tree | 6fa4d9b4d39802c9a6a01a09d4336ceb01e904dd | |
parent | c90eb5a17ef2d625f4f332f6fd7c1196eefcd064 (diff) | |
parent | 9edb318f74bf6b01db6fe3d61ff75a8dd44b4bbd (diff) |
Update upstream source from tag 'upstream/8.17'
Update to upstream version '8.17'
with Debian dir 1a47720f06dda3047e25f7828b278a8aacdd4fb5
36 files changed, 1007 insertions, 183 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f06014..acecc08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false env: - LLVM_TAG: -12 + LLVM_TAG: -13 steps: - name: Install prerequisites diff --git a/CMakeLists.txt b/CMakeLists.txt index 923b4d9..0a0d683 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,9 +68,9 @@ endif() set(LLVM_LINK_COMPONENTS Option Support - X86AsmParser - X86Desc - X86Info + AllTargetsAsmParsers + AllTargetsDescs + AllTargetsInfos ) add_llvm_executable(include-what-you-use @@ -110,8 +110,8 @@ if (MSVC) -D_HAS_EXCEPTIONS=0 ) - # Enable bigobj support and sane C++ exception semantics. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /EHsc") + # Enable bigobj support + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") endif() # Link dynamically or statically depending on user preference. @@ -40,6 +40,8 @@ We assume you already have compiled LLVM and Clang libraries on your system, eit | 9 | 0.13 | `clang_9.0` | | 10 | 0.14 | `clang_10` | | 11 | 0.15 | `clang_11` | +| 12 | 0.16 | `clang_12` | +| 13 | 0.17 | `clang_13` | | ... | ... | ... | | main | | `master` | @@ -129,12 +131,16 @@ The `CMAKE_CXX_INCLUDE_WHAT_YOU_USE` option enables a mode where CMake first com Use it like this: mkdir build && cd build - CC="clang" CXX="clang++" cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="path/to/iwyu;-Xiwyu;any;-Xiwyu;iwyu;-Xiwyu;args" ... + CC="clang" CXX="clang++" cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=include-what-you-use ... or, on Windows systems: mkdir build && cd build - cmake -DCMAKE_CXX_COMPILER="%VCINSTALLDIR%/bin/cl.exe" -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="path/to/iwyu;-Xiwyu;any;-Xiwyu;iwyu;-Xiwyu;args" -G Ninja ... + cmake -DCMAKE_CXX_COMPILER="%VCINSTALLDIR%/bin/cl.exe" -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=include-what-you-use -G Ninja ... + +These examples assume that `include-what-you-use` is in the `PATH`. If it isn't, consider changing the value to an absolute path. Arguments to IWYU can be added using CMake's semicolon-separated list syntax, e.g.: + + ... cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-w;-Xiwyu;--verbose=7" ... The option appears to be separately supported for both C and C++, so use `CMAKE_C_INCLUDE_WHAT_YOU_USE` for C code. @@ -142,7 +148,7 @@ Note that with Microsoft's Visual C++ compiler, IWYU needs the `--driver-mode=cl #### Using with a compilation database #### -The `iwyu_tool.py` script predates the native CMake support, and works off the [compilation database format](https://clang.llvm.org/docs/JSONCompilationDatabase.html). For example, CMake generates such a database named `compile_commands.json` with the `CMAKE_EXPORT_COMPILE_COMMANDS` option enabled. +The `iwyu_tool.py` script pre-dates the native CMake support, and works off the [compilation database format](https://clang.llvm.org/docs/JSONCompilationDatabase.html). For example, CMake generates such a database named `compile_commands.json` with the `CMAKE_EXPORT_COMPILE_COMMANDS` option enabled. The script's command-line syntax is designed to mimic Clang's LibTooling, but they are otherwise unrelated. It can be used like this: diff --git a/fix_includes.py b/fix_includes.py index 7600361..8de5775 100755 --- a/fix_includes.py +++ b/fix_includes.py @@ -2309,11 +2309,12 @@ def ProcessIWYUOutput(f, files_to_process, flags, cwd): # seen for them. (We have to wait until we're all done, since a .h # file may have a contentful change when #included from one .cc # file, but not another, and we need to have merged them above.) - for filename in iwyu_output_records: - if not iwyu_output_records[filename].HasContentfulChanges(): - print('(skipping %s: iwyu reports no contentful changes)' % filename) - # Mark that we're skipping this file by setting the record to None - iwyu_output_records[filename] = None + if not flags.update_comments: + for filename in iwyu_output_records: + if not iwyu_output_records[filename].HasContentfulChanges(): + print('(skipping %s: iwyu reports no contentful changes)' % filename) + # Mark that we're skipping this file by setting the record to None + iwyu_output_records[filename] = None # Now do all the fixing, and return the number of files modified contentful_records = [ior for ior in iwyu_output_records.values() if ior] @@ -2373,6 +2374,12 @@ def main(argv): help='Put comments after the #include lines') parser.add_option('--nocomments', action='store_false', dest='comments') + parser.add_option('--update_comments', action='store_true', default=False, + help=('Update #include comments, even if no #include lines' + ' are added or removed')) + parser.add_option('--noupdate_comments', action='store_false', + dest='update_comments') + parser.add_option('--safe_headers', action='store_true', default=True, help=('Do not remove unused #includes/fwd-declares from' ' header files; just add new ones [default]')) @@ -2440,6 +2447,9 @@ def main(argv): not flags.separate_project_includes.endswith('/')): flags.separate_project_includes += os.path.sep + if flags.update_comments: + flags.comments = True + if flags.sort_only: if not files_to_modify: sys.exit('FATAL ERROR: -s flag requires a list of filenames') diff --git a/fix_includes_test.py b/fix_includes_test.py index 380da54..07bd78d 100755 --- a/fix_includes_test.py +++ b/fix_includes_test.py @@ -34,6 +34,7 @@ class FakeFlags(object): def __init__(self): self.blank_lines = False self.comments = True + self.update_comments = False self.dry_run = False self.ignore_re = None self.only_re = None @@ -1916,6 +1917,54 @@ The full include-list for subdir/include_comments.cc: self.RegisterFileContents({'subdir/include_comments.cc': infile}) self.ProcessAndTest(iwyu_output) + def testUpdateCommentsFlag(self): + """Tests we update comments with --update_comments.""" + self.flags.update_comments = True + infile = """\ +#include "must_keep.h" // IWYU pragma: keep +#include "used.h" // for SomethingElse ///- +///+#include "used.h" // for Used + +Used used; +int main() { return 0; } +""" + iwyu_output = """\ +subdir/include_comments.cc should add these lines: + +subdir/include_comments.cc should remove these lines: + +The full include-list for subdir/include_comments.cc: +#include "must_keep.h" +#include "used.h" // for Used +--- +""" + self.RegisterFileContents({'subdir/include_comments.cc': infile}) + self.ProcessAndTest(iwyu_output) + + def testNoUpdateCommentsFlag(self): + """Tests we don't update comments with --noupdate_comments.""" + self.flags.update_comments = False + infile = """\ +#include "must_keep.h" // IWYU pragma: keep +#include "used.h" // for SomethingElse + +Used used; +int main() { return 0; } +""" + iwyu_output = """\ +subdir/include_comments.cc should add these lines: + +subdir/include_comments.cc should remove these lines: + +The full include-list for subdir/include_comments.cc: +#include "must_keep.h" +#include "used.h" // for Used +--- +""" + self.RegisterFileContents({'subdir/include_comments.cc': infile}) + self.ProcessAndTest(iwyu_output, + unedited_files=['subdir/include_comments.cc']) + def testFixingTwoFiles(self): """Make sure data for one fix doesn't overlap with a second.""" file_a = """\ diff --git a/gcc.libc.imp b/gcc.libc.imp index 1d436f5..a6493f6 100644 --- a/gcc.libc.imp +++ b/gcc.libc.imp @@ -203,4 +203,6 @@ { include: [ "<linux/limits.h>", private, "<limits.h>", public ] }, # PATH_MAX { include: [ "<linux/prctl.h>", private, "<sys/prctl.h>", public ] }, { include: [ "<sys/ucontext.h>", private, "<ucontext.h>", public ] }, + # Exports guaranteed by the C standard + { include: [ "<stdint.h>", public, "<inttypes.h>", public ] }, ] diff --git a/gcc.symbols.imp b/gcc.symbols.imp index 5ecf219..616fdef 100644 --- a/gcc.symbols.imp +++ b/gcc.symbols.imp @@ -9,22 +9,36 @@ # equivalents. # In each case, I ordered them so <sys/types.h> was first, if it was # an option for this type. That's the preferred #include all else -# equal. The visibility on the symbol-name is ignored; by convention -# we always set it to private. +# equal. The same goes for <stdint.h>. The visibility on the +# symbol-name is ignored; by convention we always set it to private. [ - { symbol: [ "blksize_t", private, "<sys/types.h>", public ] }, - { symbol: [ "blkcnt_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "aiocb", private, "<aio.h>", public ] }, { symbol: [ "blkcnt_t", private, "<sys/types.h>", public ] }, + { symbol: [ "blkcnt_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "blksize_t", private, "<sys/types.h>", public ] }, { symbol: [ "blksize_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "cc_t", private, "<termios.h>", public ] }, { symbol: [ "clock_t", private, "<sys/types.h>", public ] }, + { symbol: [ "clock_t", private, "<sys/time.h>", public ] }, { symbol: [ "clock_t", private, "<time.h>", public ] }, + { symbol: [ "clockid_t", private, "<sys/types.h>", public ] }, + { symbol: [ "clockid_t", private, "<time.h>", public ] }, { symbol: [ "daddr_t", private, "<sys/types.h>", public ] }, { symbol: [ "daddr_t", private, "<rpc/types.h>", public ] }, { symbol: [ "dev_t", private, "<sys/types.h>", public ] }, { symbol: [ "dev_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "div_t", private, "<stdlib.h>", public ] }, + { symbol: [ "double_t", private, "<math.h>", public ] }, { symbol: [ "error_t", private, "<errno.h>", public ] }, { symbol: [ "error_t", private, "<argp.h>", public ] }, { symbol: [ "error_t", private, "<argz.h>", public ] }, + { symbol: [ "fd_set", private, "<sys/select.h>", public ] }, + { symbol: [ "fd_set", private, "<sys/time.h>", public ] }, + { symbol: [ "fenv_t", private, "<fenv.h>", public ] }, + { symbol: [ "fexcept_t", private, "<fenv.h>", public ] }, + { symbol: [ "FILE", private, "<stdio.h>", public ] }, + { symbol: [ "FILE", private, "<wchar.h>", public ] }, + { symbol: [ "float_t", private, "<math.h>", public ] }, { symbol: [ "fsblkcnt_t", private, "<sys/types.h>", public ] }, { symbol: [ "fsblkcnt_t", private, "<sys/statvfs.h>", public ] }, { symbol: [ "fsfilcnt_t", private, "<sys/types.h>", public ] }, @@ -32,18 +46,21 @@ { symbol: [ "gid_t", private, "<sys/types.h>", public ] }, { symbol: [ "gid_t", private, "<grp.h>", public ] }, { symbol: [ "gid_t", private, "<pwd.h>", public ] }, + { symbol: [ "gid_t", private, "<signal.h>", public ] }, { symbol: [ "gid_t", private, "<stropts.h>", public ] }, { symbol: [ "gid_t", private, "<sys/ipc.h>", public ] }, { symbol: [ "gid_t", private, "<sys/stat.h>", public ] }, { symbol: [ "gid_t", private, "<unistd.h>", public ] }, { symbol: [ "id_t", private, "<sys/types.h>", public ] }, { symbol: [ "id_t", private, "<sys/resource.h>", public ] }, + { symbol: [ "imaxdiv_t", private, "<inttypes.h>", public ] }, + { symbol: [ "intmax_t", private, "<stdint.h>", public ] }, + { symbol: [ "uintmax_t", private, "<stdint.h>", public ] }, { symbol: [ "ino64_t", private, "<sys/types.h>", public ] }, { symbol: [ "ino64_t", private, "<dirent.h>", public ] }, { symbol: [ "ino_t", private, "<sys/types.h>", public ] }, { symbol: [ "ino_t", private, "<dirent.h>", public ] }, { symbol: [ "ino_t", private, "<sys/stat.h>", public ] }, - { symbol: [ "int8_t", private, "<sys/types.h>", public ] }, { symbol: [ "int8_t", private, "<stdint.h>", public ] }, { symbol: [ "int16_t", private, "<stdint.h>", public ] }, { symbol: [ "int32_t", private, "<stdint.h>", public ] }, @@ -54,69 +71,138 @@ { symbol: [ "uint64_t", private, "<stdint.h>", public ] }, { symbol: [ "intptr_t", private, "<stdint.h>", public ] }, { symbol: [ "uintptr_t", private, "<stdint.h>", public ] }, - { symbol: [ "intptr_t", private, "<unistd.h>", public ] }, { symbol: [ "key_t", private, "<sys/types.h>", public ] }, { symbol: [ "key_t", private, "<sys/ipc.h>", public ] }, + { symbol: [ "lconv", private, "<locale.h>", public ] }, + { symbol: [ "ldiv_t", private, "<stdlib.h>", public ] }, + { symbol: [ "lldiv_t", private, "<stdlib.h>", public ] }, { symbol: [ "max_align_t", private, "<stddef.h>", public ] }, { symbol: [ "mode_t", private, "<sys/types.h>", public ] }, - { symbol: [ "mode_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "mode_t", private, "<fcntl.h>", public ] }, + { symbol: [ "mode_t", private, "<ndbm.h>", public ] }, + { symbol: [ "mode_t", private, "<spawn.h>", public ] }, { symbol: [ "mode_t", private, "<sys/ipc.h>", public ] }, { symbol: [ "mode_t", private, "<sys/mman.h>", public ] }, + { symbol: [ "mode_t", private, "<sys/stat.h>", public ] }, { symbol: [ "nlink_t", private, "<sys/types.h>", public ] }, { symbol: [ "nlink_t", private, "<sys/stat.h>", public ] }, { symbol: [ "off64_t", private, "<sys/types.h>", public ] }, { symbol: [ "off64_t", private, "<unistd.h>", public ] }, { symbol: [ "off_t", private, "<sys/types.h>", public ] }, - { symbol: [ "off_t", private, "<unistd.h>", public ] }, - { symbol: [ "off_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "off_t", private, "<aio.h>", public ] }, + { symbol: [ "off_t", private, "<fcntl.h>", public ] }, + { symbol: [ "off_t", private, "<stdio.h>", public ] }, { symbol: [ "off_t", private, "<sys/mman.h>", public ] }, + { symbol: [ "off_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "off_t", private, "<unistd.h>", public ] }, { symbol: [ "pid_t", private, "<sys/types.h>", public ] }, - { symbol: [ "pid_t", private, "<unistd.h>", public ] }, + { symbol: [ "pid_t", private, "<fcntl.h>", public ] }, + { symbol: [ "pid_t", private, "<sched.h>", public ] }, { symbol: [ "pid_t", private, "<signal.h>", public ] }, + { symbol: [ "pid_t", private, "<spawn.h>", public ] }, { symbol: [ "pid_t", private, "<sys/msg.h>", public ] }, + { symbol: [ "pid_t", private, "<sys/sem.h>", public ] }, { symbol: [ "pid_t", private, "<sys/shm.h>", public ] }, + { symbol: [ "pid_t", private, "<sys/wait.h>", public ] }, { symbol: [ "pid_t", private, "<termios.h>", public ] }, { symbol: [ "pid_t", private, "<time.h>", public ] }, + { symbol: [ "pid_t", private, "<unistd.h>", public ] }, { symbol: [ "pid_t", private, "<utmpx.h>", public ] }, { symbol: [ "ptrdiff_t", private, "<stddef.h>", public ] }, + { symbol: [ "regex_t", private, "<regex.h>", public ] }, + { symbol: [ "regmatch_t", private, "<regex.h>", public ] }, + { symbol: [ "regoff_t", private, "<regex.h>", public ] }, + { symbol: [ "sigevent", private, "<signal.h>", public ] }, + { symbol: [ "sigevent", private, "<aio.h>", public ] }, + { symbol: [ "sigevent", private, "<mqueue.h>", public ] }, + { symbol: [ "sigevent", private, "<time.h>", public ] }, + { symbol: [ "siginfo_t", private, "<signal.h>", public ] }, + { symbol: [ "siginfo_t", private, "<sys/wait.h>", public ] }, { symbol: [ "sigset_t", private, "<signal.h>", public ] }, - { symbol: [ "sigset_t", private, "<sys/epoll.h>", public ] }, + { symbol: [ "sigset_t", private, "<spawn.h>", public ] }, { symbol: [ "sigset_t", private, "<sys/select.h>", public ] }, - { symbol: [ "socklen_t", private, "<bits/socket.h>", private ] }, - { symbol: [ "socklen_t", private, "<unistd.h>", public ] }, - { symbol: [ "socklen_t", private, "<arpa/inet.h>", public ] }, + { symbol: [ "sigval", private, "<signal.h>", public ] }, + { symbol: [ "sockaddr", private, "<sys/socket.h>", public ] }, + { symbol: [ "socklen_t", private, "<sys/socket.h>", public ] }, + { symbol: [ "socklen_t", private, "<netdb.h>", public ] }, { symbol: [ "ssize_t", private, "<sys/types.h>", public ] }, - { symbol: [ "ssize_t", private, "<unistd.h>", public ] }, + { symbol: [ "ssize_t", private, "<aio.h>", public ] }, { symbol: [ "ssize_t", private, "<monetary.h>", public ] }, + { symbol: [ "ssize_t", private, "<mqueue.h>", public ] }, + { symbol: [ "ssize_t", private, "<stdio.h>", public ] }, { symbol: [ "ssize_t", private, "<sys/msg.h>", public ] }, + { symbol: [ "ssize_t", private, "<sys/socket.h>", public ] }, + { symbol: [ "ssize_t", private, "<sys/uio.h>", public ] }, + { symbol: [ "ssize_t", private, "<unistd.h>", public ] }, + { symbol: [ "stat", private, "<sys/stat.h>", public ] }, + { symbol: [ "stat", private, "<ftw.h>", public ] }, { symbol: [ "suseconds_t", private, "<sys/types.h>", public ] }, - { symbol: [ "suseconds_t", private, "<sys/time.h>", public ] }, { symbol: [ "suseconds_t", private, "<sys/select.h>", public ] }, - { symbol: [ "time_t", private, "<sys/types.h>", public ] }, + { symbol: [ "suseconds_t", private, "<sys/time.h>", public ] }, { symbol: [ "time_t", private, "<time.h>", public ] }, + { symbol: [ "time_t", private, "<sched.h>", public ] }, + { symbol: [ "time_t", private, "<sys/msg.h>", public ] }, + { symbol: [ "time_t", private, "<sys/select.h>", public ] }, + { symbol: [ "time_t", private, "<sys/sem.h>", public ] }, + { symbol: [ "time_t", private, "<sys/shm.h>", public ] }, + { symbol: [ "time_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "time_t", private, "<sys/time.h>", public ] }, + { symbol: [ "time_t", private, "<sys/types.h>", public ] }, + { symbol: [ "time_t", private, "<utime.h>", public ] }, + { symbol: [ "timer_t", private, "<sys/types.h>", public ] }, + { symbol: [ "timer_t", private, "<time.h>", public ] }, { symbol: [ "timespec", private, "<time.h>", public ] }, + { symbol: [ "timespec", private, "<aio.h>", public ] }, + { symbol: [ "timespec", private, "<mqueue.h>", public ] }, + { symbol: [ "timespec", private, "<sched.h>", public ] }, + { symbol: [ "timespec", private, "<signal.h>", public ] }, + { symbol: [ "timespec", private, "<sys/select.h>", public ] }, + { symbol: [ "timespec", private, "<sys/stat.h>", public ] }, { symbol: [ "timeval", private, "<sys/time.h>", public ] }, + { symbol: [ "timeval", private, "<sys/resource.h>", public ] }, + { symbol: [ "timeval", private, "<sys/select.h>", public ] }, + { symbol: [ "timeval", private, "<utmpx.h>", public ] }, { symbol: [ "u_char", private, "<sys/types.h>", public ] }, { symbol: [ "u_char", private, "<rpc/types.h>", public ] }, { symbol: [ "uid_t", private, "<sys/types.h>", public ] }, - { symbol: [ "uid_t", private, "<unistd.h>", public ] }, { symbol: [ "uid_t", private, "<pwd.h>", public ] }, { symbol: [ "uid_t", private, "<signal.h>", public ] }, { symbol: [ "uid_t", private, "<stropts.h>", public ] }, { symbol: [ "uid_t", private, "<sys/ipc.h>", public ] }, { symbol: [ "uid_t", private, "<sys/stat.h>", public ] }, + { symbol: [ "uid_t", private, "<unistd.h>", public ] }, { symbol: [ "useconds_t", private, "<sys/types.h>", public ] }, { symbol: [ "useconds_t", private, "<unistd.h>", public ] }, { symbol: [ "wchar_t", private, "<stddef.h>", public ] }, { symbol: [ "wchar_t", private, "<stdlib.h>", public ] }, - # glob.h seems to define size_t if necessary, but it should come from stddef. { symbol: [ "size_t", private, "<stddef.h>", public ] }, + { symbol: [ "size_t", private, "<aio.h>", public ] }, + { symbol: [ "size_t", private, "<glob.h>", public ] }, + { symbol: [ "size_t", private, "<grp.h>", public ] }, + { symbol: [ "size_t", private, "<iconv.h>", public ] }, + { symbol: [ "size_t", private, "<monetary.h>", public ] }, + { symbol: [ "size_t", private, "<mqueue.h>", public ] }, + { symbol: [ "size_t", private, "<ndbm.h>", public ] }, + { symbol: [ "size_t", private, "<pwd.h>", public ] }, + { symbol: [ "size_t", private, "<regex.h>", public ] }, + { symbol: [ "size_t", private, "<search.h>", public ] }, + { symbol: [ "size_t", private, "<signal.h>", public ] }, { symbol: [ "size_t", private, "<stdio.h>", public ] }, { symbol: [ "size_t", private, "<stdlib.h>", public ] }, { symbol: [ "size_t", private, "<string.h>", public ] }, + { symbol: [ "size_t", private, "<strings.h>", public ] }, + { symbol: [ "size_t", private, "<sys/mman.h>", public ] }, + { symbol: [ "size_t", private, "<sys/msg.h>", public ] }, + { symbol: [ "size_t", private, "<sys/sem.h>", public ] }, + { symbol: [ "size_t", private, "<sys/shm.h>", public ] }, + { symbol: [ "size_t", private, "<sys/socket.h>", public ] }, + { symbol: [ "size_t", private, "<sys/types.h>", public ] }, + { symbol: [ "size_t", private, "<sys/uio.h>", public ] }, { symbol: [ "size_t", private, "<time.h>", public ] }, { symbol: [ "size_t", private, "<uchar.h>", public ] }, + { symbol: [ "size_t", private, "<unistd.h>", public ] }, { symbol: [ "size_t", private, "<wchar.h>", public ] }, + { symbol: [ "size_t", private, "<wordexp.h>", public ] }, # Macros that can be defined in more than one file, don't have the # same __foo_defined guard that other types do, so the grep above # doesn't discover them. Until I figure out a better way, I just @@ -124,7 +210,13 @@ { symbol: [ "EOF", private, "<stdio.h>", public ] }, { symbol: [ "EOF", private, "<libio.h>", public ] }, { symbol: [ "FILE", private, "<stdio.h>", public ] }, + { symbol: [ "MAP_STACK", private, "<sys/mman.h>", public ] }, + { symbol: [ "MAP_STACK", private, "<linux/mman.h>", public ] }, + { symbol: [ "SIGCHLD", private, "<signal.h>", public ] }, + { symbol: [ "SIGCHLD", private, "<linux/signal.h>", public ] }, { symbol: [ "va_list", private, "<stdarg.h>", public ] }, + { symbol: [ "va_list", private, "<stdio.h>", public ] }, + { symbol: [ "va_list", private, "<wchar.h>", public ] }, # These are symbols that could be defined in either stdlib.h or # malloc.h, but we always want the stdlib location. { symbol: [ "malloc", private, "<stdlib.h>", public ] }, @@ -167,6 +167,7 @@ using clang::ConstructorUsingShadowDecl; using clang::Decl; using clang::DeclContext; using clang::DeclRefExpr; +using clang::DeducedTemplateSpecializationType; using clang::EnumType; using clang::Expr; using clang::FileEntry; @@ -191,6 +192,7 @@ using clang::QualifiedTypeLoc; using clang::RecordDecl; using clang::RecursiveASTVisitor; using clang::ReferenceType; +using clang::Sema; using clang::SourceLocation; using clang::Stmt; using clang::SubstTemplateTypeParmType; @@ -532,17 +534,10 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { //------------------------------------------------------------ // (4) Add implicit text. - - // When we see an object that has implicit text that iwyu - // wants to look at, we make callbacks as if that text had - // been explicitly written. Here's text we consider: // - // * CXXDestructorDecl: a destructor call for each non-POD field - // in the dtor's class, and each base type of that class. - // * CXXRecordDecl: a CXXConstructorDecl for each implicit - // constructor (zero-arg and copy). A CXXDestructor decl - // if the destructor is implicit. A CXXOperatorCallDecl if - // operator= is explicit. + // This simulates a call to the destructor of every non-POD field and base + // class in all classes with destructors, to mark them as used by virtue of + // being class members. bool TraverseCXXDestructorDecl(clang::CXXDestructorDecl* decl) { if (!Base::TraverseCXXDestructorDecl(decl)) return false; if (CanIgnoreCurrentASTNode()) return true; @@ -575,69 +570,12 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { return true; } - // clang lazily constructs the implicit methods of a C++ class (the - // default constructor and destructor, etc) -- it only bothers to - // create a CXXMethodDecl if someone actually calls these classes. - // But we need to be non-lazy: iwyu depends on analyzing what future - // code *may* call in a class, not what current code *does*. So we - // force all the lazy evaluation to happen here. This will - // (possibly) add a bunch of MethodDecls to the AST, as children of - // decl. We're hoping it will always be safe to modify the AST - // while it's being traversed! - void InstantiateImplicitMethods(CXXRecordDecl* decl) { - if (decl->isDependentType()) // only instantiate if class is instantiated - return; - - clang::Sema& sema = compiler()->getSema(); - DeclContext::lookup_result ctors = sema.LookupConstructors(decl); - for (NamedDecl* ctor_lookup : ctors) { - // Ignore templated or inheriting constructors. - if (isa<FunctionTemplateDecl>(ctor_lookup) || - isa<UsingDecl>(ctor_lookup) || - isa<ConstructorUsingShadowDecl>(ctor_lookup)) - continue; - CXXConstructorDecl* ctor = cast<CXXConstructorDecl>(ctor_lookup); - if (!ctor->hasBody() && !ctor->isDeleted() && ctor->isImplicit()) { - if (sema.getSpecialMember(ctor) == clang::Sema::CXXDefaultConstructor) { - sema.DefineImplicitDefaultConstructor(CurrentLoc(), ctor); - } else { - // TODO(nlewycky): enable this! - //sema.DefineImplicitCopyConstructor(CurrentLoc(), ctor); - } - } - // Unreferenced template constructors stay uninstantiated on purpose. - } - - if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) { - if (!dtor->isDeleted()) { - if (!dtor->hasBody() && dtor->isImplicit()) - sema.DefineImplicitDestructor(CurrentLoc(), dtor); - if (!dtor->isDefined() && dtor->getTemplateInstantiationPattern()) - sema.PendingInstantiations.emplace_back(dtor, CurrentLoc()); - } - } - - // TODO(nlewycky): copy assignment operator - - // clang queues up method instantiations. We need to process them now. - sema.PerformPendingInstantiations(); - } - - // Handle implicit methods that otherwise wouldn't be seen by RAV. - bool TraverseCXXRecordDecl(clang::CXXRecordDecl* decl) { - if (CanIgnoreCurrentASTNode()) return true; - // We only care about classes that are actually defined. - if (decl && decl->isThisDeclarationADefinition()) { - InstantiateImplicitMethods(decl); - } - - return Base::TraverseCXXRecordDecl(decl); - } - + // Class template specialization are similar to regular C++ classes, + // particularly they need the same custom handling of implicit destructors. bool TraverseClassTemplateSpecializationDecl( clang::ClassTemplateSpecializationDecl* decl) { if (!Base::TraverseClassTemplateSpecializationDecl(decl)) return false; - return TraverseCXXRecordDecl(decl); + return Base::TraverseCXXRecordDecl(decl); } //------------------------------------------------------------ @@ -1322,7 +1260,26 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { for (const NamedDecl* redecl : GetClassRedecls(decl)) { if (GetFileEntry(redecl) == macro_def_file && IsForwardDecl(redecl)) { fwd_decl = redecl; + break; + } + } + + if (!fwd_decl) { + if (const auto* func_decl = dyn_cast<FunctionDecl>(decl)) { + if (const FunctionTemplateDecl* ft_decl = + func_decl->getPrimaryTemplate()) { + VERRS(5) << "No fwd-decl found, looking for function template decl\n"; + for (const NamedDecl* redecl : ft_decl->redecls()) { + if (GetFileEntry(redecl) == macro_def_file) { + fwd_decl = redecl; + break; + } + } + } + } + } + if (fwd_decl) { // Make sure we keep that forward-declaration, even if it's probably // unused in this file. IwyuFileInfo* file_info = @@ -1330,8 +1287,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { file_info->ReportForwardDeclareUse( spelling_loc, fwd_decl, ComputeUseFlags(current_ast_node()), nullptr); - break; - } } // Resolve the best use location based on our current knowledge. @@ -1460,12 +1415,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { } set<const Type*> GetCallerResponsibleTypesForTypedef( - const TypedefDecl* decl) { + const TypedefNameDecl* decl) { set<const Type*> retval; const Type* underlying_type = decl->getUnderlyingType().getTypePtr(); // If the underlying type is itself a typedef, we recurse. if (const TypedefType* underlying_typedef = DynCastFrom(underlying_type)) { - if (const TypedefDecl* underlying_typedef_decl + if (const TypedefNameDecl* underlying_typedef_decl = DynCastFrom(TypeToDeclAsWritten(underlying_typedef))) { // TODO(csilvers): if one of the intermediate typedefs // #includes the necessary definition of the 'final' @@ -1610,12 +1565,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { // anywhere. ('autocast' is similar, but is handled in // VisitCastExpr; 'fn-return-type' is also similar and is // handled in HandleFunctionCall.) - if (const TypedefDecl* typedef_decl = DynCastFrom(target_decl)) { + if (const TypedefNameDecl* typedef_decl = DynCastFrom(target_decl)) { // One exception: if this TypedefType is being used in another // typedef (that is, 'typedef MyTypedef OtherTypdef'), then the // user -- the other typedef -- is never responsible for the // underlying type. Instead, users of that typedef are. - if (!current_ast_node()->template ParentIsA<TypedefDecl>()) { + if (!current_ast_node()->template ParentIsA<TypedefNameDecl>()) { const set<const Type*>& underlying_types = GetCallerResponsibleTypesForTypedef(typedef_decl); if (!underlying_types.empty()) { @@ -1757,7 +1712,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { // iwyu will demand the full type of pair, but not of its template // arguments. This is handled not here, but below, in // VisitSubstTemplateTypeParmType. - bool VisitTypedefDecl(clang::TypedefDecl* decl) { + bool VisitTypedefNameDecl(clang::TypedefNameDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; const Type* underlying_type = decl->getUnderlyingType().getTypePtr(); const Type* deref_type @@ -1770,7 +1725,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { current_ast_node()->set_in_forward_declare_context(false); } - return Base::VisitTypedefDecl(decl); + return Base::VisitTypedefNameDecl(decl); } // If we're a declared (not defined) function, all our types -- @@ -1999,6 +1954,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { case clang::CK_IntegralToFixedPoint: case clang::CK_IntegralToFloating: case clang::CK_IntegralToPointer: + case clang::CK_MatrixCast: case clang::CK_MemberPointerToBoolean: case clang::CK_NullToMemberPointer: case clang::CK_NullToPointer: @@ -2591,7 +2547,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { // If we're in a typedef, we don't want to forward-declare even if // we're a pointer. ('typedef Foo* Bar; Bar x; x->a' needs full // type of Foo.) - if (ast_node->ParentIsA<TypedefDecl>()) + if (ast_node->ParentIsA<TypedefNameDecl>()) return false; // If we ourselves are a forward-decl -- that is, we're the type @@ -2645,8 +2601,11 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { void AddShadowDeclarations(const UsingDecl* using_decl) { for (const UsingShadowDecl* shadow : using_decl->shadows()) { - visitor_state_->using_declarations.insert( - make_pair(shadow->getTargetDecl(), shadow->getUsingDecl())); + if (const auto* introducer = + dyn_cast<UsingDecl>(shadow->getIntroducer())) { + visitor_state_->using_declarations.insert( + make_pair(shadow->getTargetDecl(), introducer)); + } } } @@ -2665,8 +2624,9 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { const DeclContext* use_context) { // First, if we have a UsingShadowDecl, then we don't need to do anything // because we can just directly return the using decl from that. - if (const UsingShadowDecl* shadow = DynCastFrom(decl)) - return shadow->getUsingDecl(); + if (const auto* shadow = dyn_cast<UsingShadowDecl>(decl)) { + return dyn_cast<UsingDecl>(shadow->getIntroducer()); + } // But, if we don't have a UsingShadowDecl, then we need to look through // all the using-decls of the given decl. We limit them to ones that are @@ -3656,11 +3616,31 @@ class IwyuAstConsumer const_cast<IwyuPreprocessorInfo*>(&preprocessor_info())-> HandlePreprocessingDone(); + TranslationUnitDecl* tu_decl = context.getTranslationUnitDecl(); + + // Sema::TUScope is reset after parsing, but Sema::getCurScope still points + // to the translation unit decl scope. TUScope is required for lookup in + // some complex scenarios, so re-wire it before running IWYU AST passes. + // Assert their expected state so we notice if these assumptions change. + Sema& sema = compiler()->getSema(); + CHECK_(sema.TUScope == nullptr); + CHECK_(sema.getCurScope() != nullptr); + sema.TUScope = sema.getCurScope(); + // We run a separate pass to force parsing of late-parsed function // templates. - ParseFunctionTemplates(context.getTranslationUnitDecl()); + ParseFunctionTemplates(sema, tu_decl); + + // Clang lazily constructs the implicit methods of a C++ class (the + // default constructor and destructor, etc) -- it only bothers to + // create a CXXMethodDecl if someone actually calls these classes. + // But we need to be non-lazy: IWYU depends on analyzing what future + // code *may* call in a class, not what current code *does*. So we + // force all the lazy evaluation to happen here. + InstantiateImplicitMethods(sema, tu_decl); - TraverseDecl(context.getTranslationUnitDecl()); + // Run IWYU analysis. + TraverseDecl(tu_decl); // Check if any unrecoverable errors have occurred. // There is no point in continuing when the AST is in a bad state. @@ -3705,9 +3685,8 @@ class IwyuAstConsumer exit(EXIT_SUCCESS_OFFSET + num_edits); } - void ParseFunctionTemplates(TranslationUnitDecl* decl) { - set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(decl); - clang::Sema& sema = compiler()->getSema(); + void ParseFunctionTemplates(Sema& sema, TranslationUnitDecl* tu_decl) { + set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(tu_decl); // If we have any late-parsed functions, make sure the // -fdelayed-template-parsing flag is on. Otherwise we don't know where @@ -3730,6 +3709,55 @@ class IwyuAstConsumer } } + void InstantiateImplicitMethods(Sema& sema, TranslationUnitDecl* tu_decl) { + // Collect all implicit ctors/dtors that need to be instantiated. + struct Visitor : public RecursiveASTVisitor<Visitor> { + Visitor(Sema& sema) : sema(sema) { + } + + bool VisitCXXRecordDecl(CXXRecordDecl* decl) { + if (CanIgnoreLocation(GetLocation(decl))) + return true; + + if (!decl->getDefinition() || decl->isDependentContext() || + decl->isBeingDefined()) { + return true; + } + + if (CXXConstructorDecl* ctor = sema.LookupDefaultConstructor(decl)) { + may_need_definition.insert(ctor); + } else if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) { + may_need_definition.insert(dtor); + } + + return true; + } + + Sema& sema; + std::set<CXXMethodDecl*> may_need_definition; + }; + + // Run visitor to collect implicit methods. + Visitor v(sema); + v.TraverseDecl(tu_decl); + + // For each method collected, let Sema define them. + for (CXXMethodDecl* method : v.may_need_definition) { + if (!method->isDefaulted() || method->isDeleted() || method->hasBody()) + continue; + + SourceLocation loc = GetLocation(method->getParent()); + if (auto* ctor = dyn_cast<CXXConstructorDecl>(method)) { + sema.DefineImplicitDefaultConstructor(loc, ctor); + } else if (auto* dtor = dyn_cast<CXXDestructorDecl>(method)) { + sema.DefineImplicitDestructor(loc, dtor); + } + } + + // Clang queues up method instantiations. Process them now. + sema.PerformPendingInstantiations(); + } + //------------------------------------------------------------ // AST visitors. We start by adding a visitor callback for // most of the subclasses of Decl/Stmt/Type listed in: @@ -3913,14 +3941,13 @@ class IwyuAstConsumer // TODO(csilvers): we can probably relax this rule in .cc files. // TODO(csilvers): this should really move into IwyuBaseASTVisitor // (that way we'll correctly identify need for hash<> in hash_set). - // This is a Traverse*() because Visit*() can't call HandleFunctionCall(). - bool TraverseTypedefDecl(clang::TypedefDecl* decl) { - // Before we go up the tree, make sure the parents know we don't - // forward-declare the underlying type of a typedef decl. - current_ast_node()->set_in_forward_declare_context(false); - if (!Base::TraverseTypedefDecl(decl)) - return false; - if (CanIgnoreCurrentASTNode()) return true; + // This is called from Traverse*() because Visit*() + // can't call HandleFunctionCall(). + bool HandleAliasedClassMethods(TypedefNameDecl* decl) { + if (CanIgnoreCurrentASTNode()) + return true; + if (current_ast_node()->in_forward_declare_context()) + return true; const Type* underlying_type = decl->getUnderlyingType().getTypePtr(); const Decl* underlying_decl = TypeToDeclAsWritten(underlying_type); @@ -3947,6 +3974,20 @@ class IwyuAstConsumer return true; } + bool TraverseTypedefDecl(clang::TypedefDecl* decl) { + if (!Base::TraverseTypedefDecl(decl)) + return false; + + return HandleAliasedClassMethods(decl); + } + + bool TraverseTypeAliasDecl(clang::TypeAliasDecl* decl) { + if (!Base::TraverseTypeAliasDecl(decl)) + return false; + + return HandleAliasedClassMethods(decl); + } + // --- Visitors of types derived from clang::Stmt. // Called whenever a variable, function, enum, etc is used. @@ -4063,18 +4104,21 @@ class IwyuAstConsumer bool VisitTemplateName(TemplateName template_name) { if (CanIgnoreCurrentASTNode()) return true; if (!Base::VisitTemplateName(template_name)) return false; - // The only time we can see a TemplateName not in the - // context of a TemplateSpecializationType is when it's - // the default argument of a template template arg: + // We can see TemplateName not in the context of aTemplateSpecializationType + // when it's either the default argument of a template template arg: // template<template<class T> class A = TplNameWithoutTST> class Foo ... - // So that's the only case we need to handle here. + // or a deduced template specialization: + // std::pair x(10, 20); // type of x is really std::pair<int, int> + // So that's the only cases we need to handle here. // TODO(csilvers): check if this is really forward-declarable or // not. You *could* do something like: 'template<template<class // T> class A = Foo> class C { A<int>* x; };' and never // dereference x, but that's pretty unlikely. So for now, we just // assume these default template template args always need full // type info. - if (IsDefaultTemplateTemplateArg(current_ast_node())) { + const ASTNode* ast_node = current_ast_node(); + if (ast_node->ParentIsA<DeducedTemplateSpecializationType>() || + IsDefaultTemplateTemplateArg(ast_node)) { current_ast_node()->set_in_forward_declare_context(false); ReportDeclUse(CurrentLoc(), template_name.getAsTemplateDecl()); } @@ -4140,7 +4184,6 @@ class IwyuAction : public ASTFrontendAction { #include "iwyu_driver.h" #include "clang/Frontend/FrontendAction.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/TargetSelect.h" using include_what_you_use::OptionsParser; @@ -4148,12 +4191,11 @@ using include_what_you_use::IwyuAction; using include_what_you_use::CreateCompilerInstance; int main(int argc, char **argv) { - // Must initialize X86 target to be able to parse Microsoft inline - // assembly. We do this unconditionally, because it allows an IWYU - // built for non-X86 targets to parse MS inline asm without choking. - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmParser(); + // X86 target is required to parse Microsoft inline assembly, so we hope it's + // part of all targets. Clang parser will complain otherwise. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); // The command line should look like // path/to/iwyu -Xiwyu --verbose=4 [-Xiwyu --other_iwyu_flag]... CLANG_FLAGS... foo.cc diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc index 9982145..81906aa 100644 --- a/iwyu_ast_util.cc +++ b/iwyu_ast_util.cc @@ -1095,11 +1095,14 @@ bool DeclsAreInSameClass(const Decl* decl1, const Decl* decl2) { return decl1->getDeclContext()->isRecord(); } -bool IsBuiltinFunction(const clang::NamedDecl* decl, - const std::string& symbol_name) { +bool IsBuiltinFunction(const clang::NamedDecl* decl) { if (const clang::IdentifierInfo* iden = decl->getIdentifier()) { - return iden->getBuiltinID() != 0 && - !clang::Builtin::Context::isBuiltinFunc(symbol_name.c_str()); + unsigned builtin_id = iden->getBuiltinID(); + if (builtin_id != 0) { + const clang::Builtin::Context& ctx = decl->getASTContext().BuiltinInfo; + return !ctx.isPredefinedLibFunction(builtin_id) && + !ctx.isHeaderDependentFunction(builtin_id); + } } return false; } diff --git a/iwyu_ast_util.h b/iwyu_ast_util.h index 18ddf2d..28668f7 100644 --- a/iwyu_ast_util.h +++ b/iwyu_ast_util.h @@ -652,8 +652,7 @@ const clang::NamedDecl* GetNonfriendClassRedecl(const clang::NamedDecl* decl); bool DeclsAreInSameClass(const clang::Decl* decl1, const clang::Decl* decl2); // Returns true if the given decl/name is a builtin function -bool IsBuiltinFunction(const clang::NamedDecl* decl, - const std::string& symbol_name); +bool IsBuiltinFunction(const clang::NamedDecl* decl); // --- Utilities for Type. diff --git a/iwyu_globals.cc b/iwyu_globals.cc index 36ac3ae..96b728c 100644 --- a/iwyu_globals.cc +++ b/iwyu_globals.cc @@ -91,6 +91,8 @@ static void PrintHelp(const char* extra_msg) { " the maximum line length can still be exceeded with long\n" " file names (default: 80).\n" " --no_comments: do not add 'why' comments.\n" + " --update_comments: always add 'why' comments, even if no\n" + " #include lines need to be added or removed.\n" " --no_fwd_decls: do not use forward declarations.\n" " --verbose=<level>: the higher the level, the more output.\n" " --quoted_includes_first: when sorting includes, place quoted\n" @@ -163,6 +165,7 @@ CommandlineFlags::CommandlineFlags() prefix_header_include_policy(CommandlineFlags::kAdd), pch_in_code(false), no_comments(false), + update_comments(false), no_fwd_decls(false), quoted_includes_first(false), cxx17ns(false) { @@ -182,6 +185,7 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) { {"pch_in_code", no_argument, nullptr, 'h'}, {"max_line_length", required_argument, nullptr, 'l'}, {"no_comments", no_argument, nullptr, 'o'}, + {"update_comments", no_argument, nullptr, 'u'}, {"no_fwd_decls", no_argument, nullptr, 'f'}, {"quoted_includes_first", no_argument, nullptr, 'q' }, {"cxx17ns", no_argument, nullptr, 'C'}, @@ -197,6 +201,7 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) { case 'm': mapping_files.push_back(optarg); break; case 'n': no_default_mappings = true; break; case 'o': no_comments = true; break; + case 'u': update_comments = true; break; case 'f': no_fwd_decls = true; break; case 'x': if (strcmp(optarg, "add") == 0) { diff --git a/iwyu_globals.h b/iwyu_globals.h index 242cdf6..eefb8ce 100644 --- a/iwyu_globals.h +++ b/iwyu_globals.h @@ -98,6 +98,7 @@ struct CommandlineFlags { PrefixHeaderIncludePolicy prefix_header_include_policy; bool pch_in_code; // Treat the first seen include as a PCH. No short option. bool no_comments; // Disable 'why' comments. No short option. + bool update_comments; // Force 'why' comments. No short option. bool no_fwd_decls; // Disable forward declarations. bool quoted_includes_first; // Place quoted includes first in sort order. bool cxx17ns; // -C: C++17 nested namespace syntax diff --git a/iwyu_include_picker.cc b/iwyu_include_picker.cc index f5d2dbc..26b55d8 100644 --- a/iwyu_include_picker.cc +++ b/iwyu_include_picker.cc @@ -16,6 +16,7 @@ // not hash_map: it's not as portable and needs hash<string>. #include <map> // for map, map<>::mapped_type, etc #include <memory> +#include <regex> #include <string> // for string, basic_string, etc #include <system_error> // for error_code #include <utility> // for pair, make_pair @@ -33,7 +34,6 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" #include "clang/Basic/FileManager.h" @@ -89,19 +89,33 @@ const IncludeMapEntry libc_symbol_map[] = { // an option for this type. That's the preferred #include all else // equal. The visibility on the symbol-name is ignored; by convention // we always set it to kPrivate. - { "blksize_t", kPrivate, "<sys/types.h>", kPublic }, - { "blkcnt_t", kPrivate, "<sys/stat.h>", kPublic }, + { "aiocb", kPrivate, "<aio.h>", kPublic }, { "blkcnt_t", kPrivate, "<sys/types.h>", kPublic }, + { "blkcnt_t", kPrivate, "<sys/stat.h>", kPublic }, + { "blksize_t", kPrivate, "<sys/types.h>", kPublic }, { "blksize_t", kPrivate, "<sys/stat.h>", kPublic }, + { "cc_t", kPrivate, "<termios.h>", kPublic }, { "clock_t", kPrivate, "<sys/types.h>", kPublic }, + { "clock_t", kPrivate, "<sys/time.h>", kPublic }, { "clock_t", kPrivate, "<time.h>", kPublic }, + { "clockid_t", kPrivate, "<sys/types.h>", kPublic }, + { "clockid_t", kPrivate, "<time.h>", kPublic }, { "daddr_t", kPrivate, "<sys/types.h>", kPublic }, { "daddr_t", kPrivate, "<rpc/types.h>", kPublic }, { "dev_t", kPrivate, "<sys/types.h>", kPublic }, { "dev_t", kPrivate, "<sys/stat.h>", kPublic }, + { "div_t", kPrivate, "<stdlib.h>", kPublic }, + { "double_t", kPrivate, "<math.h>", kPublic }, { "error_t", kPrivate, "<errno.h>", kPublic }, { "error_t", kPrivate, "<argp.h>", kPublic }, { "error_t", kPrivate, "<argz.h>", kPublic }, + { "fd_set", kPrivate, "<sys/select.h>", kPublic }, + { "fd_set", kPrivate, "<sys/time.h>", kPublic }, + { "fenv_t", kPrivate, "<fenv.h>", kPublic }, + { "fexcept_t", kPrivate, "<fenv.h>", kPublic }, + { "FILE", kPrivate, "<stdio.h>", kPublic }, + { "FILE", kPrivate, "<wchar.h>", kPublic }, + { "float_t", kPrivate, "<math.h>", kPublic }, { "fsblkcnt_t", kPrivate, "<sys/types.h>", kPublic }, { "fsblkcnt_t", kPrivate, "<sys/statvfs.h>", kPublic }, { "fsfilcnt_t", kPrivate, "<sys/types.h>", kPublic }, @@ -109,18 +123,21 @@ const IncludeMapEntry libc_symbol_map[] = { { "gid_t", kPrivate, "<sys/types.h>", kPublic }, { "gid_t", kPrivate, "<grp.h>", kPublic }, { "gid_t", kPrivate, "<pwd.h>", kPublic }, + { "gid_t", kPrivate, "<signal.h>", kPublic }, { "gid_t", kPrivate, "<stropts.h>", kPublic }, { "gid_t", kPrivate, "<sys/ipc.h>", kPublic }, { "gid_t", kPrivate, "<sys/stat.h>", kPublic }, { "gid_t", kPrivate, "<unistd.h>", kPublic }, { "id_t", kPrivate, "<sys/types.h>", kPublic }, { "id_t", kPrivate, "<sys/resource.h>", kPublic }, + { "imaxdiv_t", kPrivate, "<inttypes.h>", kPublic }, + { "intmax_t", kPrivate, "<stdint.h>", kPublic }, + { "uintmax_t", kPrivate, "<stdint.h>", kPublic }, { "ino64_t", kPrivate, "<sys/types.h>", kPublic }, { "ino64_t", kPrivate, "<dirent.h>", kPublic }, { "ino_t", kPrivate, "<sys/types.h>", kPublic }, { "ino_t", kPrivate, "<dirent.h>", kPublic }, { "ino_t", kPrivate, "<sys/stat.h>", kPublic }, - { "int8_t", kPrivate, "<sys/types.h>", kPublic }, { "int8_t", kPrivate, "<stdint.h>", kPublic }, { "int16_t", kPrivate, "<stdint.h>", kPublic }, { "int32_t", kPrivate, "<stdint.h>", kPublic }, @@ -131,71 +148,140 @@ const IncludeMapEntry libc_symbol_map[] = { { "uint64_t", kPrivate, "<stdint.h>", kPublic }, { "intptr_t", kPrivate, "<stdint.h>", kPublic }, { "uintptr_t", kPrivate, "<stdint.h>", kPublic }, - { "intptr_t", kPrivate, "<unistd.h>", kPublic }, { "key_t", kPrivate, "<sys/types.h>", kPublic }, { "key_t", kPrivate, "<sys/ipc.h>", kPublic }, + { "lconv", kPrivate, "<locale.h>", kPublic }, + { "ldiv_t", kPrivate, "<stdlib.h>", kPublic }, + { "lldiv_t", kPrivate, "<stdlib.h>", kPublic }, { "max_align_t", kPrivate, "<stddef.h>", kPublic }, { "mode_t", kPrivate, "<sys/types.h>", kPublic }, - { "mode_t", kPrivate, "<sys/stat.h>", kPublic }, + { "mode_t", kPrivate, "<fcntl.h>", kPublic }, + { "mode_t", kPrivate, "<ndbm.h>", kPublic }, + { "mode_t", kPrivate, "<spawn.h>", kPublic }, { "mode_t", kPrivate, "<sys/ipc.h>", kPublic }, { "mode_t", kPrivate, "<sys/mman.h>", kPublic }, + { "mode_t", kPrivate, "<sys/stat.h>", kPublic }, { "nlink_t", kPrivate, "<sys/types.h>", kPublic }, { "nlink_t", kPrivate, "<sys/stat.h>", kPublic }, { "off64_t", kPrivate, "<sys/types.h>", kPublic }, { "off64_t", kPrivate, "<unistd.h>", kPublic }, { "off_t", kPrivate, "<sys/types.h>", kPublic }, - { "off_t", kPrivate, "<unistd.h>", kPublic }, - { "off_t", kPrivate, "<sys/stat.h>", kPublic }, + { "off_t", kPrivate, "<aio.h>", kPublic }, + { "off_t", kPrivate, "<fcntl.h>", kPublic }, + { "off_t", kPrivate, "<stdio.h>", kPublic }, { "off_t", kPrivate, "<sys/mman.h>", kPublic }, + { "off_t", kPrivate, "<sys/stat.h>", kPublic }, + { "off_t", kPrivate, "<unistd.h>", kPublic }, { "pid_t", kPrivate, "<sys/types.h>", kPublic }, - { "pid_t", kPrivate, "<unistd.h>", kPublic }, + { "pid_t", kPrivate, "<fcntl.h>", kPublic }, + { "pid_t", kPrivate, "<sched.h>", kPublic }, { "pid_t", kPrivate, "<signal.h>", kPublic }, + { "pid_t", kPrivate, "<spawn.h>", kPublic }, { "pid_t", kPrivate, "<sys/msg.h>", kPublic }, + { "pid_t", kPrivate, "<sys/sem.h>", kPublic }, { "pid_t", kPrivate, "<sys/shm.h>", kPublic }, + { "pid_t", kPrivate, "<sys/wait.h>", kPublic }, { "pid_t", kPrivate, "<termios.h>", kPublic }, { "pid_t", kPrivate, "<time.h>", kPublic }, + { "pid_t", kPrivate, "<unistd.h>", kPublic }, { "pid_t", kPrivate, "<utmpx.h>", kPublic }, { "ptrdiff_t", kPrivate, "<stddef.h>", kPublic }, + { "regex_t", kPrivate, "<regex.h>", kPublic }, + { "regmatch_t", kPrivate, "<regex.h>", kPublic }, + { "regoff_t", kPrivate, "<regex.h>", kPublic }, + { "sigevent", kPrivate, "<signal.h>", kPublic }, + { "sigevent", kPrivate, "<aio.h>", kPublic }, + { "sigevent", kPrivate, "<mqueue.h>", kPublic }, + { "sigevent", kPrivate, "<time.h>", kPublic }, + { "siginfo_t", kPrivate, "<signal.h>", kPublic }, + { "siginfo_t", kPrivate, "<sys/wait.h>", kPublic }, { "sigset_t", kPrivate, "<signal.h>", kPublic }, - { "sigset_t", kPrivate, "<sys/epoll.h>", kPublic }, + { "sigset_t", kPrivate, "<spawn.h>", kPublic }, { "sigset_t", kPrivate, "<sys/select.h>", kPublic }, - { "socklen_t", kPrivate, "<bits/socket.h>", kPrivate }, - { "socklen_t", kPrivate, "<unistd.h>", kPublic }, - { "socklen_t", kPrivate, "<arpa/inet.h>", kPublic }, + { "sigval", kPrivate, "<signal.h>", kPublic }, + { "sockaddr", kPrivate, "<sys/socket.h>", kPublic }, + { "socklen_t", kPrivate, "<sys/socket.h>", kPublic }, + { "socklen_t", kPrivate, "<netdb.h>", kPublic }, { "ssize_t", kPrivate, "<sys/types.h>", kPublic }, - { "ssize_t", kPrivate, "<unistd.h>", kPublic }, + { "ssize_t", kPrivate, "<aio.h>", kPublic }, { "ssize_t", kPrivate, "<monetary.h>", kPublic }, + { "ssize_t", kPrivate, "<mqueue.h>", kPublic }, + { "ssize_t", kPrivate, "<stdio.h>", kPublic }, { "ssize_t", kPrivate, "<sys/msg.h>", kPublic }, + { "ssize_t", kPrivate, "<sys/socket.h>", kPublic }, + { "ssize_t", kPrivate, "<sys/uio.h>", kPublic }, + { "ssize_t", kPrivate, "<unistd.h>", kPublic }, + { "stat", kPrivate, "<sys/stat.h>", kPublic }, + { "stat", kPrivate, "<ftw.h>", kPublic }, { "suseconds_t", kPrivate, "<sys/types.h>", kPublic }, - { "suseconds_t", kPrivate, "<sys/time.h>", kPublic }, { "suseconds_t", kPrivate, "<sys/select.h>", kPublic }, - { "time_t", kPrivate, "<sys/types.h>", kPublic }, + { "suseconds_t", kPrivate, "<sys/time.h>", kPublic }, { "time_t", kPrivate, "<time.h>", kPublic }, + { "time_t", kPrivate, "<sched.h>", kPublic }, + { "time_t", kPrivate, "<sys/msg.h>", kPublic }, + { "time_t", kPrivate, "<sys/select.h>", kPublic }, + { "time_t", kPrivate, "<sys/sem.h>", kPublic }, + { "time_t", kPrivate, "<sys/shm.h>", kPublic }, + { "time_t", kPrivate, "<sys/stat.h>", kPublic }, + { "time_t", kPrivate, "<sys/time.h>", kPublic }, + { "time_t", kPrivate, "<sys/types.h>", kPublic }, + { "time_t", kPrivate, "<utime.h>", kPublic }, + { "timer_t", kPrivate, "<sys/types.h>", kPublic }, + { "timer_t", kPrivate, "<time.h>", kPublic }, { "timespec", kPrivate, "<time.h>", kPublic }, + { "timespec", kPrivate, "<aio.h>", kPublic }, + { "timespec", kPrivate, "<mqueue.h>", kPublic }, + { "timespec", kPrivate, "<sched.h>", kPublic }, + { "timespec", kPrivate, "<signal.h>", kPublic }, + { "timespec", kPrivate, "<sys/select.h>", kPublic }, + { "timespec", kPrivate, "<sys/stat.h>", kPublic }, { "timeval", kPrivate, "<sys/time.h>", kPublic }, + { "timeval", kPrivate, "<sys/resource.h>", kPublic }, + { "timeval", kPrivate, "<sys/select.h>", kPublic }, + { "timeval", kPrivate, "<utmpx.h>", kPublic }, { "u_char", kPrivate, "<sys/types.h>", kPublic }, { "u_char", kPrivate, "<rpc/types.h>", kPublic }, { "uid_t", kPrivate, "<sys/types.h>", kPublic }, - { "uid_t", kPrivate, "<unistd.h>", kPublic }, { "uid_t", kPrivate, "<pwd.h>", kPublic }, { "uid_t", kPrivate, "<signal.h>", kPublic }, { "uid_t", kPrivate, "<stropts.h>", kPublic }, { "uid_t", kPrivate, "<sys/ipc.h>", kPublic }, { "uid_t", kPrivate, "<sys/stat.h>", kPublic }, + { "uid_t", kPrivate, "<unistd.h>", kPublic }, { "useconds_t", kPrivate, "<sys/types.h>", kPublic }, { "useconds_t", kPrivate, "<unistd.h>", kPublic }, { "wchar_t", kPrivate, "<stddef.h>", kPublic }, { "wchar_t", kPrivate, "<stdlib.h>", kPublic }, - // glob.h seems to define size_t if necessary, but it should come from stddef. // It is unspecified if the cname headers provide ::size_t. // <locale.h> is the one header which defines NULL but not size_t. { "size_t", kPrivate, "<stddef.h>", kPublic }, // 'canonical' location for size_t + { "size_t", kPrivate, "<aio.h>", kPublic }, + { "size_t", kPrivate, "<glob.h>", kPublic }, + { "size_t", kPrivate, "<grp.h>", kPublic }, + { "size_t", kPrivate, "<iconv.h>", kPublic }, + { "size_t", kPrivate, "<monetary.h>", kPublic }, + { "size_t", kPrivate, "<mqueue.h>", kPublic }, + { "size_t", kPrivate, "<ndbm.h>", kPublic }, + { "size_t", kPrivate, "<pwd.h>", kPublic }, + { "size_t", kPrivate, "<regex.h>", kPublic }, + { "size_t", kPrivate, "<search.h>", kPublic }, + { "size_t", kPrivate, "<signal.h>", kPublic }, { "size_t", kPrivate, "<stdio.h>", kPublic }, { "size_t", kPrivate, "<stdlib.h>", kPublic }, { "size_t", kPrivate, "<string.h>", kPublic }, + { "size_t", kPrivate, "<strings.h>", kPublic }, + { "size_t", kPrivate, "<sys/mman.h>", kPublic }, + { "size_t", kPrivate, "<sys/msg.h>", kPublic }, + { "size_t", kPrivate, "<sys/sem.h>", kPublic }, + { "size_t", kPrivate, "<sys/shm.h>", kPublic }, + { "size_t", kPrivate, "<sys/socket.h>", kPublic }, + { "size_t", kPrivate, "<sys/types.h>", kPublic }, + { "size_t", kPrivate, "<sys/uio.h>", kPublic }, { "size_t", kPrivate, "<time.h>", kPublic }, { "size_t", kPrivate, "<uchar.h>", kPublic }, + { "size_t", kPrivate, "<unistd.h>", kPublic }, { "size_t", kPrivate, "<wchar.h>", kPublic }, + { "size_t", kPrivate, "<wordexp.h>", kPublic }, // Macros that can be defined in more than one file, don't have the // same __foo_defined guard that other types do, so the grep above // doesn't discover them. Until I figure out a better way, I just @@ -203,7 +289,13 @@ const IncludeMapEntry libc_symbol_map[] = { { "EOF", kPrivate, "<stdio.h>", kPublic }, { "EOF", kPrivate, "<libio.h>", kPublic }, { "FILE", kPrivate, "<stdio.h>", kPublic }, + { "MAP_STACK", kPrivate, "<sys/mman.h>", kPublic }, + { "MAP_STACK", kPrivate, "<linux/mman.h>", kPublic }, + { "SIGCHLD", kPrivate, "<signal.h>", kPublic }, + { "SIGCHLD", kPrivate, "<linux/signal.h>", kPublic }, { "va_list", kPrivate, "<stdarg.h>", kPublic }, + { "va_list", kPrivate, "<stdio.h>", kPublic }, + { "va_list", kPrivate, "<wchar.h>", kPublic }, // These are symbols that could be defined in either stdlib.h or // malloc.h, but we always want the stdlib location. { "malloc", kPrivate, "<stdlib.h>", kPublic }, @@ -262,8 +354,8 @@ const IncludeMapEntry libstdcpp_symbol_map[] = { { "std::size_t", kPrivate, "<cwchar>", kPublic }, }; -// Private -> public include mappings for GNU libc const IncludeMapEntry libc_include_map[] = { + // Private -> public include mappings for GNU libc // ( cd /usr/include && grep '^ *# *include' {sys/,net/,}* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | grep bits/ | sort ) // When I saw more than one mapping for these, I typically picked // what I thought was the "best" one. @@ -467,6 +559,8 @@ const IncludeMapEntry libc_include_map[] = { { "<linux/limits.h>", kPrivate, "<limits.h>", kPublic }, // PATH_MAX { "<linux/prctl.h>", kPrivate, "<sys/prctl.h>", kPublic }, { "<sys/ucontext.h>", kPrivate, "<ucontext.h>", kPublic }, + // Exports guaranteed by the C standard + { "<stdint.h>", kPublic, "<inttypes.h>", kPublic }, }; const IncludeMapEntry stdlib_c_include_map[] = { @@ -1315,16 +1409,17 @@ void IncludePicker::ExpandRegexes() { for (const string& regex_key : filepath_include_map_regex_keys) { const vector<MappedInclude>& map_to = filepath_include_map_[regex_key]; // Enclose the regex in ^(...)$ for full match. - llvm::Regex regex(std::string("^(" + regex_key.substr(1) + ")$")); - if (regex.match(hdr, nullptr) && !ContainsQuotedInclude(map_to, hdr)) { + std::regex regex(std::string("^(" + regex_key.substr(1) + ")$")); + if (std::regex_match(hdr, regex) && + !ContainsQuotedInclude(map_to, hdr)) { Extend(&filepath_include_map_[hdr], filepath_include_map_[regex_key]); MarkVisibility(&include_visibility_map_, hdr, include_visibility_map_[regex_key]); } } for (const string& regex_key : friend_to_headers_map_regex_keys) { - llvm::Regex regex(std::string("^(" + regex_key.substr(1) + ")$")); - if (regex.match(hdr, nullptr)) { + std::regex regex(std::string("^(" + regex_key.substr(1) + ")$")); + if (std::regex_match(hdr, regex)) { InsertAllInto(friend_to_headers_map_[regex_key], &friend_to_headers_map_[hdr]); } diff --git a/iwyu_output.cc b/iwyu_output.cc index e6bb851..d805242 100644 --- a/iwyu_output.cc +++ b/iwyu_output.cc @@ -1161,7 +1161,7 @@ void ProcessFullUse(OneUse* use, // We normally ignore uses for builtins, but when there is a mapping defined // for the symbol, we should respect that. So, we need to determine whether // the symbol has any mappings. - bool is_builtin_function = IsBuiltinFunction(use->decl(), use->symbol_name()); + bool is_builtin_function = IsBuiltinFunction(use->decl()); bool is_builtin_function_with_mappings = is_builtin_function && HasMapping(use->symbol_name()); @@ -1987,7 +1987,7 @@ size_t PrintableDiffs(const string& filename, break; } } - if (no_adds_or_deletes) { + if (no_adds_or_deletes && !GlobalFlags().update_comments) { output = "\n(" + filename + " has correct #includes/fwd-decls)\n"; return 0; } diff --git a/iwyu_port.h b/iwyu_port.h index d890575..e1fabb3 100644 --- a/iwyu_port.h +++ b/iwyu_port.h @@ -26,7 +26,7 @@ class FatalMessageEmitter { FatalMessageEmitter(const char* file, int line, const char* message) { stream() << file << ":" << line << ": Assertion failed: " << message; } - LLVM_ATTRIBUTE_NORETURN ~FatalMessageEmitter() { + [[noreturn]] ~FatalMessageEmitter() { stream() << "\n"; ::abort(); #ifdef LLVM_BUILTIN_UNREACHABLE diff --git a/iwyu_tool.py b/iwyu_tool.py index eaf0abc..45b2a4a 100755 --- a/iwyu_tool.py +++ b/iwyu_tool.py @@ -42,6 +42,7 @@ import subprocess CORRECT_RE = re.compile(r'^\((.*?) has correct #includes/fwd-decls\)$') SHOULD_ADD_RE = re.compile(r'^(.*?) should add these lines:$') +ADD_RE = re.compile('^(.*?) +// (.*)$') SHOULD_REMOVE_RE = re.compile(r'^(.*?) should remove these lines:$') FULL_LIST_RE = re.compile(r'The full include-list for (.*?):$') END_RE = re.compile(r'^---$') @@ -80,14 +81,17 @@ def clang_formatter(output): elif state[0] == GENERAL: formatted.append(line) elif state[0] == ADD: - formatted.append('%s:1:1: error: add the following line' % state[1]) - formatted.append(line) + match = ADD_RE.match(line) + if match: + formatted.append("%s:1:1: error: add '%s' (%s)" % + (state[1], match.group(1), match.group(2))) + else: + formatted.append("%s:1:1: error: add '%s'" % (state[1], line)) elif state[0] == REMOVE: match = LINES_RE.match(line) line_no = match.group(2) if match else '1' - formatted.append('%s:%s:1: error: remove the following line' % - (state[1], line_no)) - formatted.append(match.group(1)) + formatted.append("%s:%s:1: error: superfluous '%s'" % + (state[1], line_no, match.group(1))) return os.linesep.join(formatted) diff --git a/iwyu_version.h b/iwyu_version.h index 12a451f..7c3b41c 100644 --- a/iwyu_version.h +++ b/iwyu_version.h @@ -10,6 +10,6 @@ #ifndef INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_ #define INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_ -#define IWYU_VERSION_STRING "0.16" +#define IWYU_VERSION_STRING "0.17" #endif // INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_ diff --git a/tests/c/libbuiltins-direct.h b/tests/c/libbuiltins-direct.h new file mode 100644 index 0000000..eef6b58 --- /dev/null +++ b/tests/c/libbuiltins-direct.h @@ -0,0 +1,10 @@ +//===--- libbuiltins-direct.h - test input file for iwyu ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <math.h> diff --git a/tests/c/libbuiltins.c b/tests/c/libbuiltins.c new file mode 100644 index 0000000..4ba3033 --- /dev/null +++ b/tests/c/libbuiltins.c @@ -0,0 +1,34 @@ +//===--- libbuiltins.c - test input file for iwyu -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Library builtins are, like normal builtins, compiled down to an intrinsic, +// but a header still needs to be included for the program to be valid. The math +// library (pow, round, etc) is a typical example. + +// IWYU_ARGS: -I . + +#include "tests/c/libbuiltins-direct.h" + +float kapow(float x) { + // IWYU: pow is...*math.h + return pow(x, 2.0F); +} + +/**** IWYU_SUMMARY + +tests/c/libbuiltins.c should add these lines: +#include <math.h> + +tests/c/libbuiltins.c should remove these lines: +- #include "tests/c/libbuiltins-direct.h" // lines XX-XX + +The full include-list for tests/c/libbuiltins.c: +#include <math.h> // for pow + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/badinc.cc b/tests/cxx/badinc.cc index e58a98f..3c3c3aa 100644 --- a/tests/cxx/badinc.cc +++ b/tests/cxx/badinc.cc @@ -1094,8 +1094,10 @@ int main() { // IWYU: I1_PtrDereferenceClass needs a declaration I1_PtrDereferenceClass* local_i1_ptrdereference_class = 0; int x; - // IWYU: va_list is...*<stdarg.h> - va_list vl; // in gcc, va_list is an internal type, so this tests <built-in> + // va_list is normally in <stdarg.h>, but we already have <stdio.h> + // available, so mappings will source it from there. + // IWYU: va_list is...*<stdio.h> + va_list vl; D1_I1_Typedef d1_i1_typedef; // IWYU: i1_int is...*badinc-i1.h int vararray[i1_int]; @@ -1859,7 +1861,6 @@ int main() { tests/cxx/badinc.cc should add these lines: #include <ctype.h> -#include <stdarg.h> #include <stddef.h> #include <list> #include "tests/cxx/badinc-i1.h" @@ -1889,7 +1890,6 @@ The full include-list for tests/cxx/badinc.cc: #include "tests/cxx/badinc-inl.h" #include <ctype.h> // for isascii #include <setjmp.h> -#include <stdarg.h> // for va_list #include <stddef.h> // for offsetof #include <algorithm> // for find #include <fstream> // for fstream diff --git a/tests/cxx/ctad-d1.h b/tests/cxx/ctad-d1.h new file mode 100644 index 0000000..c492fde --- /dev/null +++ b/tests/cxx/ctad-d1.h @@ -0,0 +1,10 @@ +//===--- ctad-d1.h - test input file for iwyu -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "tests/cxx/ctad-i1.h" diff --git a/tests/cxx/ctad-i1.h b/tests/cxx/ctad-i1.h new file mode 100644 index 0000000..defd3f0 --- /dev/null +++ b/tests/cxx/ctad-i1.h @@ -0,0 +1,20 @@ +//===--- ctad-i1.h - test input file for iwyu -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +template <class Func> +struct Deduced { + Deduced(Func&& deferred) : deferred(deferred) { + } + + ~Deduced() { + deferred(); + } + + Func deferred; +}; diff --git a/tests/cxx/ctad.cc b/tests/cxx/ctad.cc new file mode 100644 index 0000000..792343b --- /dev/null +++ b/tests/cxx/ctad.cc @@ -0,0 +1,33 @@ +//===--- ctad.cc - test input file for iwyu -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// IWYU_ARGS: -I . -std=c++17 + +// Test that C++17 CTAD (Class Template Argument Deduction) is recognized as +// pointing back to a template, even if it's not explicitly specialized. + +#include "tests/cxx/ctad-d1.h" + +void f() { + // IWYU: Deduced is...*ctad-i1.h + Deduced d([] {}); +} + +/**** IWYU_SUMMARY + +tests/cxx/ctad.cc should add these lines: +#include "tests/cxx/ctad-i1.h" + +tests/cxx/ctad.cc should remove these lines: +- #include "tests/cxx/ctad-d1.h" // lines XX-XX + +The full include-list for tests/cxx/ctad.cc: +#include "tests/cxx/ctad-i1.h" // for Deduced + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/iwyu_stricter_than_cpp-type_alias.h b/tests/cxx/iwyu_stricter_than_cpp-type_alias.h new file mode 100644 index 0000000..3256f55 --- /dev/null +++ b/tests/cxx/iwyu_stricter_than_cpp-type_alias.h @@ -0,0 +1,76 @@ +//===--- iwyu_stricter_than_cpp-type_alias.h - test input file for iwyu ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// The two rules the author has to follow to disable iwyu's +// stricter-than-C++ rule and force it to fall back on the c++ +// requirement (forward-declare ok): +// (1) forward-declare the relevant type +// (2) do not directly #include the definition of the relevant type. + +#include "tests/cxx/iwyu_stricter_than_cpp-d1.h" + +// --- Type aliases. + +// Requires the full type because it does not obey rule (1) +// IWYU: IndirectStruct1 is...*iwyu_stricter_than_cpp-i1.h +using DoesNotForwardDeclareAl = IndirectStruct1; + +// This also does not obey rule (1): it's -d1 that does the fwd-declaring. +// IWYU: IndirectStructForwardDeclaredInD1 is...*iwyu_stricter_than_cpp-i1.h +using DoesNotForwardDeclareProperlyAl = IndirectStructForwardDeclaredInD1; + +// Requires the full type because it does not obey rule (2) +struct DirectStruct1; +using IncludesAl = DirectStruct1; + +// Requires the full type because it does not obey rules (1) *or* (2) +using DoesNotForwardDeclareAndIncludesAl = DirectStruct2; + +// Does not require full type because it obeys all the rules. +struct IndirectStruct2; +using DoesEverythingRightAl = IndirectStruct2; + +// --- Now do it all again, with templates! + +// IWYU: TplIndirectStruct1 is...*iwyu_stricter_than_cpp-i1.h +using TplDoesNotForwardDeclareAl = TplIndirectStruct1<int>; + +using TplDoesNotForwardDeclareProperlyAl +// IWYU: TplIndirectStructForwardDeclaredInD1 is...*iwyu_stricter_than_cpp-i1.h + = TplIndirectStructForwardDeclaredInD1<int>; + +template <typename T> struct TplDirectStruct1; +using TplIncludesAl = TplDirectStruct1<int>; + +using TplDoesNotForwardDeclareAndIncludesAl = TplDirectStruct2<int>; + +template <typename T> struct TplIndirectStruct2; +using TplDoesEverythingRightAl = TplIndirectStruct2<int>; + +// Another way to forward-declare a class template. +template <> struct TplIndirectStruct2<float>; +using TplDoesEverythingRightAgainAl = TplIndirectStruct2<float>; + + +/**** IWYU_SUMMARY + +tests/cxx/iwyu_stricter_than_cpp-type_alias.h should add these lines: +#include "tests/cxx/iwyu_stricter_than_cpp-i1.h" + +tests/cxx/iwyu_stricter_than_cpp-type_alias.h should remove these lines: +- struct DirectStruct1; // lines XX-XX +- template <typename T> struct TplDirectStruct1; // lines XX-XX + +The full include-list for tests/cxx/iwyu_stricter_than_cpp-type_alias.h: +#include "tests/cxx/iwyu_stricter_than_cpp-d1.h" // for DirectStruct1, DirectStruct2, TplDirectStruct1, TplDirectStruct2 +#include "tests/cxx/iwyu_stricter_than_cpp-i1.h" // for IndirectStruct1, IndirectStructForwardDeclaredInD1, TplIndirectStruct1, TplIndirectStructForwardDeclaredInD1 +struct IndirectStruct2; // lines XX-XX +template <typename T> struct TplIndirectStruct2; // lines XX-XX + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/iwyu_stricter_than_cpp.cc b/tests/cxx/iwyu_stricter_than_cpp.cc index d6f70d8..2bfa1c1 100644 --- a/tests/cxx/iwyu_stricter_than_cpp.cc +++ b/tests/cxx/iwyu_stricter_than_cpp.cc @@ -10,6 +10,7 @@ // IWYU_ARGS: -Xiwyu --check_also="tests/cxx/*-autocast.h" \ // -Xiwyu --check_also="tests/cxx/*-fnreturn.h" \ // -Xiwyu --check_also="tests/cxx/*-typedefs.h" \ +// -Xiwyu --check_also="tests/cxx/*-type_alias.h" \ // -Xiwyu --check_also="tests/cxx/*-d2.h" \ // -I . @@ -36,6 +37,7 @@ // when these two conditions are met, and not otherwise. #include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h" +#include "tests/cxx/iwyu_stricter_than_cpp-type_alias.h" #include "tests/cxx/iwyu_stricter_than_cpp-autocast.h" #include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h" // We include this so the second declaration of TwiceDeclaredFunction @@ -81,6 +83,39 @@ void TestTypedefs() { // all) of the template args as well. } +using DoubleTypedefAl = DoesEverythingRightAl; + +void TestTypeAliases() { + DoesNotForwardDeclareAl dnfd(1); + DoesNotForwardDeclareProperlyAl dnfdp(2); + IncludesAl i(3); + DoesNotForwardDeclareAndIncludesAl dnfdai(4); + // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h + DoesEverythingRightAl dor(5); + // Because DoubleTypedefAl resolves to DoesEverythingRightAl, we need the + // same things DoesEverythingRightAl does. + // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h + DoubleTypedefAl dt(6); + + // ...and with templates. + TplDoesNotForwardDeclareAl tdnfd(7); + TplDoesNotForwardDeclareProperlyAl tdnfdp(8); + TplIncludesAl ti(9); + TplDoesNotForwardDeclareAndIncludesAl tdnfdai(10); + // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h + TplDoesEverythingRightAl tdor(11); + // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h + TplDoesEverythingRightAgainAl tdora(12); + + // But if we're in a forward-declare context, we don't require the + // underlying type! + DoesEverythingRightAl* dor_ptr = 0; + TplDoesEverythingRightAgainAl* tdora_ptr = 0; + // ...at least until we dereference the pointer + // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h + (void) dor_ptr->a; +} + void TestAutocast() { // We need full type of is2 because the declarer of Fn didn't // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h @@ -159,6 +194,7 @@ The full include-list for tests/cxx/iwyu_stricter_than_cpp.cc: #include "tests/cxx/iwyu_stricter_than_cpp-autocast.h" // for Fn, TplFn #include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h" // for DoesEverythingRightFn, DoesNotForwardDeclareAndIncludesFn, DoesNotForwardDeclareFn, DoesNotForwardDeclareProperlyFn, IncludesFn, TplDoesEverythingRightAgainFn, TplDoesEverythingRightFn, TplDoesNotForwardDeclareAndIncludesFn, TplDoesNotForwardDeclareFn, TplDoesNotForwardDeclareProperlyFn, TplIncludesFn #include "tests/cxx/iwyu_stricter_than_cpp-i2.h" // for IndirectStruct2, TplIndirectStruct2 +#include "tests/cxx/iwyu_stricter_than_cpp-type_alias.h" // for DoesEverythingRightAl, DoesNotForwardDeclareAl, DoesNotForwardDeclareAndIncludesAl, DoesNotForwardDeclareProperlyAl, IncludesAl, TplDoesEverythingRightAgainAl, TplDoesEverythingRightAl, TplDoesNotForwardDeclareAl, TplDoesNotForwardDeclareAndIncludesAl, TplDoesNotForwardDeclareProperlyAl, TplIncludesAl #include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h" // for DoesEverythingRight, DoesNotForwardDeclare, DoesNotForwardDeclareAndIncludes, DoesNotForwardDeclareProperly, Includes, TplDoesEverythingRight, TplDoesEverythingRightAgain, TplDoesNotForwardDeclare, TplDoesNotForwardDeclareAndIncludes, TplDoesNotForwardDeclareProperly, TplIncludes struct DirectStruct1; struct DirectStruct2; diff --git a/tests/cxx/libbuiltins-direct.h b/tests/cxx/libbuiltins-direct.h new file mode 100644 index 0000000..47afdf6 --- /dev/null +++ b/tests/cxx/libbuiltins-direct.h @@ -0,0 +1,10 @@ +//===--- libbuiltins-direct.h - test input file for iwyu ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cmath> diff --git a/tests/cxx/libbuiltins.cc b/tests/cxx/libbuiltins.cc new file mode 100644 index 0000000..d2cdd3e --- /dev/null +++ b/tests/cxx/libbuiltins.cc @@ -0,0 +1,34 @@ +//===--- libbuiltins.cc - test input file for iwyu ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Library builtins are, like normal builtins, compiled down to an intrinsic, +// but a header still needs to be included for the program to be valid. The math +// library (std::pow, std::round, etc) is a typical example. + +// IWYU_ARGS: -I . + +#include "tests/cxx/libbuiltins-direct.h" + +float kapow(float x) { + // IWYU: std::pow is...*cmath + return std::pow(x, 2.0F); +} + +/**** IWYU_SUMMARY + +tests/cxx/libbuiltins.cc should add these lines: +#include <cmath> + +tests/cxx/libbuiltins.cc should remove these lines: +- #include "tests/cxx/libbuiltins-direct.h" // lines XX-XX + +The full include-list for tests/cxx/libbuiltins.cc: +#include <cmath> // for pow + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/macro_location_tpl-d1.h b/tests/cxx/macro_location_tpl-d1.h new file mode 100644 index 0000000..cf7712f --- /dev/null +++ b/tests/cxx/macro_location_tpl-d1.h @@ -0,0 +1,10 @@ +//===--- macro_location_tpl-d1.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "tests/cxx/macro_location_tpl-i1.h" diff --git a/tests/cxx/macro_location_tpl-d2.h b/tests/cxx/macro_location_tpl-d2.h new file mode 100644 index 0000000..33da0bb --- /dev/null +++ b/tests/cxx/macro_location_tpl-d2.h @@ -0,0 +1,33 @@ +//===--- macro_location_tpl-d2.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Declare a couple of function templates whose specializations are used in a +// macro, to check that author intent hints attribute uses to the right place. +template <typename> +void expansion_template() = delete; +template <> +void expansion_template<int>(); + +template <typename> +void spelling_template() = delete; +template <> +void spelling_template<int>(); + +// As above, but for class templates. +template <typename> +struct ExpansionTemplate { + void method() { + } +}; + +template <typename> +struct SpellingTemplate { + void method() { + } +}; diff --git a/tests/cxx/macro_location_tpl-i1.h b/tests/cxx/macro_location_tpl-i1.h new file mode 100644 index 0000000..460e2a5 --- /dev/null +++ b/tests/cxx/macro_location_tpl-i1.h @@ -0,0 +1,30 @@ +//===--- macro_location_tpl-i1.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Forward-declare the primary templates as a signal that specialization uses +// belong in the expansion location. +template <typename> +void expansion_template(); + +template <typename> +class ExpansionTemplate; + +// expansion_template should be attributed to expansion loc. +#define FUNC_TEMPLATE_SPEC_EXPANSION expansion_template<int>() + +// spelling_template should be attributed to this file, because there's no +// forward-declare hint. +#define FUNC_TEMPLATE_SPEC_SPELLING spelling_template<int>(); + +// ExpansionTemplate should be attributed to expansion loc. +#define CLASS_TEMPLATE_SPEC_EXPANSION ExpansionTemplate<int>().method(); + +// SpellingTemplate should be attributed to this file, because there's no +// forward-declare hint. +#define CLASS_TEMPLATE_SPEC_SPELLING SpellingTemplate<int>().method(); diff --git a/tests/cxx/macro_location_tpl.cc b/tests/cxx/macro_location_tpl.cc new file mode 100644 index 0000000..01a0a00 --- /dev/null +++ b/tests/cxx/macro_location_tpl.cc @@ -0,0 +1,46 @@ +//===--- macro_location_tpl.cc - test input file for iwyu -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Expands on macro_location test case to also cover template scenarios. Macro +// uses are attributed to spelling location, but forward-declarations of primary +// templates also work as author intent hints for template specializations used +// inside the macro. + +// IWYU_ARGS: -I . + +#include "tests/cxx/macro_location_tpl-d2.h" +#include "tests/cxx/macro_location_tpl-d1.h" + +void use_macro_with_template_spec() { + // IWYU: FUNC_TEMPLATE_SPEC_EXPANSION is defined...*macro_location_tpl-i1.h + FUNC_TEMPLATE_SPEC_EXPANSION; + + // IWYU: FUNC_TEMPLATE_SPEC_SPELLING is defined...*macro_location_tpl-i1.h + FUNC_TEMPLATE_SPEC_SPELLING; + + // IWYU: CLASS_TEMPLATE_SPEC_EXPANSION is defined...*macro_location_tpl-i1.h + CLASS_TEMPLATE_SPEC_EXPANSION; + + // IWYU: CLASS_TEMPLATE_SPEC_SPELLING is defined...*macro_location_tpl-i1.h + CLASS_TEMPLATE_SPEC_SPELLING; +} + +/**** IWYU_SUMMARY + +tests/cxx/macro_location_tpl.cc should add these lines: +#include "tests/cxx/macro_location_tpl-i1.h" + +tests/cxx/macro_location_tpl.cc should remove these lines: +- #include "tests/cxx/macro_location_tpl-d1.h" // lines XX-XX + +The full include-list for tests/cxx/macro_location_tpl.cc: +#include "tests/cxx/macro_location_tpl-d2.h" // for ExpansionTemplate, expansion_template +#include "tests/cxx/macro_location_tpl-i1.h" // for CLASS_TEMPLATE_SPEC_EXPANSION, CLASS_TEMPLATE_SPEC_SPELLING, FUNC_TEMPLATE_SPEC_EXPANSION, FUNC_TEMPLATE_SPEC_SPELLING + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/no_forced_alias_callability-d1.h b/tests/cxx/no_forced_alias_callability-d1.h new file mode 100644 index 0000000..895a73f --- /dev/null +++ b/tests/cxx/no_forced_alias_callability-d1.h @@ -0,0 +1,14 @@ +//===--- no_forced_alias_callability-d1.h - test input file for iwyu ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +struct ReturnType; + +struct Aliased { + ReturnType doSomething(); +}; diff --git a/tests/cxx/no_forced_alias_callability-d2.h b/tests/cxx/no_forced_alias_callability-d2.h new file mode 100644 index 0000000..7be9a1b --- /dev/null +++ b/tests/cxx/no_forced_alias_callability-d2.h @@ -0,0 +1,18 @@ +//===--- no_forced_alias_callability-d2.h - test input file for iwyu ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +struct Aliased; + +typedef Aliased Alias; + +/**** IWYU_SUMMARY + +(tests/cxx/no_forced_alias_callability-d2.h has correct #includes/fwd-decls) + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/no_forced_alias_callability.cc b/tests/cxx/no_forced_alias_callability.cc new file mode 100644 index 0000000..6d4ce0a --- /dev/null +++ b/tests/cxx/no_forced_alias_callability.cc @@ -0,0 +1,29 @@ +//===--- no_forced_alias_callability.cc - test input file for iwyu --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// IWYU_ARGS: -Xiwyu --check_also="tests/cxx/no_forced_alias_callability-d2.h" \ +// -I . + +// Tests that IWYU doesn't require inclusion of an aliased class header +// (...-d1.h) into a header with the alias to provide callability of methods +// of the aliased class if the aliased class is explicitly made forward declared +// in accordance with the IWYU policy + +#include "tests/cxx/no_forced_alias_callability-d1.h" +#include "tests/cxx/no_forced_alias_callability-d2.h" + +int main() { + Alias a; +} + +/**** IWYU_SUMMARY + +(tests/cxx/no_forced_alias_callability.cc has correct #includes/fwd-decls) + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/scope_crash.cc b/tests/cxx/scope_crash.cc new file mode 100644 index 0000000..1659e08 --- /dev/null +++ b/tests/cxx/scope_crash.cc @@ -0,0 +1,45 @@ +//===--- scope_crash.cc - test input file for iwyu ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This is a weak testcase, but it's the smallest example we've found to +// reproduce an IWYU crash where Sema::TUScope was unexpectedly null. +// +// For some reason libstdc++9's std::map with a value with explicit default +// constructor triggers some path in Sema's constructor lookup that needs a +// non-null TUScope. +// +// Clang or libstdc++ might change so that this can no longer trigger the +// original bug, or so that the bug manifests some other way. But testers can't +// be choosers. + +#include <string> +#include <map> + +struct A {}; + +bool operator<(const A& lhs, const A& rhs) { + return false; +} + +struct B { + // Used to crash with libstdc++ 9, worked without 'explicit' + explicit B() = default; + std::string data; +}; + +void foo(const A& a) { + std::map<A, B> m; + m.erase(a); +} + +/**** IWYU_SUMMARY + +(tests/cxx/scope_crash.cc has correct #includes/fwd-decls) + +***** IWYU_SUMMARY */ diff --git a/tests/cxx/update_comments.cc b/tests/cxx/update_comments.cc new file mode 100644 index 0000000..bf0eccb --- /dev/null +++ b/tests/cxx/update_comments.cc @@ -0,0 +1,28 @@ +//===--- update_comments.cc - test input file for iwyu --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// IWYU_ARGS: -Xiwyu --update_comments -I . + +// Test that passing the --update_comments switch to IWYU makes it always print +// the full include-list, with up to date "// for XYZ" comments. + +#include "tests/cxx/indirect.h" // for SomethingElse + +IndirectClass indirect; + +/**** IWYU_SUMMARY + +tests/cxx/update_comments.cc should add these lines: + +tests/cxx/update_comments.cc should remove these lines: + +The full include-list for tests/cxx/update_comments.cc: +#include "tests/cxx/indirect.h" // for IndirectClass + +***** IWYU_SUMMARY */ |