blob: 242e9104fc10ab17468e208bea0e72a6eb606018 [file] [log] [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/doxygen/classclang_1_1VerifyDiagnosticConsumer.html.
#
# 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.
}
}
}