Browse Source

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).
Jon Ross-Perkins 1 year ago
parent
commit
fa95892a37

+ 40 - 2
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: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:   %.loc15: <witness> = 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> = namespace [template] {
+// CHECK:STDOUT:     .F = invalid
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %default.import = import <invalid>
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: extern fn @F();
+// CHECK:STDOUT:

+ 31 - 1
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> = 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:

+ 55 - 0
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> = 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:

+ 186 - 18
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> = 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> = 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> = 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> = 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> = 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> = 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:

+ 4 - 20
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.

+ 46 - 0
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 }

+ 35 - 2
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 }

BIN
toolchain/lex/testdata/string_literals.carbon


+ 16 - 0
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(

+ 65 - 0
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:   ]