From fa95892a37d3de00db8928245ee5a00e79d11606 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Wed, 13 Nov 2024 10:04:25 -0800 Subject: [PATCH] Add diagnostic coverage, remove possibly-unreachable unary op diagnostic (#4519) I'm working to make sure remaining diagnostics have coverage, at least the ones I'd previously added a TODO for. Note in particular that I couldn't figure out a repro for UnaryOperatorRequiresWhitespace; if you have one, I can add a test, but otherwise maybe it's actually unreachable due to being diagnosed through infix logic (or, maybe this'll let fuzzing tell me an example). --- .../declaration/no_prelude/extern.carbon | 42 +++- .../no_prelude/extern_library.carbon | 32 ++- .../definition/no_prelude/basics.carbon | 55 +++++ .../no_prelude/fail_modifiers.carbon | 204 ++++++++++++++++-- toolchain/diagnostics/coverage_test.cpp | 24 +-- .../testdata/multiline_string_literals.carbon | 46 ++++ .../lex/testdata/numeric_literals.carbon | 37 +++- toolchain/lex/testdata/string_literals.carbon | Bin 2575 -> 4783 bytes toolchain/lex/tokenized_buffer_test.cpp | 16 ++ .../parse/testdata/operators/unary.carbon | 65 ++++++ 10 files changed, 478 insertions(+), 43 deletions(-) create mode 100644 toolchain/check/testdata/function/definition/no_prelude/basics.carbon create mode 100644 toolchain/lex/testdata/multiline_string_literals.carbon create mode 100644 toolchain/parse/testdata/operators/unary.carbon diff --git a/toolchain/check/testdata/function/declaration/no_prelude/extern.carbon b/toolchain/check/testdata/function/declaration/no_prelude/extern.carbon index 2db98d38424c..651817de2ca9 100644 --- a/toolchain/check/testdata/function/declaration/no_prelude/extern.carbon +++ b/toolchain/check/testdata/function/declaration/no_prelude/extern.carbon @@ -58,12 +58,28 @@ class C { // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: extern fn F(); - // CHECK:STDERR: fail_member_extern.carbon:[[@LINE+3]]:3: error: `extern` not allowed; requires file or namespace scope [ModifierExternNotAllowed] + // CHECK:STDERR: fail_member_extern.carbon:[[@LINE+4]]:3: error: `extern` not allowed; requires file or namespace scope [ModifierExternNotAllowed] // CHECK:STDERR: extern fn G[self: Self](); // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: extern fn G[self: Self](); } +// --- fail_extern_library_in_importer.carbon + +library "[[@TEST_NAME]]"; + +import library "basic"; + +// CHECK:STDERR: fail_extern_library_in_importer.carbon:[[@LINE+7]]:1: error: cannot declare imported `fn F` as `extern library` [ExternLibraryInImporter] +// CHECK:STDERR: extern library "basic" fn F(); +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_extern_library_in_importer.carbon:[[@LINE-5]]:1: in import [InImport] +// CHECK:STDERR: basic.carbon:4:1: note: previously declared here [RedeclPrevDecl] +// CHECK:STDERR: extern fn F(); +// CHECK:STDERR: ^~~~~~~~~~~~~~ +extern library "basic" fn F(); + // CHECK:STDOUT: --- basic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -181,7 +197,7 @@ class C { // CHECK:STDOUT: %self.param: %C = value_param runtime_param0 // CHECK:STDOUT: %self: %C = bind_name self, %self.param // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc14: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc15: = complete_type_witness %.1 [template = constants.%.2] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%C @@ -193,3 +209,25 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: fn @G[%self.param_patt: %C](); // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_extern_library_in_importer.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %import_ref: %F.type = import_ref Main//basic, inst+1, loaded [template = constants.%F] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import = import +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: extern fn @F(); +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon b/toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon index e3c6c7244d38..a3d8cdf9990c 100644 --- a/toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon +++ b/toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon @@ -132,15 +132,25 @@ library "[[@TEST_NAME]]"; import library "extern_of_import"; -// CHECK:STDERR: fail_extern_of_import_redecl.carbon:[[@LINE+7]]:1: error: redeclarations of `fn F` must match use of `extern` [RedeclExternMismatch] +// CHECK:STDERR: fail_extern_of_import_redecl.carbon:[[@LINE+8]]:1: error: redeclarations of `fn F` must match use of `extern` [RedeclExternMismatch] // CHECK:STDERR: extern library "extern_of_import" fn F(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_extern_of_import_redecl.carbon:[[@LINE-5]]:1: in import [InImport] // CHECK:STDERR: extern_of_import.carbon:4:1: note: previously declared here [RedeclPrevDecl] // CHECK:STDERR: fn F(); // CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: extern library "extern_of_import" fn F(); +// --- fail_extern_library_on_definition.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_extern_library_on_definition.carbon:[[@LINE+3]]:1: error: a library cannot be provided for an `extern` modifier on a definition [ExternLibraryOnDefinition] +// CHECK:STDERR: extern library "extern_library_owner" fn F() {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +extern library "extern_library_owner" fn F() {} + // CHECK:STDOUT: --- extern_library.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -367,3 +377,23 @@ extern library "extern_of_import" fn F(); // CHECK:STDOUT: // CHECK:STDOUT: fn @F(); // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_extern_library_on_definition.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: extern fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/definition/no_prelude/basics.carbon b/toolchain/check/testdata/function/definition/no_prelude/basics.carbon new file mode 100644 index 000000000000..b9e0902d947e --- /dev/null +++ b/toolchain/check/testdata/function/definition/no_prelude/basics.carbon @@ -0,0 +1,55 @@ + +// 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 +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/definition/no_prelude/basics.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/definition/no_prelude/basics.carbon + +// --- fail_incomplete_type.carbon + +class C; + +// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+6]]:6: error: parameter has incomplete type `C` in function definition [IncompleteTypeInFunctionParam] +// CHECK:STDERR: fn F(n: C) {} +// CHECK:STDERR: ^~~~ +// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE-5]]:1: note: class was forward declared here [ClassForwardDeclaredHere] +// CHECK:STDERR: class C; +// CHECK:STDERR: ^~~~~~~~ +fn F(n: C) {} + +// CHECK:STDOUT: --- fail_incomplete_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %n.patt: %C = binding_pattern n +// CHECK:STDOUT: %n.param_patt: %C = value_param_pattern %n.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %n.param: %C = value_param runtime_param0 +// CHECK:STDOUT: %n: %C = bind_name n, %n.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%n.param_patt: %C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_modifiers.carbon b/toolchain/check/testdata/interface/no_prelude/fail_modifiers.carbon index 2e16f77e5687..b676e49f1e2e 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_modifiers.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_modifiers.carbon @@ -8,72 +8,240 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_modifiers.carbon -// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: error: `abstract` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] +// --- fail_abstract.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_abstract.carbon:[[@LINE+4]]:1: error: `abstract` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] // CHECK:STDERR: abstract interface Abstract { // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: abstract interface Abstract { } -// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: error: `default` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] +// --- fail_default.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_default.carbon:[[@LINE+4]]:1: error: `default` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] // CHECK:STDERR: default interface Default; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: default interface Default; -// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: error: `virtual` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] +// --- fail_virtual.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:1: error: `virtual` not allowed on `interface` declaration [ModifierNotAllowedOnDeclaration] // CHECK:STDERR: virtual interface Virtual { // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: virtual interface Virtual { } -// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+3]]:1: error: `protected` not allowed; requires class scope [ModifierProtectedNotAllowed] +// --- fail_protected.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_protected.carbon:[[@LINE+4]]:1: error: `protected` not allowed; requires class scope [ModifierProtectedNotAllowed] // CHECK:STDERR: protected interface Protected; // CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: protected interface Protected; -// CHECK:STDOUT: --- fail_modifiers.carbon +// --- fail_private_member.carbon + +library "[[@TEST_NAME]]"; + +interface I { + // CHECK:STDERR: fail_private_member.carbon:[[@LINE+4]]:3: error: `private` not allowed; requires class or file scope [ModifierPrivateNotAllowed] + // CHECK:STDERR: private fn F[self: Self](); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + private fn F[self: Self](); +} + +// --- fail_protected_member.carbon + +library "[[@TEST_NAME]]"; + +interface I { + // CHECK:STDERR: fail_protected_member.carbon:[[@LINE+3]]:3: error: `protected` not allowed; requires class scope [ModifierProtectedNotAllowed] + // CHECK:STDERR: protected fn F[self: Self](); + // CHECK:STDERR: ^~~~~~~~~ + protected fn F[self: Self](); +} + +// CHECK:STDOUT: --- fail_abstract.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Abstract.type: type = facet_type <@Abstract> [template] -// CHECK:STDOUT: %Self.1: %Abstract.type = bind_symbolic_name Self, 0 [symbolic] -// CHECK:STDOUT: %Default.type: type = facet_type <@Default> [template] -// CHECK:STDOUT: %Virtual.type: type = facet_type <@Virtual> [template] -// CHECK:STDOUT: %Self.2: %Virtual.type = bind_symbolic_name Self, 0 [symbolic] -// CHECK:STDOUT: %Protected.type: type = facet_type <@Protected> [template] +// CHECK:STDOUT: %Self: %Abstract.type = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Abstract = %Abstract.decl -// CHECK:STDOUT: .Default = %Default.decl -// CHECK:STDOUT: .Virtual = %Virtual.decl -// CHECK:STDOUT: .Protected = %Protected.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Abstract.decl: type = interface_decl @Abstract [template = constants.%Abstract.type] {} {} -// CHECK:STDOUT: %Default.decl: type = interface_decl @Default [template = constants.%Default.type] {} {} -// CHECK:STDOUT: %Virtual.decl: type = interface_decl @Virtual [template = constants.%Virtual.type] {} {} -// CHECK:STDOUT: %Protected.decl: type = interface_decl @Protected [template = constants.%Protected.type] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Abstract { -// CHECK:STDOUT: %Self: %Abstract.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.1] +// CHECK:STDOUT: %Self: %Abstract.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self // CHECK:STDOUT: witness = () // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_default.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Default.type: type = facet_type <@Default> [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Default = %Default.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Default.decl: type = interface_decl @Default [template = constants.%Default.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: interface @Default; // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_virtual.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Virtual.type: type = facet_type <@Virtual> [template] +// CHECK:STDOUT: %Self: %Virtual.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Virtual = %Virtual.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Virtual.decl: type = interface_decl @Virtual [template = constants.%Virtual.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: interface @Virtual { -// CHECK:STDOUT: %Self: %Virtual.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.2] +// CHECK:STDOUT: %Self: %Virtual.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self // CHECK:STDOUT: witness = () // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_protected.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Protected.type: type = facet_type <@Protected> [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Protected = %Protected.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Protected.decl: type = interface_decl @Protected [template = constants.%Protected.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: interface @Protected; // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_private_member.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %I.type: type = facet_type <@I> [template] +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.1: type = assoc_entity_type %I.type, %F.type [template] +// CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @I.%F.decl [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %self.patt: @F.%Self (%Self) = binding_pattern self +// CHECK:STDOUT: %self.param_patt: @F.%Self (%Self) = value_param_pattern %self.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.loc9_22.1: type = facet_type_access %Self.ref [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.loc9_22.2: type = converted %Self.ref, %.loc9_22.1 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %self.param: @F.%Self (%Self) = value_param runtime_param0 +// CHECK:STDOUT: %self: @F.%Self (%Self) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc9: %.1 = assoc_entity element0, %F.decl [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc9 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(@I.%Self: %I.type) { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self.param_patt: @F.%Self (%Self)](); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_protected_member.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %I.type: type = facet_type <@I> [template] +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.1: type = assoc_entity_type %I.type, %F.type [template] +// CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @I.%F.decl [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %self.patt: @F.%Self (%Self) = binding_pattern self +// CHECK:STDOUT: %self.param_patt: @F.%Self (%Self) = value_param_pattern %self.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %.loc8_24.2: type = converted %Self.ref, %.loc8_24.1 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %self.param: @F.%Self (%Self) = value_param runtime_param0 +// CHECK:STDOUT: %self: @F.%Self (%Self) = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8: %.1 = assoc_entity element0, %F.decl [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc8 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(@I.%Self: %I.type) { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self.param_patt: @F.%Self (%Self)](); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/diagnostics/coverage_test.cpp b/toolchain/diagnostics/coverage_test.cpp index f21d8936d664..979bacfaae5d 100644 --- a/toolchain/diagnostics/coverage_test.cpp +++ b/toolchain/diagnostics/coverage_test.cpp @@ -33,30 +33,14 @@ constexpr DiagnosticKind UntestedDiagnosticKinds[] = { // should be tested. DiagnosticKind::ArrayBoundTooLarge, - // This isn't feasible to test with a normal testcase, but is tested in + // These aren't feasible to test with a normal testcase, but are tested in // lex/tokenized_buffer_test.cpp. DiagnosticKind::TooManyTokens, - - // TODO: Should look closer at these, but adding tests is a high risk of - // loss in merge conflicts due to the amount of tests being changed right - // now. - DiagnosticKind::ExternLibraryInImporter, - DiagnosticKind::ExternLibraryOnDefinition, - DiagnosticKind::HexadecimalEscapeMissingDigits, - DiagnosticKind::IncompleteTypeInFunctionParam, - DiagnosticKind::InvalidDigit, - DiagnosticKind::InvalidDigitSeparator, - DiagnosticKind::InvalidHorizontalWhitespaceInString, - DiagnosticKind::MismatchedIndentInString, - DiagnosticKind::ModifierPrivateNotAllowed, - DiagnosticKind::MultiLineStringWithDoubleQuotes, - DiagnosticKind::TooManyDigits, - DiagnosticKind::UnaryOperatorRequiresWhitespace, - DiagnosticKind::UnicodeEscapeSurrogate, - DiagnosticKind::UnicodeEscapeTooLarge, - DiagnosticKind::UnknownBaseSpecifier, DiagnosticKind::UnsupportedCRLineEnding, DiagnosticKind::UnsupportedLFCRLineEnding, + + // This is a little long but is tested in lex/numeric_literal_test.cpp. + DiagnosticKind::TooManyDigits, }; // Looks for diagnostic kinds that aren't covered by a file_test. diff --git a/toolchain/lex/testdata/multiline_string_literals.carbon b/toolchain/lex/testdata/multiline_string_literals.carbon new file mode 100644 index 000000000000..1c67d9fa098f --- /dev/null +++ b/toolchain/lex/testdata/multiline_string_literals.carbon @@ -0,0 +1,46 @@ +// 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 +// +// For multiline string literals, force autoupdates to the end so that we don't +// accidentally mix diagnostics with the literal. +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lex/testdata/multiline_string_literals.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lex/testdata/multiline_string_literals.carbon + +// --- fail_indent_mismatch.carbon + + ''' +a + ''' + +// --- fail_quotes.carbon + +""" +a +""" + +// --- AUTOUPDATE-SPLIT + +// CHECK:STDERR: fail_indent_mismatch.carbon:3:1: error: indentation does not match that of the closing `'''` in multi-line string literal [MismatchedIndentInString] +// CHECK:STDERR: a +// CHECK:STDERR: ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_quotes.carbon:2:1: error: use `'''` delimiters for a multi-line string literal, not `"""` [MultiLineStringWithDoubleQuotes] +// CHECK:STDERR: """ +// CHECK:STDERR: ^ +// CHECK:STDOUT: - filename: fail_indent_mismatch.carbon +// CHECK:STDOUT: tokens: +// CHECK:STDOUT: - { index: 1, kind: 'StringLiteral', line: {{ *}}2, column: 3, indent: 3, spelling: '''' +// CHECK:STDOUT: a +// CHECK:STDOUT: '''', value: `a +// CHECK:STDOUT: `, has_leading_space: true } +// CHECK:STDOUT: - filename: fail_quotes.carbon +// CHECK:STDOUT: tokens: +// CHECK:STDOUT: - { index: 1, kind: 'StringLiteral', line: {{ *}}2, column: 1, indent: 1, spelling: '""" +// CHECK:STDOUT: a +// CHECK:STDOUT: """', value: `a +// CHECK:STDOUT: `, has_leading_space: true } diff --git a/toolchain/lex/testdata/numeric_literals.carbon b/toolchain/lex/testdata/numeric_literals.carbon index 9c6df916c1ad..cd39bd13f238 100644 --- a/toolchain/lex/testdata/numeric_literals.carbon +++ b/toolchain/lex/testdata/numeric_literals.carbon @@ -104,8 +104,41 @@ fn F() { // CHECK:STDOUT: - filename: fail_wrong_real_exponent.carbon // CHECK:STDOUT: tokens: -// CHECK:STDERR: fail_wrong_real_exponent.carbon:[[@LINE+3]]:4: error: expected 'e' to introduce exponent [WrongRealLiteralExponent] +// CHECK:STDERR: fail_wrong_real_exponent.carbon:[[@LINE+4]]:4: error: expected 'e' to introduce exponent [WrongRealLiteralExponent] // CHECK:STDERR: 1.0r3 // CHECK:STDERR: ^ +// CHECK:STDERR: 1.0r3 -// CHECK:STDOUT: - { index: 1, kind: 'Error', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '1.0r3', has_leading_space: true } +// CHECK:STDOUT: - { index: 1, kind: 'Error', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '1.0r3', has_leading_space: true } + +// --- fail_invalid_digit.carbon +// CHECK:STDOUT: - filename: fail_invalid_digit.carbon +// CHECK:STDOUT: tokens: + +// CHECK:STDERR: fail_invalid_digit.carbon:[[@LINE+4]]:4: error: invalid digit 'a' in hexadecimal numeric literal [InvalidDigit] +// CHECK:STDERR: 0x1a +// CHECK:STDERR: ^ +// CHECK:STDERR: +0x1a +// CHECK:STDOUT: - { index: 1, kind: 'Error', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '0x1a', has_leading_space: true } + +// --- fail_invalid_separator.carbon +// CHECK:STDOUT: - filename: fail_invalid_separator.carbon +// CHECK:STDOUT: tokens: + +// CHECK:STDERR: fail_invalid_separator.carbon:[[@LINE+4]]:2: error: misplaced digit separator in numeric literal [InvalidDigitSeparator] +// CHECK:STDERR: 1__2 +// CHECK:STDERR: ^ +// CHECK:STDERR: +1__2 +// CHECK:STDOUT: - { index: 1, kind: 'IntLiteral', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '1__2', value: `12`, has_leading_space: true } + +// --- fail_unknown_base.carbon +// CHECK:STDOUT: - filename: fail_unknown_base.carbon +// CHECK:STDOUT: tokens: + +// CHECK:STDERR: fail_unknown_base.carbon:[[@LINE+3]]:1: error: unknown base specifier in numeric literal [UnknownBaseSpecifier] +// CHECK:STDERR: 05 +// CHECK:STDERR: ^ +05 +// CHECK:STDOUT: - { index: 1, kind: 'Error', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '05', has_leading_space: true } diff --git a/toolchain/lex/testdata/string_literals.carbon b/toolchain/lex/testdata/string_literals.carbon index db2ca7889a3ab96d928ae9a4f692980082a68632..b8d4b9c7c9052488993e40707c67c40850648561 100644 GIT binary patch delta 1077 zcmbV~&2G~`6osWA5<7^9mJnzp;1UTTQApDQ5;6-wO`=4!NHj$((!`!PQ+p(59L8f} zh@y%YfW>Th0yZpQ#S5_DLEsILSTnX`EB%25v-6pIJ?A_3zAt{h{^f%rzGe#Iqw-Ds z&YsWs6|t@q#nl`VKh;(7DR*|o#(|DK6OFMxBA!R6r4NZkxF`CV74a~$^v?=y`FOv0 zt6ZGFx?Bzn82KKD0fv3oaohXDIN zer*jlTaC>pT4%T3*xAvbvKNSF>ZOP&NSO*j<;E>|g&ZGiUK*}gNZHQ^2W%-;Bp%?;5MQ# zb`YTu%SjSA7&Gj7GKvY|Hpr@Y0^s47KBn>q+p-5i>=x!;pxdSrjtpBaBX3;Fk@F&b zvQ0Y?+DT!lGOJ>#e=Np)MNP6Z3hH8Zs?2Uf@q7tpAuf8Ea<~cSd`e7ri1mew2M0$* zd{RpH(v-p7=?Jz+SG#eT2r3Guz1%!?QS7v3CViKpN19TiFlWwpRdRiV@Zk$bW?m+uUuQu M53#4^a^{!+0DymO0{{R3 delta 38 ucmZ3l+Ap$U1_z_@-EDHPklf@ioLT??kPL4C diff --git a/toolchain/lex/tokenized_buffer_test.cpp b/toolchain/lex/tokenized_buffer_test.cpp index 1731a1b623d0..68be49380afb 100644 --- a/toolchain/lex/tokenized_buffer_test.cpp +++ b/toolchain/lex/tokenized_buffer_test.cpp @@ -1119,6 +1119,22 @@ TEST_F(LexerTest, DiagnosticInvalidDigit) { compile_helper_.GetTokenizedBuffer("0x123abc", &consumer); } +TEST_F(LexerTest, DiagnosticCR) { + Testing::MockDiagnosticConsumer consumer; + EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic( + DiagnosticKind::UnsupportedCRLineEnding, + DiagnosticLevel::Error, 1, 1, _))); + compile_helper_.GetTokenizedBuffer("\r", &consumer); +} + +TEST_F(LexerTest, DiagnosticLFCR) { + Testing::MockDiagnosticConsumer consumer; + EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic( + DiagnosticKind::UnsupportedLFCRLineEnding, + DiagnosticLevel::Error, 2, 1, _))); + compile_helper_.GetTokenizedBuffer("\n\r", &consumer); +} + TEST_F(LexerTest, DiagnosticMissingTerminator) { Testing::MockDiagnosticConsumer consumer; EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic( diff --git a/toolchain/parse/testdata/operators/unary.carbon b/toolchain/parse/testdata/operators/unary.carbon new file mode 100644 index 000000000000..cf6ba2a384c6 --- /dev/null +++ b/toolchain/parse/testdata/operators/unary.carbon @@ -0,0 +1,65 @@ +// 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 +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/unary.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/unary.carbon + +// --- fail_space_before.carbon + +fn F() { + // CHECK:STDERR: fail_space_before.carbon:[[@LINE+3]]:16: error: whitespace is required before this unary operator [UnaryOperatorRequiresWhitespace] + // CHECK:STDERR: if (false) {}--0; + // CHECK:STDERR: ^~ + if (false) {}--0; +} + +// --- todo_fail_space_before_op_with_keyword.carbon + +fn F() { + if (false) {}--false; +} + +// CHECK:STDOUT: - filename: fail_space_before.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'IfConditionStart', text: '('}, +// CHECK:STDOUT: {kind: 'BoolLiteralFalse', text: 'false'}, +// CHECK:STDOUT: {kind: 'IfCondition', text: ')', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'CodeBlockStart', text: '{'}, +// CHECK:STDOUT: {kind: 'CodeBlock', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IfStatement', text: 'if', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'}, +// CHECK:STDOUT: {kind: 'PrefixOperatorMinusMinus', text: '--', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: todo_fail_space_before_op_with_keyword.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'IfConditionStart', text: '('}, +// CHECK:STDOUT: {kind: 'BoolLiteralFalse', text: 'false'}, +// CHECK:STDOUT: {kind: 'IfCondition', text: ')', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'CodeBlockStart', text: '{'}, +// CHECK:STDOUT: {kind: 'CodeBlock', text: '}', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IfStatement', text: 'if', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'BoolLiteralFalse', text: 'false'}, +// CHECK:STDOUT: {kind: 'PrefixOperatorMinusMinus', text: '--', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ]