1# Copyright 2011 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# This file is meant to be included into an target to create a unittest that 6# invokes a set of no-compile tests. A no-compile test is a test that asserts 7# a particular construct will not compile. 8# 9# Usage: 10# 11# 1. Create a GN target: 12# 13# import("//build/nocompile.gni") 14# 15# nocompile_source_set("base_nocompile_tests") { 16# sources = [ 17# "functional/one_not_equal_two_nocompile.nc", 18# ] 19# deps = [ 20# ":base" 21# ] 22# } 23# 24# Note that by convention, nocompile tests use the `.nc` extension rather 25# than the standard `.cc` extension: this is because the expectation lines 26# often exceed 80 characters, which would make clang-format unhappy. 27# 28# 2. Add a dep from a related test binary to the nocompile source set: 29# 30# test("base_unittests") { 31# ... 32# deps += [ ":base_nocompile_tests" ] 33# } 34# 35# 3. Populate the .nc file with test cases. Expected compile failures should be 36# annotated with a comment of the form: 37# 38# // expected-error {{<expected error string here>}} 39# 40# For example: 41# 42# void OneDoesNotEqualTwo() { 43# static_assert(1 == 2); // expected-error {{static assertion failed due to requirement '1 == 2'}} 44# } 45# 46# The verification logic is built as part of clang; full documentation is at 47# https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html. 48# 49# Also see: 50# http://dev.chromium.org/developers/testing/no-compile-tests 51# 52import("//build/config/clang/clang.gni") 53if (is_win) { 54 import("//build/toolchain/win/win_toolchain_data.gni") 55} 56 57declare_args() { 58 enable_nocompile_tests = is_clang && !is_nacl 59} 60 61if (enable_nocompile_tests) { 62 template("nocompile_source_set") { 63 action_foreach(target_name) { 64 testonly = true 65 66 script = "//tools/nocompile/wrapper.py" 67 sources = invoker.sources 68 if (defined(invoker.deps)) { 69 deps = invoker.deps 70 } 71 72 # An action is not a compiler, so configs is empty until it is explicitly 73 # set. 74 configs = default_compiler_configs 75 if (defined(invoker.configs)) { 76 configs += invoker.configs 77 } 78 79 # Disable the checks that the Chrome style plugin normally enforces to 80 # reduce the amount of boilerplate needed in nocompile tests. 81 configs -= [ "//build/config/clang:find_bad_constructs" ] 82 83 if (is_win) { 84 result_path = 85 "$target_out_dir/$target_name/{{source_name_part}}_placeholder.obj" 86 } else { 87 result_path = 88 "$target_out_dir/$target_name/{{source_name_part}}_placeholder.o" 89 } 90 rebased_obj_path = rebase_path(result_path, root_build_dir) 91 92 depfile = "${result_path}.d" 93 rebased_depfile_path = rebase_path(depfile, root_build_dir) 94 outputs = [ result_path ] 95 96 if (is_win) { 97 if (host_os == "win") { 98 cxx = "clang-cl.exe" 99 } else { 100 cxx = "clang-cl" 101 } 102 } else { 103 cxx = "clang++" 104 } 105 106 args = [] 107 108 if (is_win) { 109 # ninja normally parses /showIncludes output, but the depsformat 110 # variable can only be set in compiler tools, not for custom actions. 111 # Unfortunately, this means the clang wrapper needs to generate the 112 # depfile itself. 113 args += [ "--generate-depfile" ] 114 } 115 116 args += [ 117 rebase_path("$clang_base_path/bin/$cxx", root_build_dir), 118 "{{source}}", 119 rebased_obj_path, 120 rebased_depfile_path, 121 "--", 122 "{{cflags}}", 123 "{{cflags_cc}}", 124 "{{defines}}", 125 "{{include_dirs}}", 126 127 # No need to generate an object file for nocompile tests. 128 "-Xclang", 129 "-fsyntax-only", 130 131 # Enable clang's VerifyDiagnosticConsumer: 132 # https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html 133 "-Xclang", 134 "-verify", 135 136 # But don't require expected-note comments since that is not the 137 # primary point of the nocompile tests. 138 "-Xclang", 139 "-verify-ignore-unexpected=note", 140 141 # Disable the error limit so that nocompile tests do not need to be 142 # arbitrarily split up when they hit the default error limit. 143 "-ferror-limit=0", 144 145 # So funny characters don't show up in error messages. 146 "-fno-color-diagnostics", 147 148 # Always treat warnings as errors. 149 "-Werror", 150 ] 151 152 if (!is_win) { 153 args += [ 154 # On non-Windows platforms, clang can generate the depfile. 155 "-MMD", 156 "-MF", 157 rebased_depfile_path, 158 "-MT", 159 rebased_obj_path, 160 161 # Non-Windows clang uses file extensions to determine how to treat 162 # various inputs, so explicitly tell it to treat all inputs (even 163 # those with weird extensions like .nc) as C++ source files. 164 "-x", 165 "c++", 166 ] 167 } else { 168 # For some reason, the Windows includes are not part of the default 169 # compiler configs. Set it explicitly here, since things like libc++ 170 # depend on the VC runtime. 171 if (target_cpu == "x86") { 172 win_toolchain_data = win_toolchain_data_x86 173 } else if (target_cpu == "x64") { 174 win_toolchain_data = win_toolchain_data_x64 175 } else if (target_cpu == "arm64") { 176 win_toolchain_data = win_toolchain_data_arm64 177 } else { 178 error("Unsupported target_cpu, add it to win_toolchain_data.gni") 179 } 180 args += win_toolchain_data.include_flags_imsvc_list 181 args += [ "/showIncludes:user" ] 182 } 183 184 # Note: for all platforms, the depfile only lists user includes, and not 185 # system includes. If system includes change, the compiler flags are 186 # expected to artificially change in some way to invalidate and force the 187 # nocompile tests to run again. 188 } 189 } 190} 191