Просмотр исходного кода

Disallow `abstract` or `base` on class declarations (that are not definitions) (#4378)

Per:
[p3762](https://docs.carbon-lang.dev/proposals/p3762.html#modifier-keywords:~:text=Other%20class%2C%20impl%2C%20and%20interface%20modifiers%20%28abstract%2C%20base%2C%20final%29%20exist%20only%20on%20the%20definition%2C%20not%20on%20the%20forward%20declaration):
"Other class, impl, and interface modifiers (`abstract`, `base`,
`final`) exist only on the definition, not on the forward declaration."
David Blaikie 1 год назад
Родитель
Сommit
b1014bf9f5

+ 7 - 15
toolchain/check/handle_class.cpp

@@ -79,19 +79,6 @@ static auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
     return false;
   }
 
-  // The introducer kind must match the previous declaration.
-  // TODO: The rule here is not yet decided. See #3384.
-  if (prev_class.inheritance_kind != new_class.inheritance_kind) {
-    CARBON_DIAGNOSTIC(ClassRedeclarationDifferentIntroducer, Error,
-                      "class redeclared with different inheritance kind");
-    CARBON_DIAGNOSTIC(ClassRedeclarationDifferentIntroducerPrevious, Note,
-                      "previously declared here");
-    context.emitter()
-        .Build(new_loc, ClassRedeclarationDifferentIntroducer)
-        .Note(prev_loc, ClassRedeclarationDifferentIntroducerPrevious)
-        .Emit();
-  }
-
   if (new_is_definition) {
     prev_class.MergeDefinition(new_class);
     prev_class.scope_id = new_class.scope_id;
@@ -194,9 +181,14 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
   auto introducer =
       context.decl_introducer_state_stack().Pop<Lex::TokenKind::Class>();
   CheckAccessModifiersOnDecl(context, introducer, parent_scope_inst);
+  auto always_acceptable_modifiers =
+      KeywordModifierSet::Access | KeywordModifierSet::Extern;
   LimitModifiersOnDecl(context, introducer,
-                       KeywordModifierSet::Class | KeywordModifierSet::Access |
-                           KeywordModifierSet::Extern);
+                       always_acceptable_modifiers | KeywordModifierSet::Class);
+  if (!is_definition) {
+    LimitModifiersOnNotDefinition(context, introducer,
+                                  always_acceptable_modifiers);
+  }
   RestrictExternModifierOnDecl(context, introducer, parent_scope_inst,
                                is_definition);
 

+ 6 - 0
toolchain/check/modifiers.h

@@ -46,6 +46,12 @@ inline auto LimitModifiersOnDecl(Context& context,
   ForbidModifiersOnDecl(context, introducer, ~allowed, "");
 }
 
+inline auto LimitModifiersOnNotDefinition(Context& context,
+                                          DeclIntroducerState& introducer,
+                                          KeywordModifierSet allowed) -> void {
+  ForbidModifiersOnDecl(context, introducer, ~allowed, ", only definition");
+}
+
 // Restricts the `extern` modifier to only be used on namespace-scoped
 // declarations. Diagnoses and cleans up:
 // - `extern library` on a definition.

+ 126 - 60
toolchain/check/testdata/class/fail_abstract.carbon

@@ -8,6 +8,8 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_abstract.carbon
 
+
+// --- fail_todo_rejects_valid_abstract_subobject_construction.carbon
 abstract class Abstract {
   var a: i32;
 }
@@ -20,17 +22,34 @@ class Derived {
 
 fn Make() -> Derived {
   // TODO: This should be valid, and should construct an instance of `partial Abstract` as the base.
-  // CHECK:STDERR: fail_abstract.carbon:[[@LINE+3]]:19: error: cannot construct instance of abstract class; consider using `partial Abstract` instead
+  // CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_construction.carbon:[[@LINE+6]]:19: error: cannot construct instance of abstract class; consider using `partial Abstract` instead
   // CHECK:STDERR:   return {.base = {.a = 1}, .d = 7};
   // CHECK:STDERR:                   ^~~~~~~~
+  // CHECK:STDERR:
+  // CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_access.carbon: error: `Main//default` previously provided by `fail_todo_rejects_valid_abstract_subobject_construction.carbon`
+  // CHECK:STDERR:
   return {.base = {.a = 1}, .d = 7};
 }
 
+// --- fail_todo_rejects_valid_abstract_subobject_access.carbon
+
+// CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_access.carbon:[[@LINE+6]]:14: error: name `Derived` not found
+// CHECK:STDERR: fn Access(d: Derived) -> (i32, i32) {
+// CHECK:STDERR:              ^~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_abstract_decl.carbon: error: `Main//default` previously provided by `fail_todo_rejects_valid_abstract_subobject_construction.carbon`
+// CHECK:STDERR:
 fn Access(d: Derived) -> (i32, i32) {
   return (d.d, d.base.a);
 }
 
-// CHECK:STDOUT: --- fail_abstract.carbon
+// --- fail_abstract_decl.carbon
+// CHECK:STDERR: fail_abstract_decl.carbon:[[@LINE+3]]:1: error: `abstract` not allowed on `class` declaration, only definition
+// CHECK:STDERR: abstract class AbstractDecl;
+// CHECK:STDERR: ^~~~~~~~
+abstract class AbstractDecl;
+
+// CHECK:STDOUT: --- fail_todo_rejects_valid_abstract_subobject_construction.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %Abstract: type = class_type @Abstract [template]
@@ -54,11 +73,6 @@ fn Access(d: Derived) -> (i32, i32) {
 // CHECK:STDOUT:   %.13: i32 = int_literal 1 [template]
 // CHECK:STDOUT:   %.14: i32 = int_literal 7 [template]
 // CHECK:STDOUT:   %.15: type = struct_type {.base: %.3, .d: i32} [template]
-// CHECK:STDOUT:   %.16: type = tuple_type (type, type) [template]
-// CHECK:STDOUT:   %.17: type = tuple_type (i32, i32) [template]
-// CHECK:STDOUT:   %Access.type: type = fn_type @Access [template]
-// CHECK:STDOUT:   %Access: %Access.type = struct_value () [template]
-// CHECK:STDOUT:   %.18: type = ptr_type %.17 [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -82,7 +96,6 @@ fn Access(d: Derived) -> (i32, i32) {
 // CHECK:STDOUT:     .Abstract = %Abstract.decl
 // CHECK:STDOUT:     .Derived = %Derived.decl
 // CHECK:STDOUT:     .Make = %Make.decl
-// CHECK:STDOUT:     .Access = %Access.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {}
@@ -91,49 +104,33 @@ fn Access(d: Derived) -> (i32, i32) {
 // CHECK:STDOUT:     %Derived.ref: type = name_ref Derived, file.%Derived.decl [template = constants.%Derived]
 // CHECK:STDOUT:     %return: ref %Derived = var <return slot>
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] {
-// CHECK:STDOUT:     %d.patt: %Derived = binding_pattern d
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %Derived.ref: type = name_ref Derived, file.%Derived.decl [template = constants.%Derived]
-// CHECK:STDOUT:     %d.param: %Derived = param d, runtime_param0
-// CHECK:STDOUT:     %d: %Derived = bind_name d, %d.param
-// CHECK:STDOUT:     %int.make_type_32.loc29_27: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:     %int.make_type_32.loc29_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:     %.loc29_35.1: %.16 = tuple_literal (%int.make_type_32.loc29_27, %int.make_type_32.loc29_32)
-// CHECK:STDOUT:     %.loc29_35.2: type = value_of_initializer %int.make_type_32.loc29_27 [template = i32]
-// CHECK:STDOUT:     %.loc29_35.3: type = converted %int.make_type_32.loc29_27, %.loc29_35.2 [template = i32]
-// CHECK:STDOUT:     %.loc29_35.4: type = value_of_initializer %int.make_type_32.loc29_32 [template = i32]
-// CHECK:STDOUT:     %.loc29_35.5: type = converted %int.make_type_32.loc29_32, %.loc29_35.4 [template = i32]
-// CHECK:STDOUT:     %.loc29_35.6: type = converted %.loc29_35.1, constants.%.17 [template = constants.%.17]
-// CHECK:STDOUT:     %return: ref %.17 = var <return slot>
-// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Abstract {
 // CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc12_10.1: type = value_of_initializer %int.make_type_32 [template = i32]
-// CHECK:STDOUT:   %.loc12_10.2: type = converted %int.make_type_32, %.loc12_10.1 [template = i32]
-// CHECK:STDOUT:   %.loc12_8: %.2 = field_decl a, element0 [template]
-// CHECK:STDOUT:   %.loc13: <witness> = complete_type_witness %.3 [template = constants.%.4]
+// CHECK:STDOUT:   %.loc2_10.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc2_10.2: type = converted %int.make_type_32, %.loc2_10.1 [template = i32]
+// CHECK:STDOUT:   %.loc2_8: %.2 = field_decl a, element0 [template]
+// CHECK:STDOUT:   %.loc3: <witness> = complete_type_witness %.3 [template = constants.%.4]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Abstract
-// CHECK:STDOUT:   .a = %.loc12_8
+// CHECK:STDOUT:   .a = %.loc2_8
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @Derived {
 // CHECK:STDOUT:   %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract]
-// CHECK:STDOUT:   %.loc16: %.6 = base_decl %Abstract, element0 [template]
+// CHECK:STDOUT:   %.loc6: %.6 = base_decl %Abstract, element0 [template]
 // CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc18_10.1: type = value_of_initializer %int.make_type_32 [template = i32]
-// CHECK:STDOUT:   %.loc18_10.2: type = converted %int.make_type_32, %.loc18_10.1 [template = i32]
-// CHECK:STDOUT:   %.loc18_8: %.7 = field_decl d, element1 [template]
-// CHECK:STDOUT:   %.loc19: <witness> = complete_type_witness %.8 [template = constants.%.9]
+// CHECK:STDOUT:   %.loc8_10.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc8_10.2: type = converted %int.make_type_32, %.loc8_10.1 [template = i32]
+// CHECK:STDOUT:   %.loc8_8: %.7 = field_decl d, element1 [template]
+// CHECK:STDOUT:   %.loc9: <witness> = complete_type_witness %.8 [template = constants.%.9]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .base = %.loc16
-// CHECK:STDOUT:   .d = %.loc18_8
+// CHECK:STDOUT:   .base = %.loc6
+// CHECK:STDOUT:   .d = %.loc8_8
 // CHECK:STDOUT:   extend name_scope2
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -141,33 +138,102 @@ fn Access(d: Derived) -> (i32, i32) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Make() -> %return: %Derived {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc26_25: i32 = int_literal 1 [template = constants.%.13]
-// CHECK:STDOUT:   %.loc26_26: %.3 = struct_literal (%.loc26_25)
-// CHECK:STDOUT:   %.loc26_34: i32 = int_literal 7 [template = constants.%.14]
-// CHECK:STDOUT:   %.loc26_35: %.15 = struct_literal (%.loc26_26, %.loc26_34)
+// CHECK:STDOUT:   %.loc19_25: i32 = int_literal 1 [template = constants.%.13]
+// CHECK:STDOUT:   %.loc19_26: %.3 = struct_literal (%.loc19_25)
+// CHECK:STDOUT:   %.loc19_34: i32 = int_literal 7 [template = constants.%.14]
+// CHECK:STDOUT:   %.loc19_35: %.15 = struct_literal (%.loc19_26, %.loc19_34)
 // CHECK:STDOUT:   return <error> to %return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @Access(%d: %Derived) -> %return: %.17 {
+// CHECK:STDOUT: --- fail_todo_rejects_valid_abstract_subobject_access.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = tuple_type (type, type) [template]
+// CHECK:STDOUT:   %.3: type = tuple_type (i32, i32) [template]
+// CHECK:STDOUT:   %Access.type: type = fn_type @Access [template]
+// CHECK:STDOUT:   %Access: %Access.type = struct_value () [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.3 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int32 = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .Access = %Access.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] {
+// CHECK:STDOUT:     %d.patt: <error> = binding_pattern d
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Derived.ref: <error> = name_ref Derived, <error> [template = <error>]
+// CHECK:STDOUT:     %d.param: <error> = param d, runtime_param0
+// CHECK:STDOUT:     %d: <error> = bind_name d, %d.param
+// CHECK:STDOUT:     %int.make_type_32.loc8_27: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %int.make_type_32.loc8_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc8_35.1: %.2 = tuple_literal (%int.make_type_32.loc8_27, %int.make_type_32.loc8_32)
+// CHECK:STDOUT:     %.loc8_35.2: type = value_of_initializer %int.make_type_32.loc8_27 [template = i32]
+// CHECK:STDOUT:     %.loc8_35.3: type = converted %int.make_type_32.loc8_27, %.loc8_35.2 [template = i32]
+// CHECK:STDOUT:     %.loc8_35.4: type = value_of_initializer %int.make_type_32.loc8_32 [template = i32]
+// CHECK:STDOUT:     %.loc8_35.5: type = converted %int.make_type_32.loc8_32, %.loc8_35.4 [template = i32]
+// CHECK:STDOUT:     %.loc8_35.6: type = converted %.loc8_35.1, constants.%.3 [template = constants.%.3]
+// CHECK:STDOUT:     %return: ref %.3 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Access(%d: <error>) -> %return: %.3 {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %d.ref.loc30_11: %Derived = name_ref d, %d
-// CHECK:STDOUT:   %d.ref.loc30_12: %.7 = name_ref d, @Derived.%.loc18_8 [template = @Derived.%.loc18_8]
-// CHECK:STDOUT:   %.loc30_12.1: ref i32 = class_element_access %d.ref.loc30_11, element1
-// CHECK:STDOUT:   %.loc30_12.2: i32 = bind_value %.loc30_12.1
-// CHECK:STDOUT:   %d.ref.loc30_16: %Derived = name_ref d, %d
-// CHECK:STDOUT:   %base.ref: %.6 = name_ref base, @Derived.%.loc16 [template = @Derived.%.loc16]
-// CHECK:STDOUT:   %.loc30_17.1: ref %Abstract = class_element_access %d.ref.loc30_16, element0
-// CHECK:STDOUT:   %.loc30_17.2: %Abstract = bind_value %.loc30_17.1
-// CHECK:STDOUT:   %a.ref: %.2 = name_ref a, @Abstract.%.loc12_8 [template = @Abstract.%.loc12_8]
-// CHECK:STDOUT:   %.loc30_22.1: ref i32 = class_element_access %.loc30_17.2, element0
-// CHECK:STDOUT:   %.loc30_22.2: i32 = bind_value %.loc30_22.1
-// CHECK:STDOUT:   %.loc30_24.1: %.17 = tuple_literal (%.loc30_12.2, %.loc30_22.2)
-// CHECK:STDOUT:   %.loc30_24.2: ref i32 = tuple_access %return, element0
-// CHECK:STDOUT:   %.loc30_24.3: init i32 = initialize_from %.loc30_12.2 to %.loc30_24.2
-// CHECK:STDOUT:   %.loc30_24.4: ref i32 = tuple_access %return, element1
-// CHECK:STDOUT:   %.loc30_24.5: init i32 = initialize_from %.loc30_22.2 to %.loc30_24.4
-// CHECK:STDOUT:   %.loc30_24.6: init %.17 = tuple_init (%.loc30_24.3, %.loc30_24.5) to %return
-// CHECK:STDOUT:   %.loc30_25: init %.17 = converted %.loc30_24.1, %.loc30_24.6
-// CHECK:STDOUT:   return %.loc30_25 to %return
+// CHECK:STDOUT:   %d.ref.loc9_11: <error> = name_ref d, %d
+// CHECK:STDOUT:   %d.ref.loc9_16: <error> = name_ref d, %d
+// CHECK:STDOUT:   %.loc9: <error> = tuple_literal (<error>, <error>)
+// CHECK:STDOUT:   return <error> to %return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_abstract_decl.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %AbstractDecl: type = class_type @AbstractDecl [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .AbstractDecl = %AbstractDecl.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %AbstractDecl.decl: type = class_decl @AbstractDecl [template = constants.%AbstractDecl] {} {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @AbstractDecl;
+// CHECK:STDOUT:

Разница между файлами не показана из-за своего большого размера
+ 688 - 389
toolchain/check/testdata/class/fail_base_bad_type.carbon


+ 53 - 26
toolchain/check/testdata/class/fail_modifiers.carbon

@@ -8,32 +8,44 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_modifiers.carbon
 
-// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:18: error: `private` repeated on declaration
-// CHECK:STDERR: private abstract private class DuplicatePrivate;
-// CHECK:STDERR:                  ^~~~~~~
+// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:9: error: `private` repeated on declaration
+// CHECK:STDERR: private private class DuplicatePrivate;
+// CHECK:STDERR:         ^~~~~~~
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: note: `private` previously appeared here
-// CHECK:STDERR: private abstract private class DuplicatePrivate;
+// CHECK:STDERR: private private class DuplicatePrivate;
 // CHECK:STDERR: ^~~~~~~
 // CHECK:STDERR:
-private abstract private class DuplicatePrivate;
+private private class DuplicatePrivate;
 
-// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:14: error: `protected` not allowed on declaration with `private`
-// CHECK:STDERR: private base protected class TwoAccess {}
-// CHECK:STDERR:              ^~~~~~~~~
+// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: error: `abstract` not allowed on `class` declaration, only definition
+// CHECK:STDERR: abstract class AbstractDecl;
+// CHECK:STDERR: ^~~~~~~~
+// CHECK:STDERR:
+abstract class AbstractDecl;
+
+// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:9: error: `protected` not allowed on declaration with `private`
+// CHECK:STDERR: private protected class TwoAccess;
+// CHECK:STDERR:         ^~~~~~~~~
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: note: `private` previously appeared here
-// CHECK:STDERR: private base protected class TwoAccess {}
+// CHECK:STDERR: private protected class TwoAccess;
 // CHECK:STDERR: ^~~~~~~
 // CHECK:STDERR:
-private base protected class TwoAccess {}
+private protected class TwoAccess;
+
+// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: error: `base` not allowed on `class` declaration, only definition
+// CHECK:STDERR: base class BaseDecl;
+// CHECK:STDERR: ^~~~
+// CHECK:STDERR:
+base class BaseDecl;
 
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:10: error: `abstract` repeated on declaration
-// CHECK:STDERR: abstract abstract class TwoAbstract;
+// CHECK:STDERR: abstract abstract class TwoAbstract { }
 // CHECK:STDERR:          ^~~~~~~~
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: note: `abstract` previously appeared here
-// CHECK:STDERR: abstract abstract class TwoAbstract;
+// CHECK:STDERR: abstract abstract class TwoAbstract { }
 // CHECK:STDERR: ^~~~~~~~
 // CHECK:STDERR:
-abstract abstract class TwoAbstract;
+abstract abstract class TwoAbstract { }
 
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+15]]:1: error: `protected` not allowed on `class` declaration at file scope, `protected` is only allowed on class members
 // CHECK:STDERR: protected virtual base class Virtual {}
@@ -53,13 +65,13 @@ abstract abstract class TwoAbstract;
 protected virtual base class Virtual {}
 
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:10: error: `protected` must appear before `abstract`
-// CHECK:STDERR: abstract protected class WrongOrder;
+// CHECK:STDERR: abstract protected class WrongOrder { }
 // CHECK:STDERR:          ^~~~~~~~~
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:1: note: `abstract` previously appeared here
-// CHECK:STDERR: abstract protected class WrongOrder;
+// CHECK:STDERR: abstract protected class WrongOrder { }
 // CHECK:STDERR: ^~~~~~~~
 // CHECK:STDERR:
-abstract protected class WrongOrder;
+abstract protected class WrongOrder { }
 
 // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:10: error: `base` not allowed on declaration with `abstract`
 // CHECK:STDERR: abstract base class AbstractAndBase {}
@@ -88,10 +100,12 @@ fn AbstractWithDefinition.G() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %DuplicatePrivate: type = class_type @DuplicatePrivate [template]
+// CHECK:STDOUT:   %AbstractDecl: type = class_type @AbstractDecl [template]
 // CHECK:STDOUT:   %TwoAccess: type = class_type @TwoAccess [template]
+// CHECK:STDOUT:   %BaseDecl: type = class_type @BaseDecl [template]
+// CHECK:STDOUT:   %TwoAbstract: type = class_type @TwoAbstract [template]
 // CHECK:STDOUT:   %.1: type = struct_type {} [template]
 // CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT:   %TwoAbstract: type = class_type @TwoAbstract [template]
 // CHECK:STDOUT:   %Virtual: type = class_type @Virtual [template]
 // CHECK:STDOUT:   %WrongOrder: type = class_type @WrongOrder [template]
 // CHECK:STDOUT:   %AbstractAndBase: type = class_type @AbstractAndBase [template]
@@ -120,7 +134,9 @@ fn AbstractWithDefinition.G() {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .Core = imports.%Core
 // CHECK:STDOUT:     .DuplicatePrivate [private] = %DuplicatePrivate.decl
+// CHECK:STDOUT:     .AbstractDecl = %AbstractDecl.decl
 // CHECK:STDOUT:     .TwoAccess [private] = %TwoAccess.decl
+// CHECK:STDOUT:     .BaseDecl = %BaseDecl.decl
 // CHECK:STDOUT:     .TwoAbstract = %TwoAbstract.decl
 // CHECK:STDOUT:     .Virtual = %Virtual.decl
 // CHECK:STDOUT:     .WrongOrder = %WrongOrder.decl
@@ -129,7 +145,9 @@ fn AbstractWithDefinition.G() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %DuplicatePrivate.decl: type = class_decl @DuplicatePrivate [template = constants.%DuplicatePrivate] {} {}
+// CHECK:STDOUT:   %AbstractDecl.decl: type = class_decl @AbstractDecl [template = constants.%AbstractDecl] {} {}
 // CHECK:STDOUT:   %TwoAccess.decl: type = class_decl @TwoAccess [template = constants.%TwoAccess] {} {}
+// CHECK:STDOUT:   %BaseDecl.decl: type = class_decl @BaseDecl [template = constants.%BaseDecl] {} {}
 // CHECK:STDOUT:   %TwoAbstract.decl: type = class_decl @TwoAbstract [template = constants.%TwoAbstract] {} {}
 // CHECK:STDOUT:   %Virtual.decl: type = class_decl @Virtual [template = constants.%Virtual] {} {}
 // CHECK:STDOUT:   %WrongOrder.decl: type = class_decl @WrongOrder [template = constants.%WrongOrder] {} {}
@@ -140,26 +158,35 @@ fn AbstractWithDefinition.G() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @DuplicatePrivate;
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @TwoAccess {
-// CHECK:STDOUT:   %.loc27: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT: class @AbstractDecl;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @TwoAccess;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @BaseDecl;
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @TwoAbstract {
+// CHECK:STDOUT:   %.loc48: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%TwoAccess
+// CHECK:STDOUT:   .Self = constants.%TwoAbstract
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @TwoAbstract;
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @Virtual {
-// CHECK:STDOUT:   %.loc53: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:   %.loc65: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Virtual
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: class @WrongOrder;
+// CHECK:STDOUT: class @WrongOrder {
+// CHECK:STDOUT:   %.loc74: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%WrongOrder
+// CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @AbstractAndBase {
-// CHECK:STDOUT:   %.loc71: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:   %.loc83: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AbstractAndBase
@@ -168,7 +195,7 @@ fn AbstractWithDefinition.G() {
 // CHECK:STDOUT: class @AbstractWithDefinition {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {} {}
-// CHECK:STDOUT:   %.loc80: <witness> = complete_type_witness %.1 [template = constants.%.2]
+// CHECK:STDOUT:   %.loc92: <witness> = complete_type_witness %.1 [template = constants.%.2]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%AbstractWithDefinition

+ 0 - 321
toolchain/check/testdata/class/fail_redeclaration_introducer.carbon

@@ -1,321 +0,0 @@
-// 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/class/fail_redeclaration_introducer.carbon
-// TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_redeclaration_introducer.carbon
-
-// --- fail_add_base.carbon
-
-library "[[@TEST_NAME]]";
-
-class A;
-// CHECK:STDERR: fail_add_base.carbon:[[@LINE+7]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: base class A {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_add_base.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: class A;
-// CHECK:STDERR: ^~~~~~~~
-// CHECK:STDERR:
-base class A {}
-
-// --- fail_add_abstract.carbon
-
-library "[[@TEST_NAME]]";
-
-class B;
-// CHECK:STDERR: fail_add_abstract.carbon:[[@LINE+7]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: abstract class B {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
-// CHECK:STDERR: fail_add_abstract.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: class B;
-// CHECK:STDERR: ^~~~~~~~
-// CHECK:STDERR:
-abstract class B {}
-
-// --- fail_remove_base.carbon
-
-library "[[@TEST_NAME]]";
-
-base class C;
-// CHECK:STDERR: fail_remove_base.carbon:[[@LINE+7]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: class C {}
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_remove_base.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: base class C;
-// CHECK:STDERR: ^~~~~~~~~~~~~
-// CHECK:STDERR:
-class C {}
-
-// --- fail_base_to_abstract.carbon
-
-library "[[@TEST_NAME]]";
-
-base class D;
-// CHECK:STDERR: fail_base_to_abstract.carbon:[[@LINE+7]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: abstract class D {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
-// CHECK:STDERR: fail_base_to_abstract.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: base class D;
-// CHECK:STDERR: ^~~~~~~~~~~~~
-// CHECK:STDERR:
-abstract class D {}
-
-// --- fail_remove_abstract.carbon
-
-library "[[@TEST_NAME]]";
-
-abstract class E;
-// CHECK:STDERR: fail_remove_abstract.carbon:[[@LINE+7]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: class E {}
-// CHECK:STDERR: ^~~~~~~~~
-// CHECK:STDERR: fail_remove_abstract.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: abstract class E;
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
-// CHECK:STDERR:
-class E {}
-
-// --- fail_abstract_to_base.carbon
-
-library "[[@TEST_NAME]]";
-
-abstract class F;
-// CHECK:STDERR: fail_abstract_to_base.carbon:[[@LINE+6]]:1: error: class redeclared with different inheritance kind
-// CHECK:STDERR: base class F {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR: fail_abstract_to_base.carbon:[[@LINE-4]]:1: note: previously declared here
-// CHECK:STDERR: abstract class F;
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
-base class F {}
-
-// CHECK:STDOUT: --- fail_add_base.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %A: type = class_type @A [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .A = %A.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %A.decl.loc4: type = class_decl @A [template = constants.%A] {} {}
-// CHECK:STDOUT:   %A.decl.loc12: type = class_decl @A [template = constants.%A] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @A {
-// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%A
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_add_abstract.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %B: type = class_type @B [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .B = %B.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %B.decl.loc4: type = class_decl @B [template = constants.%B] {} {}
-// CHECK:STDOUT:   %B.decl.loc12: type = class_decl @B [template = constants.%B] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @B {
-// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%B
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_remove_base.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %C: type = class_type @C [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .C = %C.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %C.decl.loc4: type = class_decl @C [template = constants.%C] {} {}
-// CHECK:STDOUT:   %C.decl.loc12: type = class_decl @C [template = constants.%C] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @C {
-// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%C
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_base_to_abstract.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %D: type = class_type @D [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .D = %D.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %D.decl.loc4: type = class_decl @D [template = constants.%D] {} {}
-// CHECK:STDOUT:   %D.decl.loc12: type = class_decl @D [template = constants.%D] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @D {
-// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%D
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_remove_abstract.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %E: type = class_type @E [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .E = %E.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %E.decl.loc4: type = class_decl @E [template = constants.%E] {} {}
-// CHECK:STDOUT:   %E.decl.loc12: type = class_decl @E [template = constants.%E] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @E {
-// CHECK:STDOUT:   %.loc12: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%E
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_abstract_to_base.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %F: type = class_type @F [template]
-// CHECK:STDOUT:   %.1: type = struct_type {} [template]
-// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %.1 [template]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     import Core//prelude
-// CHECK:STDOUT:     import Core//prelude/operators
-// CHECK:STDOUT:     import Core//prelude/types
-// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
-// CHECK:STDOUT:     import Core//prelude/operators/as
-// CHECK:STDOUT:     import Core//prelude/operators/bitwise
-// CHECK:STDOUT:     import Core//prelude/operators/comparison
-// CHECK:STDOUT:     import Core//prelude/types/bool
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = imports.%Core
-// CHECK:STDOUT:     .F = %F.decl.loc4
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %F.decl.loc4: type = class_decl @F [template = constants.%F] {} {}
-// CHECK:STDOUT:   %F.decl.loc11: type = class_decl @F [template = constants.%F] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: class @F {
-// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.1 [template = constants.%.2]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .Self = constants.%F
-// CHECK:STDOUT: }
-// CHECK:STDOUT:

+ 2 - 2
toolchain/check/testdata/class/redeclaration_introducer.carbon

@@ -9,8 +9,8 @@
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/redeclaration_introducer.carbon
 
 class A;
-base class B;
-abstract class C;
+class B;
+class C;
 
 class A {}
 base class B {}

+ 0 - 2
toolchain/diagnostics/diagnostic_kind.def

@@ -216,8 +216,6 @@ CARBON_DIAGNOSTIC_KIND(BaseDeclRepeated)
 CARBON_DIAGNOSTIC_KIND(BaseIsFinal)
 CARBON_DIAGNOSTIC_KIND(BaseMissingExtend)
 CARBON_DIAGNOSTIC_KIND(ClassForwardDeclaredHere)
-CARBON_DIAGNOSTIC_KIND(ClassRedeclarationDifferentIntroducer)
-CARBON_DIAGNOSTIC_KIND(ClassRedeclarationDifferentIntroducerPrevious)
 CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass)
 CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious)
 CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)

Некоторые файлы не были показаны из-за большого количества измененных файлов