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