mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 21:01:21 +01:00
Delay finishing the C++ translation unit until we reach the real EOF. (#6489)
Instead of parsing a complete C++ translation unit and then interacting with the translation unit further after the fact, delay finishing the translation unit until we finish the Carbon check phase. This fixes some issues where we would produce duplicated or incorrect diagnostics at the end of the C++ translation unit, particularly for unused declarations. Now we're in control of how we parse the translation unit, also disable parsing of C++20 modules if the syntax appears within `import Cpp inline` code. Keep the same clang parser alive throughout check, and use it instead of building a new one when parsing macros. This resolves issues where the translation unit scope was destroyed too early, resulting in unqualified lookup within macros being unable to find global scope entities. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
77caf3b9d8
commit
a8eca2ece6
+3
-44
@@ -613,32 +613,13 @@ constexpr auto operator""_kb(unsigned long long k) -> unsigned long long {
|
||||
}
|
||||
#define M_1KB 1_kb
|
||||
|
||||
// --- fail_todo_import_user_defined_literal.carbon
|
||||
// --- import_user_defined_literal.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_todo_import_user_defined_literal.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
|
||||
// CHECK:STDERR: ./user_defined_literal.h:4:16: error: no matching literal operator for call to 'operator""_kb' with argument of type 'unsigned long long' or 'const char *', and no matching literal operator template [CppInteropParseError]
|
||||
// CHECK:STDERR: 4 | #define M_1KB 1_kb
|
||||
// CHECK:STDERR: | ^
|
||||
import Cpp library "user_defined_literal.h";
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_todo_import_user_defined_literal.carbon:[[@LINE+15]]:2: note: in `Cpp` name lookup for `M_1KB` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.M_1KB;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_import_user_defined_literal.carbon:[[@LINE+11]]:2: error: failed to parse macro Cpp.M_1KB to a valid constant expression [InCppMacroEvaluation]
|
||||
// CHECK:STDERR: Cpp.M_1KB;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_user_defined_literal.carbon:[[@LINE+8]]:2: note: in `Cpp` name lookup for `M_1KB` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.M_1KB;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_import_user_defined_literal.carbon:[[@LINE+4]]:2: error: member name `M_1KB` not found in `Cpp` [MemberNameNotFoundInInstScope]
|
||||
// CHECK:STDERR: Cpp.M_1KB;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.M_1KB;
|
||||
}
|
||||
|
||||
@@ -657,27 +638,16 @@ fn F() {
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_todo_enums_no_scope.carbon
|
||||
// --- enums_no_scope.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp inline '''
|
||||
enum A { a = 1, b = 2 };
|
||||
// CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE+7]]:24: error: use of undeclared identifier 'a'; did you mean '::a'? [CppInteropParseError]
|
||||
// CHECK:STDERR: 13 | #define M_A_NO_SCOPE a
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: | ::a
|
||||
// CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE-5]]:12: note: '::a' declared here [CppInteropParseNote]
|
||||
// CHECK:STDERR: 5 | enum A { a = 1, b = 2 };
|
||||
// CHECK:STDERR: | ^
|
||||
#define M_A_NO_SCOPE a
|
||||
''';
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `M_A_NO_SCOPE` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.M_A_NO_SCOPE;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.M_A_NO_SCOPE;
|
||||
}
|
||||
|
||||
@@ -696,27 +666,16 @@ fn F() {
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_import_constexpr_no_scope.carbon
|
||||
// --- import_constexpr_no_scope.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp inline '''
|
||||
constexpr int a = 1;
|
||||
// CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE+7]]:33: error: use of undeclared identifier 'a'; did you mean '::a'? [CppInteropParseError]
|
||||
// CHECK:STDERR: 13 | #define M_CONSTEXPR_NO_SCOPE a
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: | ::a
|
||||
// CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE-5]]:18: note: '::a' declared here [CppInteropParseNote]
|
||||
// CHECK:STDERR: 5 | constexpr int a = 1;
|
||||
// CHECK:STDERR: | ^
|
||||
#define M_CONSTEXPR_NO_SCOPE a
|
||||
''';
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE+4]]:16: note: in `Cpp` name lookup for `M_CONSTEXPR_NO_SCOPE` [InCppNameLookup]
|
||||
// CHECK:STDERR: let a: i32 = Cpp.M_CONSTEXPR_NO_SCOPE;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let a: i32 = Cpp.M_CONSTEXPR_NO_SCOPE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
|
||||
// EXTRA-ARGS: --clang-arg=--std=c++20
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/modules.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/modules.carbon
|
||||
|
||||
// --- fail_export_module_in_inline_cpp.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: This diagnostic isn't very good.
|
||||
import Cpp inline '''
|
||||
// CHECK:STDERR: fail_export_module_in_inline_cpp.carbon:[[@LINE+7]]:8: error: module declaration must occur at the start of the translation unit [CppInteropParseError]
|
||||
// CHECK:STDERR: 13 | export module Foo;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: <carbon Cpp imports>:1:1: note: add 'module;' to the start of the file to introduce a global module fragment [CppInteropParseNote]
|
||||
// CHECK:STDERR: 1 | # 6 "fail_export_module_in_inline_cpp.carbon"
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
export module Foo;
|
||||
''';
|
||||
|
||||
// --- fail_module_in_inline_cpp.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: This diagnostic isn't very good.
|
||||
import Cpp inline '''
|
||||
// CHECK:STDERR: fail_module_in_inline_cpp.carbon:[[@LINE+11]]:1: error: module declaration must occur at the start of the translation unit [CppInteropParseError]
|
||||
// CHECK:STDERR: 17 | module Foo;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: <carbon Cpp imports>:1:1: note: add 'module;' to the start of the file to introduce a global module fragment [CppInteropParseNote]
|
||||
// CHECK:STDERR: 1 | # 6 "fail_module_in_inline_cpp.carbon"
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_module_in_inline_cpp.carbon:[[@LINE+4]]:8: error: module 'Foo' not found [CppInteropParseError]
|
||||
// CHECK:STDERR: 17 | module Foo;
|
||||
// CHECK:STDERR: | ~~~~~~~^~~
|
||||
// CHECK:STDERR:
|
||||
module Foo;
|
||||
''';
|
||||
|
||||
// --- fail_global_module_in_inline_cpp.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: This diagnostic isn't very good.
|
||||
import Cpp inline '''
|
||||
// CHECK:STDERR: fail_global_module_in_inline_cpp.carbon:[[@LINE+4]]:1: error: 'module;' introducing a global module fragment can appear only at the start of the translation unit [CppInteropParseError]
|
||||
// CHECK:STDERR: 10 | module;
|
||||
// CHECK:STDERR: | ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
module;
|
||||
|
||||
int n;
|
||||
|
||||
// CHECK:STDERR: fail_global_module_in_inline_cpp.carbon:[[@LINE+11]]:1: error: module declaration must occur at the start of the translation unit [CppInteropParseError]
|
||||
// CHECK:STDERR: 25 | module Foo;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR: <carbon Cpp imports>:1:1: note: add 'module;' to the start of the file to introduce a global module fragment [CppInteropParseNote]
|
||||
// CHECK:STDERR: 1 | # 6 "fail_global_module_in_inline_cpp.carbon"
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_global_module_in_inline_cpp.carbon:[[@LINE+4]]:8: error: module 'Foo' not found [CppInteropParseError]
|
||||
// CHECK:STDERR: 25 | module Foo;
|
||||
// CHECK:STDERR: | ~~~~~~~^~~
|
||||
// CHECK:STDERR:
|
||||
module Foo;
|
||||
''';
|
||||
|
||||
// --- fail_import_in_inline_cpp.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: Also test that a valid module import works.
|
||||
import Cpp inline '''
|
||||
// CHECK:STDERR: fail_import_in_inline_cpp.carbon:[[@LINE+4]]:8: error: 'file_that_does_not_exist.h' file not found [CppInteropParseError]
|
||||
// CHECK:STDERR: 10 | import "file_that_does_not_exist.h";
|
||||
// CHECK:STDERR: | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
import "file_that_does_not_exist.h";
|
||||
''';
|
||||
@@ -0,0 +1,43 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
// EXTRA-ARGS: --clang-arg=-Wunused
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/unused_internal.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/unused_internal.carbon
|
||||
|
||||
// --- unused.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp inline '''c++
|
||||
// CHECK:STDERR: unused.carbon:[[@LINE+4]]:12: warning: unused variable 'n' [CppInteropParseWarning]
|
||||
// CHECK:STDERR: 9 | static int n = 0;
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
static int n = 0;
|
||||
// CHECK:STDERR: unused.carbon:[[@LINE+4]]:13: warning: unused function 'f' [CppInteropParseWarning]
|
||||
// CHECK:STDERR: 14 | static void f() {}
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
static void f() {}
|
||||
''';
|
||||
|
||||
// --- not_unused.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp inline '''c++
|
||||
static int n = 0;
|
||||
static void f() {}
|
||||
''';
|
||||
|
||||
fn F() -> i32 {
|
||||
Cpp.f();
|
||||
return Cpp.n;
|
||||
}
|
||||
Reference in New Issue
Block a user