diff --git a/toolchain/check/decl_state.h b/toolchain/check/decl_state.h index 44a8d13a03b4..cff68ec61739 100644 --- a/toolchain/check/decl_state.h +++ b/toolchain/check/decl_state.h @@ -71,6 +71,7 @@ struct DeclState { Base, Class, Constraint, + Export, Fn, Impl, Interface, diff --git a/toolchain/check/handle_export.cpp b/toolchain/check/handle_export.cpp index ef4e5348c7c0..055e7dbd9a3c 100644 --- a/toolchain/check/handle_export.cpp +++ b/toolchain/check/handle_export.cpp @@ -4,6 +4,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/decl_name_stack.h" +#include "toolchain/check/modifiers.h" #include "toolchain/parse/typed_nodes.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" @@ -12,6 +13,7 @@ namespace Carbon::Check { auto HandleExportIntroducer(Context& context, Parse::ExportIntroducerId /*node_id*/) -> bool { + context.decl_state_stack().Push(DeclState::Export); // TODO: Probably need to update DeclNameStack to restrict to only namespaces. context.decl_name_stack().PushScopeAndStartName(); return true; @@ -22,6 +24,10 @@ auto HandleExportDirective(Context& context, Parse::ExportDirectiveId node_id) auto name_context = context.decl_name_stack().FinishName(); context.decl_name_stack().PopScope(); + LimitModifiersOnDecl(context, KeywordModifierSet::None, + Lex::TokenKind::Export); + context.decl_state_stack().Pop(DeclState::Export); + if (name_context.state == DeclNameStack::NameContext::State::Error) { // Should already be diagnosed. return true; diff --git a/toolchain/check/testdata/packages/no_prelude/export_name.carbon b/toolchain/check/testdata/packages/no_prelude/export_name.carbon index 5c3cf1c737e4..94d877c38c32 100644 --- a/toolchain/check/testdata/packages/no_prelude/export_name.carbon +++ b/toolchain/check/testdata/packages/no_prelude/export_name.carbon @@ -95,6 +95,21 @@ import library "base"; // CHECK:STDERR: export NS; +// --- fail_export_decl.carbon + +library "fail_export_decl" api; + +class Local {} + +// CHECK:STDERR: fail_export_decl.carbon:[[@LINE+7]]:1: ERROR: Only imported entities are valid for `export`. +// CHECK:STDERR: export Local; +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: fail_export_decl.carbon:[[@LINE-5]]:1: Name is declared here. +// CHECK:STDERR: class Local {} +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: +export Local; + // --- fail_export_member.carbon library "fail_export_member" api; @@ -224,7 +239,7 @@ export C; library "use_repeat_export" api; -// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+18]]:1: In import. +// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+19]]:1: In import. // CHECK:STDERR: import library "repeat_export"; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: repeat_export.carbon:4:1: In import. @@ -233,7 +248,7 @@ library "use_repeat_export" api; // CHECK:STDERR: base.carbon:4:1: ERROR: Duplicate name being declared in the same scope. // CHECK:STDERR: class C { // CHECK:STDERR: ^~~~~~~~~ -// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+9]]:1: In import. +// CHECK:STDERR: fail_todo_use_repeat_export.carbon:[[@LINE+10]]:1: In import. // CHECK:STDERR: import library "repeat_export"; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: repeat_export.carbon:4:1: In import. @@ -242,10 +257,22 @@ library "use_repeat_export" api; // CHECK:STDERR: base.carbon:4:1: Name is previously declared here. // CHECK:STDERR: class C { // CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: import library "repeat_export"; var c: C = {.x = ()}; +// --- fail_modifiers.carbon + +library "fail_modifiers" api; + +import library "base"; + +// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+3]]:1: ERROR: `private` not allowed on `export` declaration. +// CHECK:STDERR: private export C; +// CHECK:STDERR: ^~~~~~~ +private export C; + // CHECK:STDOUT: --- base.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -630,6 +657,25 @@ var c: C = {.x = ()}; // CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+12, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_export_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Local: type = class_type @Local [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Local = %Local.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Local.decl: type = class_decl @Local [template = constants.%Local] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Local { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Local +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_export_member.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -888,14 +934,44 @@ var c: C = {.x = ()}; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc24_19.1: () = tuple_literal () -// CHECK:STDOUT: %.loc24_20.1: {.x: ()} = struct_literal (%.loc24_19.1) -// CHECK:STDOUT: %.loc24_20.2: ref () = class_element_access file.%c.var, element0 -// CHECK:STDOUT: %.loc24_19.2: init () = tuple_init () to %.loc24_20.2 [template = constants.%tuple] -// CHECK:STDOUT: %.loc24_20.3: init () = converted %.loc24_19.1, %.loc24_19.2 [template = constants.%tuple] -// CHECK:STDOUT: %.loc24_20.4: init C = class_init (%.loc24_20.3), file.%c.var [template = constants.%struct] -// CHECK:STDOUT: %.loc24_21: init C = converted %.loc24_20.1, %.loc24_20.4 [template = constants.%struct] -// CHECK:STDOUT: assign file.%c.var, %.loc24_21 +// CHECK:STDOUT: %.loc25_19.1: () = tuple_literal () +// CHECK:STDOUT: %.loc25_20.1: {.x: ()} = struct_literal (%.loc25_19.1) +// CHECK:STDOUT: %.loc25_20.2: ref () = class_element_access file.%c.var, element0 +// CHECK:STDOUT: %.loc25_19.2: init () = tuple_init () to %.loc25_20.2 [template = constants.%tuple] +// CHECK:STDOUT: %.loc25_20.3: init () = converted %.loc25_19.1, %.loc25_19.2 [template = constants.%tuple] +// CHECK:STDOUT: %.loc25_20.4: init C = class_init (%.loc25_20.3), file.%c.var [template = constants.%struct] +// CHECK:STDOUT: %.loc25_21: init C = converted %.loc25_20.1, %.loc25_20.4 [template = constants.%struct] +// CHECK:STDOUT: assign file.%c.var, %.loc25_21 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_modifiers.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %.2: type = struct_type {.x: ()} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %import_ref.1 +// CHECK:STDOUT: .NS = %NS +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, loaded [template = constants.%C] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+11, loaded +// CHECK:STDOUT: %NS: = namespace %import_ref.2, [template] { +// CHECK:STDOUT: .NSC = %import_ref.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+12, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+7, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+2, unloaded +// CHECK:STDOUT: %C: type = bind_export C, %import_ref.1 [template = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .x = file.%import_ref.4 +// CHECK:STDOUT: .Self = file.%import_ref.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index 748a7466faf3..9e4bcf315c18 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -21,11 +21,14 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool { } // Packaging-related keywords manage their packaging state. case Lex::TokenKind::Export: { - context.PushState(State::Export); + if (!context.PositionIs(Lex::TokenKind::Import, Lookahead::NextToken)) { + break; + } + context.PushState(State::ImportAsExport); return true; } case Lex::TokenKind::Import: { - context.PushState(State::Import); + context.PushState(State::ImportAsRegular); return true; } case Lex::TokenKind::Library: { @@ -37,18 +40,19 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool { return true; } default: - // Because a non-packaging keyword was encountered, packaging is complete. - // Misplaced packaging keywords may lead to this being re-triggered. - if (context.packaging_state() != - Context::PackagingState::AfterNonPackagingDecl) { - if (!context.first_non_packaging_token().is_valid()) { - context.set_first_non_packaging_token(*context.position()); - } - context.set_packaging_state( - Context::PackagingState::AfterNonPackagingDecl); - } - return false; + break; } + + // Because a non-packaging keyword was encountered, packaging is complete. + // Misplaced packaging keywords may lead to this being re-triggered. + if (context.packaging_state() != + Context::PackagingState::AfterNonPackagingDecl) { + if (!context.first_non_packaging_token().is_valid()) { + context.set_first_non_packaging_token(*context.position()); + } + context.set_packaging_state(Context::PackagingState::AfterNonPackagingDecl); + } + return false; } // Finishes an invalid declaration, skipping past its end. @@ -142,6 +146,11 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state, State::TypeAfterIntroducerAsNamedConstraint); return true; } + case Lex::TokenKind::Export: { + ApplyIntroducer(context, state, NodeKind::ExportIntroducer, + State::ExportName); + return true; + } case Lex::TokenKind::Extend: { // TODO: Treat this `extend` token as a declaration introducer HandleUnrecognizedDecl(context, state.subtree_start); diff --git a/toolchain/parse/handle_import_and_package.cpp b/toolchain/parse/handle_import_and_package.cpp index e26d34aeb2b4..92c21de2ff51 100644 --- a/toolchain/parse/handle_import_and_package.cpp +++ b/toolchain/parse/handle_import_and_package.cpp @@ -183,8 +183,8 @@ static auto VerifyInImports(Context& context, Lex::TokenIndex intro_token) context.set_packaging_state( Context::PackagingState::InImportsAfterNonPackagingDecl); CARBON_DIAGNOSTIC(ImportTooLate, Error, - "`import` and `export` directives must come after the " - "`package` directive (if present) and before any other " + "`import` directives must come after the `package` " + "directive (if present) and before any other " "entities in the file."); CARBON_DIAGNOSTIC(FirstDecl, Note, "First declaration is here."); context.emitter() @@ -225,11 +225,15 @@ static auto HandleImportHelper(Context& context, } } -auto HandleExport(Context& context) -> void { +auto HandleImportAsRegular(Context& context) -> void { auto state = context.PopState(); - context.ConsumeChecked(Lex::TokenKind::Export); + HandleImportHelper(context, state, /*export_token=*/Lex::TokenIndex::Invalid); +} +// Diagnoses if `export` is used in an `impl` file. +static auto RestrictExportToApi(Context& context, + Context::StateStackEntry& state) -> void { // Error for both Main//default and every implementation file. auto packaging = context.tree().packaging_directive(); if (!packaging || packaging->api_or_impl == Tree::ApiOrImpl::Impl) { @@ -238,21 +242,27 @@ auto HandleExport(Context& context) -> void { context.emitter().Emit(state.token, ExportFromImpl); state.has_error = true; } - - if (context.PositionIs(Lex::TokenKind::Import)) { - HandleImportHelper(context, state, state.token); - } else { - if (!VerifyInImports(context, state.token)) { - state.has_error = true; - } - context.AddLeafNode(NodeKind::ExportIntroducer, state.token, - state.has_error); - context.PushState(state, State::ExportFinish); - context.PushState(State::DeclNameAndParamsAsNone, state.token); - } } -auto HandleExportFinish(Context& context) -> void { +auto HandleImportAsExport(Context& context) -> void { + auto state = context.PopState(); + + context.ConsumeChecked(Lex::TokenKind::Export); + RestrictExportToApi(context, state); + + HandleImportHelper(context, state, state.token); +} + +auto HandleExportName(Context& context) -> void { + auto state = context.PopState(); + + RestrictExportToApi(context, state); + + context.PushState(state, State::ExportNameFinish); + context.PushState(State::DeclNameAndParamsAsNone, state.token); +} + +auto HandleExportNameFinish(Context& context) -> void { auto state = context.PopState(); context.AddNodeExpectingDeclSemi(state, NodeKind::ExportDirective, @@ -260,12 +270,6 @@ auto HandleExportFinish(Context& context) -> void { /*is_def_allowed=*/false); } -auto HandleImport(Context& context) -> void { - auto state = context.PopState(); - - HandleImportHelper(context, state, /*export_token=*/Lex::TokenIndex::Invalid); -} - // Handles common logic for `package` and `library`. static auto HandlePackageAndLibraryDirectives(Context& context, Lex::TokenKind intro_token_kind, diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index e2e93050682f..03aa6f97276f 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -223,7 +223,8 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, Library) // _external_: IdentifierName or QualifiedName // ExportDirective CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExportIntroducer, 0, Export) -CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExportDirective, 2, CARBON_IF_VALID(Semi)) +CARBON_PARSE_NODE_KIND_BRACKET(ExportDirective, ExportIntroducer, + CARBON_IF_VALID(Semi)) // `namespace`: // NamespaceStart diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index 8c172555b92c..d4697d3efd0c 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -334,6 +334,11 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit) // 1. TypeAfterIntroducerAsNamedConstraint // 2. DeclScopeLoop // +// export ... +// ^~~~~~ +// 1. ExportName +// 2. DeclScopeLoop +// // fn ... // ^~ // 1. FunctionIntroducer @@ -670,24 +675,20 @@ CARBON_PARSE_STATE(FunctionSignatureFinish) // (state done) CARBON_PARSE_STATE(FunctionDefinitionFinish) -// Handles `export`. -// -// export import library "libname"; -// ^~~~~~ -// 1. Import +// Handles `export `. // // export Name; -// ^~~~~~ +// ^ // 1. DeclNameAndParamsAsNone // 2. ExportFinish -CARBON_PARSE_STATE(Export) +CARBON_PARSE_STATE(ExportName) -// Finishes an `export`. +// Finishes an `export `. // // export Name; // ^ // (state done) -CARBON_PARSE_STATE(ExportFinish) +CARBON_PARSE_STATE(ExportNameFinish) // Handles `import`. // @@ -695,10 +696,10 @@ CARBON_PARSE_STATE(ExportFinish) // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // import ??? ; // ^~~~~~~~~~~~ -// export import library "libname"; -// ^~~~~~~~~~~~~~~~~~~~~~~~~ +// export import library "libname" ; +// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // (state done) -CARBON_PARSE_STATE(Import) +CARBON_PARSE_STATE_VARIANTS2(Import, Regular, Export) // Handles `library` in directive form. // diff --git a/toolchain/parse/testdata/packages/export.carbon b/toolchain/parse/testdata/packages/export.carbon index 09c66a3d5eca..0f1b73c21749 100644 --- a/toolchain/parse/testdata/packages/export.carbon +++ b/toolchain/parse/testdata/packages/export.carbon @@ -4,6 +4,10 @@ // // AUTOUPDATE +// --- lib.carbon + +library "lib" api; + // --- name.carbon package Pkg api; @@ -86,20 +90,28 @@ package Pkg api; // CHECK:STDERR: export .Bar; -// --- fail_after_decl.carbon +// --- after_decl.carbon package Pkg api; class C; -// CHECK:STDERR: fail_after_decl.carbon:[[@LINE+7]]:1: ERROR: `import` and `export` directives must come after the `package` directive (if present) and before any other entities in the file. +export Foo; + +// --- fail_before_import.carbon + +package Pkg api; + +export Foo; + +// CHECK:STDERR: fail_before_import.carbon:[[@LINE+7]]:1: ERROR: `import` directives must come after the `package` directive (if present) and before any other entities in the file. +// CHECK:STDERR: import library "lib"; +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: fail_before_import.carbon:[[@LINE-5]]:1: First declaration is here. // CHECK:STDERR: export Foo; // CHECK:STDERR: ^~~~~~ -// CHECK:STDERR: fail_after_decl.carbon:[[@LINE-5]]:1: First declaration is here. -// CHECK:STDERR: class C; -// CHECK:STDERR: ^~~~~ // CHECK:STDERR: -export Foo; +import library "lib"; // --- fail_in_default_library.carbon @@ -118,6 +130,15 @@ package Pkg impl; // CHECK:STDERR: ^~~~~~ export Foo; +// CHECK:STDOUT: - filename: lib.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"lib"'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] // CHECK:STDOUT: - filename: name.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, @@ -230,7 +251,7 @@ export Foo; // CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDOUT: - filename: fail_after_decl.carbon +// CHECK:STDOUT: - filename: after_decl.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, @@ -240,15 +261,29 @@ export Foo; // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, // CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 3}, -// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export', has_error: yes}, +// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, // CHECK:STDOUT: {kind: 'IdentifierName', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: fail_before_import.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Pkg'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] // CHECK:STDOUT: - filename: fail_in_default_library.carbon // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, -// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export', has_error: yes}, +// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, // CHECK:STDOUT: {kind: 'IdentifierName', text: 'Foo'}, // CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, @@ -260,7 +295,7 @@ export Foo; // CHECK:STDOUT: {kind: 'PackageName', text: 'Pkg'}, // CHECK:STDOUT: {kind: 'PackageImpl', text: 'impl'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, -// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export', has_error: yes}, +// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'}, // CHECK:STDOUT: {kind: 'IdentifierName', text: 'Foo'}, // CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/import/export.carbon b/toolchain/parse/testdata/packages/import/export.carbon index 49f4ff28f8fe..0e24965f24fa 100644 --- a/toolchain/parse/testdata/packages/import/export.carbon +++ b/toolchain/parse/testdata/packages/import/export.carbon @@ -34,7 +34,7 @@ export import library "a"; class C; -// CHECK:STDERR: fail_order.carbon:[[@LINE+7]]:8: ERROR: `import` and `export` directives must come after the `package` directive (if present) and before any other entities in the file. +// CHECK:STDERR: fail_order.carbon:[[@LINE+7]]:8: ERROR: `import` directives must come after the `package` directive (if present) and before any other entities in the file. // CHECK:STDERR: export import library "b"; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_order.carbon:[[@LINE-5]]:1: First declaration is here. diff --git a/toolchain/parse/testdata/packages/import/fail_after_decl.carbon b/toolchain/parse/testdata/packages/import/fail_after_decl.carbon index 977da44f6768..02d98b5d68ea 100644 --- a/toolchain/parse/testdata/packages/import/fail_after_decl.carbon +++ b/toolchain/parse/testdata/packages/import/fail_after_decl.carbon @@ -6,7 +6,7 @@ fn A(); -// CHECK:STDERR: fail_after_decl.carbon:[[@LINE+6]]:1: ERROR: `import` and `export` directives must come after the `package` directive (if present) and before any other entities in the file. +// CHECK:STDERR: fail_after_decl.carbon:[[@LINE+6]]:1: ERROR: `import` directives must come after the `package` directive (if present) and before any other entities in the file. // CHECK:STDERR: import B; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_after_decl.carbon:[[@LINE-5]]:1: First declaration is here. diff --git a/toolchain/parse/testdata/packages/import/fail_after_decl_repeated.carbon b/toolchain/parse/testdata/packages/import/fail_after_decl_repeated.carbon index 9a6588c89130..58d77b6486b5 100644 --- a/toolchain/parse/testdata/packages/import/fail_after_decl_repeated.carbon +++ b/toolchain/parse/testdata/packages/import/fail_after_decl_repeated.carbon @@ -6,7 +6,7 @@ fn A(); -// CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE+7]]:1: ERROR: `import` and `export` directives must come after the `package` directive (if present) and before any other entities in the file. +// CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE+7]]:1: ERROR: `import` directives must come after the `package` directive (if present) and before any other entities in the file. // CHECK:STDERR: import B; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE-5]]:1: First declaration is here. @@ -28,7 +28,7 @@ package D; fn E(); -// CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE+6]]:1: ERROR: `import` and `export` directives must come after the `package` directive (if present) and before any other entities in the file. +// CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE+6]]:1: ERROR: `import` directives must come after the `package` directive (if present) and before any other entities in the file. // CHECK:STDERR: import F; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_after_decl_repeated.carbon:[[@LINE-27]]:1: First declaration is here. diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 1bdfdf794cbe..c94b3a685b39 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -208,6 +208,7 @@ struct ExportDirective { NodeKind::ExportDirective.Define(NodeCategory::Decl); ExportIntroducerId introducer; + llvm::SmallVector modifiers; AnyNameComponentId name; };