Add export keyword handling. (#3944)

This provides `export import` logic in lex, parse, and check; `export
name` logic is only in lex and parse, not check.

I think with `export name` I'm going to need to modify import_ref and
some consolidation logic, whereas `export import` seems feasible to keep
as primarily import logic. Given the implementations were looking like
they'd diverge more substantially, I thought it'd be helpful to cut the
PR here.
This commit is contained in:
Jon Ross-Perkins
2024-05-10 22:54:06 +00:00
committed by GitHub
parent c7e4cb2c76
commit a16842ab37
21 changed files with 1823 additions and 81 deletions
+82 -25
View File
@@ -200,6 +200,82 @@ struct UnitInfo {
UnitInfo* api_for_impl = nullptr;
};
// Imports the current package.
static auto ImportCurrentPackage(Context& context, UnitInfo& unit_info,
int total_ir_count,
SemIR::InstId package_inst_id,
SemIR::TypeId namespace_type_id) -> void {
// Add imports from the current package.
auto self_import = unit_info.package_imports_map.find(IdentifierId::Invalid);
if (self_import == unit_info.package_imports_map.end()) {
// Push the scope; there are no names to add.
context.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package);
return;
}
// Track whether an IR was imported in full, including `export import`. This
// distinguishes from IRs that are indirectly added without all names being
// exported to this IR.
llvm::SmallVector<bool> imported_irs(total_ir_count, false);
if (self_import->second.has_load_error) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
}
for (const auto& import : self_import->second.imports) {
const auto& import_sem_ir = **import.unit_info->unit->sem_ir;
auto& imported_ir = imported_irs[import_sem_ir.check_ir_id().index];
if (!imported_ir) {
imported_ir = true;
// Import the IR and its exported imports.
ImportLibraryFromCurrentPackage(context, namespace_type_id,
import.names.node_id, import_sem_ir,
import.names.is_export);
for (const auto& indirect_ir : import_sem_ir.import_irs().array_ref()) {
if (indirect_ir.is_export) {
auto& imported_indirect_ir =
imported_irs[indirect_ir.sem_ir->check_ir_id().index];
if (!imported_indirect_ir) {
imported_indirect_ir = true;
ImportLibraryFromCurrentPackage(
context, namespace_type_id, import.names.node_id,
*indirect_ir.sem_ir, import.names.is_export);
} else if (import.names.is_export) {
// The indirect IR was previously indirectly imported, but it's
// found through `export import`. We need to mark it for re-export.
context.import_irs()
.Get(context.check_ir_map()[indirect_ir.sem_ir->check_ir_id()
.index])
.is_export = true;
}
}
}
} else if (import.names.is_export) {
// The IR was previously indirectly imported, but it's `export import`.
// We need to mark it -- and transitive `export import`s -- for re-export.
context.import_irs()
.Get(context.check_ir_map()[import_sem_ir.check_ir_id().index])
.is_export = true;
for (const auto& indirect_ir : import_sem_ir.import_irs().array_ref()) {
if (indirect_ir.is_export) {
context.import_irs()
.Get(context
.check_ir_map()[indirect_ir.sem_ir->check_ir_id().index])
.is_export = true;
}
}
}
}
context.scope_stack().Push(
package_inst_id, SemIR::NameScopeId::Package,
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error);
}
// Add imports to the root block.
static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info,
int total_ir_count) -> void {
@@ -248,30 +324,8 @@ static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info,
{.node_id = Parse::InvalidNodeId(), .sem_ir = nullptr});
}
// Add imports from the current package.
auto self_import = unit_info.package_imports_map.find(IdentifierId::Invalid);
if (self_import != unit_info.package_imports_map.end()) {
bool error_in_import = self_import->second.has_load_error;
for (const auto& import : self_import->second.imports) {
const auto& import_sem_ir = **import.unit_info->unit->sem_ir;
ImportLibraryFromCurrentPackage(context, namespace_type_id,
import.names.node_id, import_sem_ir);
error_in_import |= import_sem_ir.name_scopes()
.Get(SemIR::NameScopeId::Package)
.has_error;
}
// If an import of the current package caused an error for the imported
// file, it transitively affects the current file too.
if (error_in_import) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
}
context.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package,
error_in_import);
} else {
// Push the scope; there are no names to add.
context.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package);
}
ImportCurrentPackage(context, unit_info, total_ir_count, package_inst_id,
namespace_type_id);
CARBON_CHECK(context.scope_stack().PeekIndex() == ScopeIndex::Package);
for (auto& [package_id, package_imports] : unit_info.package_imports_map) {
@@ -283,7 +337,10 @@ static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info,
llvm::SmallVector<SemIR::ImportIR> import_irs;
for (auto import : package_imports.imports) {
import_irs.push_back({.node_id = import.names.node_id,
.sem_ir = &**import.unit_info->unit->sem_ir});
.sem_ir = &**import.unit_info->unit->sem_ir,
.is_export = false});
CARBON_CHECK(!import.names.is_export)
<< "Imports from other packages can't be exported.";
}
ImportLibrariesFromOtherPackage(context, namespace_type_id,
package_imports.node_id, package_id,
+20
View File
@@ -0,0 +1,20 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/check/context.h"
#include "toolchain/parse/typed_nodes.h"
namespace Carbon::Check {
auto HandleExportIntroducer(Context& /*context*/,
Parse::ExportIntroducerId /*node_id*/) -> bool {
return true;
}
auto HandleExportDirective(Context& context, Parse::ExportDirectiveId node_id)
-> bool {
return context.TODO(node_id, "ExportDirective");
}
} // namespace Carbon::Check
@@ -14,6 +14,11 @@ auto HandleImportIntroducer(Context& /*context*/,
return true;
}
auto HandleImportExport(Context& /*context*/, Parse::ImportExportId /*node_id*/)
-> bool {
return true;
}
auto HandleImportDirective(Context& /*context*/,
Parse::ImportDirectiveId /*node_id*/) -> bool {
return true;
+11 -3
View File
@@ -213,9 +213,11 @@ static auto CopyEnclosingNameScopesFromImportIR(
auto ImportLibraryFromCurrentPackage(Context& context,
SemIR::TypeId namespace_type_id,
Parse::ImportDirectiveId node_id,
const SemIR::File& import_sem_ir) -> void {
auto ir_id =
AddImportIR(context, {.node_id = node_id, .sem_ir = &import_sem_ir});
const SemIR::File& import_sem_ir,
bool is_export) -> void {
auto ir_id = AddImportIR(
context,
{.node_id = node_id, .sem_ir = &import_sem_ir, .is_export = is_export});
context.import_ir_constant_values()[ir_id.index].Set(
SemIR::InstId::PackageNamespace,
@@ -257,6 +259,12 @@ auto ImportLibraryFromCurrentPackage(Context& context,
}
}
}
// If an import of the current package caused an error for the imported
// file, it transitively affects the current file too.
if (import_sem_ir.name_scopes().Get(SemIR::NameScopeId::Package).has_error) {
context.name_scopes().Get(SemIR::NameScopeId::Package).has_error = true;
}
}
auto ImportLibrariesFromOtherPackage(Context& context,
+2 -1
View File
@@ -17,7 +17,8 @@ namespace Carbon::Check {
auto ImportLibraryFromCurrentPackage(Context& context,
SemIR::TypeId namespace_type_id,
Parse::ImportDirectiveId node_id,
const SemIR::File& import_sem_ir) -> void;
const SemIR::File& import_sem_ir,
bool is_export) -> void;
// Adds another package's imports to name lookup, with all libraries together.
// This only adds the package name to lookup, so that `package.ImportedPackage`
+7 -2
View File
@@ -44,6 +44,10 @@ auto AddImportIR(Context& context, SemIR::ImportIR import_ir)
if (!ir_id.is_valid()) {
// Note this updates check_ir_map.
ir_id = InternalAddImportIR(context, import_ir);
} else if (import_ir.is_export) {
// We're processing an `export import`. In case the IR was indirectly added
// as a non-export, mark it as an export.
context.import_irs().Get(ir_id).is_export = true;
}
return ir_id;
}
@@ -246,8 +250,9 @@ class ImportRefResolver {
cursor_ir_id = context_.check_ir_map()[cursor_ir->check_ir_id().index];
if (!cursor_ir_id.is_valid()) {
// TODO: Should we figure out a location to assign here?
cursor_ir_id = AddImportIR(
context_, {.node_id = Parse::NodeId::Invalid, .sem_ir = cursor_ir});
cursor_ir_id = AddImportIR(context_, {.node_id = Parse::NodeId::Invalid,
.sem_ir = cursor_ir,
.is_export = false});
}
cursor_inst_id = ir_inst.inst_id;
@@ -0,0 +1,726 @@
// 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
// ============================================================================
// Setup files
// ============================================================================
// --- base.carbon
library "base" api;
class C {
var x: ();
};
// --- export.carbon
library "export" api;
export import library "base";
// --- export_copy.carbon
library "export_copy" api;
export import library "base";
// --- non_export.carbon
library "non_export" api;
import library "export";
// --- export_export.carbon
library "export_export" api;
export import library "export";
// --- import_then_export.carbon
library "import_then_export" api;
import library "base";
export import library "export";
// --- export_in_impl.carbon
// This is just providing an API for the implicit import.
library "export_in_impl" api;
// ============================================================================
// Test files
// ============================================================================
// --- use_export.carbon
library "use_export" api;
import library "export";
var c: C = {.x = ()};
// --- fail_export_in_impl.impl.carbon
library "export_in_impl" impl;
// CHECK:STDERR: fail_export_in_impl.impl.carbon:[[@LINE+4]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export import library "base";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
export import library "base";
// Note the import still occurs.
var c: C = {.x = ()};
// --- export_export.impl.carbon
library "export_export" impl;
var c: C = {.x = ()};
// --- use_export_export.carbon
library "use_export_export" api;
import library "export_export";
var c: C = {.x = ()};
// --- use_import_then_export.carbon
library "use_import_then_export" api;
import library "import_then_export";
var c: C = {.x = ()};
// --- use_import_when_export.carbon
library "use_import_when_export" api;
export import library "base";
var c: C = {.x = ()};
// --- use_base_and_export.carbon
library "use_base_and_export" api;
import library "base";
import library "export";
var c: C = {.x = ()};
// --- use_export_and_base.carbon
library "import_both_reversed" api;
import library "export";
import library "base";
var c: C = {.x = ()};
// --- use_export_copy.carbon
library "use_export_copy" api;
import library "export";
import library "export_copy";
var c: C = {.x = ()};
// --- fail_use_non_export.carbon
library "fail_use_non_export" api;
import library "non_export";
// CHECK:STDERR: fail_use_non_export.carbon:[[@LINE+3]]:15: ERROR: Name `C` not found.
// CHECK:STDERR: alias Local = C;
// CHECK:STDERR: ^
alias Local = C;
// --- use_non_export_then_base.carbon
library "use_non_export_then_base" api;
import library "non_export";
export import library "base";
var c: C = {.x = ()};
// --- indirect_use_non_export_then_base.carbon
library "indirect_use_non_export_then_base" api;
import library "use_non_export_then_base";
var indirect_c: C = {.x = ()};
// CHECK:STDOUT: --- base.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 = unbound_element_type C, () [template]
// CHECK:STDOUT: %.3: type = struct_type {.x: ()} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %.loc5_11.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc5_11.2: type = converted %.loc5_11.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: %.loc5_8: <unbound element of class C> = field_decl x, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .x = %.loc5_8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_copy.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- non_export.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir2, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_export.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir2, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- import_then_export.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref = import_ref ir1, inst+1, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_in_impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_export.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_20.1: {.x: ()} = struct_literal (%.loc6_19.1)
// CHECK:STDOUT: %.loc6_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_19.2: init () = tuple_init () to %.loc6_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.3: init () = converted %.loc6_19.1, %.loc6_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.4: init C = class_init (%.loc6_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_21: init C = converted %.loc6_20.1, %.loc6_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_export_in_impl.impl.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// 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+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc11_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc11_20.1: {.x: ()} = struct_literal (%.loc11_19.1)
// CHECK:STDOUT: %.loc11_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc11_19.2: init () = tuple_init () to %.loc11_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc11_20.3: init () = converted %.loc11_19.1, %.loc11_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc11_20.4: init C = class_init (%.loc11_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc11_21: init C = converted %.loc11_20.1, %.loc11_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc11_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_export.impl.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc4_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc4_20.1: {.x: ()} = struct_literal (%.loc4_19.1)
// CHECK:STDOUT: %.loc4_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc4_19.2: init () = tuple_init () to %.loc4_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc4_20.3: init () = converted %.loc4_19.1, %.loc4_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc4_20.4: init C = class_init (%.loc4_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc4_21: init C = converted %.loc4_20.1, %.loc4_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc4_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_export_export.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir3, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir3, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_20.1: {.x: ()} = struct_literal (%.loc6_19.1)
// CHECK:STDOUT: %.loc6_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_19.2: init () = tuple_init () to %.loc6_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.3: init () = converted %.loc6_19.1, %.loc6_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.4: init C = class_init (%.loc6_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_21: init C = converted %.loc6_20.1, %.loc6_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_import_then_export.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_20.1: {.x: ()} = struct_literal (%.loc6_19.1)
// CHECK:STDOUT: %.loc6_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_19.2: init () = tuple_init () to %.loc6_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.3: init () = converted %.loc6_19.1, %.loc6_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.4: init C = class_init (%.loc6_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_21: init C = converted %.loc6_20.1, %.loc6_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_import_when_export.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// 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+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_20.1: {.x: ()} = struct_literal (%.loc6_19.1)
// CHECK:STDOUT: %.loc6_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc6_19.2: init () = tuple_init () to %.loc6_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.3: init () = converted %.loc6_19.1, %.loc6_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_20.4: init C = class_init (%.loc6_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_21: init C = converted %.loc6_20.1, %.loc6_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc6_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_base_and_export.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// 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+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_export_and_base.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_export_copy.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_use_non_export.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Local = %Local
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %Local: <error> = bind_alias Local, <error> [template = <error>]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_non_export_then_base.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.2
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- indirect_use_non_export_then_base.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .c = %import_ref.1
// CHECK:STDOUT: .C = %import_ref.2
// CHECK:STDOUT: .indirect_c = %indirect_c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+13, unloaded
// CHECK:STDOUT: %import_ref.2: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.4 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.2 [template = constants.%C]
// CHECK:STDOUT: %indirect_c.var: ref C = var indirect_c
// CHECK:STDOUT: %indirect_c: ref C = bind_name indirect_c, %indirect_c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .x = file.%import_ref.3
// CHECK:STDOUT: .Self = file.%import_ref.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6_28.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc6_29.1: {.x: ()} = struct_literal (%.loc6_28.1)
// CHECK:STDOUT: %.loc6_29.2: ref () = class_element_access file.%indirect_c.var, element0
// CHECK:STDOUT: %.loc6_28.2: init () = tuple_init () to %.loc6_29.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_29.3: init () = converted %.loc6_28.1, %.loc6_28.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc6_29.4: init C = class_init (%.loc6_29.3), file.%indirect_c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc6_30: init C = converted %.loc6_29.1, %.loc6_29.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%indirect_c.var, %.loc6_30
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,385 @@
// 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
// ============================================================================
// Setup files
// ============================================================================
// --- class.carbon
library "class" api;
class C {
var x: ();
};
namespace NS;
class NS.NSC {
var x: ();
};
// --- fail_todo_export_class.carbon
library "export_class" api;
import library "class";
// CHECK:STDERR: fail_todo_export_class.carbon:[[@LINE+4]]:1: ERROR: Semantics TODO: `ExportDirective`.
// CHECK:STDERR: export C;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
export C;
// --- non_export_class.carbon
library "non_export_class" api;
import library "export_class";
// --- fail_todo_export_export_class.carbon
library "export_export_class" api;
import library "export_class";
// CHECK:STDERR: fail_todo_export_export_class.carbon:[[@LINE+4]]:1: ERROR: Semantics TODO: `ExportDirective`.
// CHECK:STDERR: export C;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
export C;
// --- export_in_impl.carbon
// This is just providing an API for the implicit import.
library "export_in_impl" api;
// ============================================================================
// Test files
// ============================================================================
// --- fail_todo_use_export_class.carbon
library "use_export_class" api;
import library "export_class";
// CHECK:STDERR: fail_todo_use_export_class.carbon:[[@LINE+4]]:8: ERROR: Name `C` not found.
// CHECK:STDERR: var c: C = {.x = ()};
// CHECK:STDERR: ^
// CHECK:STDERR:
var c: C = {.x = ()};
// --- fail_todo_export_in_impl.impl.carbon
library "export_in_impl" impl;
import library "class";
// CHECK:STDERR: fail_todo_export_in_impl.impl.carbon:[[@LINE+8]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export C;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_export_in_impl.impl.carbon:[[@LINE+4]]:1: ERROR: Semantics TODO: `ExportDirective`.
// CHECK:STDERR: export C;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
export C;
// --- fail_todo_export_export_class.impl.carbon
library "export_export_class" impl;
// CHECK:STDERR: fail_todo_export_export_class.impl.carbon:[[@LINE+4]]:8: ERROR: Name `C` not found.
// CHECK:STDERR: var c: C = {.x = ()};
// CHECK:STDERR: ^
// CHECK:STDERR:
var c: C = {.x = ()};
// --- fail_todo_use_export_export_class.carbon
library "use_export_export_class" api;
import library "export_export_class";
// CHECK:STDERR: fail_todo_use_export_export_class.carbon:[[@LINE+4]]:8: ERROR: Name `C` not found.
// CHECK:STDERR: var c: C = {.x = ()};
// CHECK:STDERR: ^
// CHECK:STDERR:
var c: C = {.x = ()};
// --- import_both.carbon
library "import_both" api;
import library "class";
import library "export_class";
var c: C = {.x = ()};
// --- import_both_reversed.carbon
library "import_both_reversed" api;
import library "export_class";
import library "class";
var c: C = {.x = ()};
// --- fail_use_non_export_class.carbon
library "fail_use_non_export_class" api;
import library "non_export_class";
// CHECK:STDERR: fail_use_non_export_class.carbon:[[@LINE+3]]:15: ERROR: Name `C` not found.
// CHECK:STDERR: alias Local = C;
// CHECK:STDERR: ^
alias Local = C;
// CHECK:STDOUT: --- class.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 = unbound_element_type C, () [template]
// CHECK:STDOUT: %.3: type = struct_type {.x: ()} [template]
// CHECK:STDOUT: %NSC: type = class_type @NSC [template]
// CHECK:STDOUT: %.4: type = unbound_element_type NSC, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .NS = %NS
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %NS: <namespace> = namespace [template] {
// CHECK:STDOUT: .NSC = %NSC.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %NSC.decl: type = class_decl @NSC [template = constants.%NSC] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %.loc5_11.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc5_11.2: type = converted %.loc5_11.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: %.loc5_8: <unbound element of class C> = field_decl x, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .x = %.loc5_8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @NSC {
// CHECK:STDOUT: %.loc10_11.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc10_11.2: type = converted %.loc10_11.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: %.loc10_8: <unbound element of class NSC> = field_decl x, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%NSC
// CHECK:STDOUT: .x = %.loc10_8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- non_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_export_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- export_in_impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// 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> = namespace [template] {
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc10_19: () = tuple_literal ()
// CHECK:STDOUT: %.loc10_20: {.x: ()} = struct_literal (%.loc10_19)
// CHECK:STDOUT: assign file.%c.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_export_in_impl.impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_export_export_class.impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// 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> = namespace [template] {
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc8_19: () = tuple_literal ()
// CHECK:STDOUT: %.loc8_20: {.x: ()} = struct_literal (%.loc8_19)
// CHECK:STDOUT: assign file.%c.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_use_export_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// 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> = namespace [template] {
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc10_19: () = tuple_literal ()
// CHECK:STDOUT: %.loc10_20: {.x: ()} = struct_literal (%.loc10_19)
// CHECK:STDOUT: assign file.%c.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- import_both.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .NS = %NS
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2: <namespace> = import_ref ir1, inst+11, loaded
// CHECK:STDOUT: %NS: <namespace> = 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.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- import_both_reversed.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: %.3: type = ptr_type {.x: ()} [template]
// CHECK:STDOUT: %tuple: () = tuple_value () [template]
// CHECK:STDOUT: %struct: C = struct_value (%tuple) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .NS = %NS
// CHECK:STDOUT: .c = %c
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+1, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref.2: <namespace> = import_ref ir2, inst+11, loaded
// CHECK:STDOUT: %NS: <namespace> = namespace %import_ref.2, [template] {
// CHECK:STDOUT: .NSC = %import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+12, unloaded
// CHECK:STDOUT: %import_ref.4 = import_ref ir2, inst+7, unloaded
// CHECK:STDOUT: %import_ref.5 = import_ref ir2, inst+2, unloaded
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C]
// CHECK:STDOUT: %c.var: ref C = var c
// CHECK:STDOUT: %c: ref C = bind_name c, %c.var
// 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:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_19.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc7_20.1: {.x: ()} = struct_literal (%.loc7_19.1)
// CHECK:STDOUT: %.loc7_20.2: ref () = class_element_access file.%c.var, element0
// CHECK:STDOUT: %.loc7_19.2: init () = tuple_init () to %.loc7_20.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.3: init () = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%tuple]
// CHECK:STDOUT: %.loc7_20.4: init C = class_init (%.loc7_20.3), file.%c.var [template = constants.%struct]
// CHECK:STDOUT: %.loc7_21: init C = converted %.loc7_20.1, %.loc7_20.4 [template = constants.%struct]
// CHECK:STDOUT: assign file.%c.var, %.loc7_21
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_use_non_export_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Local = %Local
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.ref: <error> = name_ref C, <error> [template = <error>]
// CHECK:STDOUT: %Local: <error> = bind_alias Local, <error> [template = <error>]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -99,6 +99,7 @@ CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName)
CARBON_DIAGNOSTIC_KIND(ExpectedLibraryNameOrDefault)
CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword)
CARBON_DIAGNOSTIC_KIND(ExpectedApiOrImpl)
CARBON_DIAGNOSTIC_KIND(ExportImportPackage)
// For-specific diagnostics.
CARBON_DIAGNOSTIC_KIND(ExpectedIn)
@@ -148,6 +149,7 @@ CARBON_DIAGNOSTIC_KIND(ImportSelf)
CARBON_DIAGNOSTIC_KIND(ExplicitImportApi)
CARBON_DIAGNOSTIC_KIND(RepeatedImport)
CARBON_DIAGNOSTIC_KIND(FirstImported)
CARBON_DIAGNOSTIC_KIND(ExportFromImpl)
// Merge-related redeclaration checking.
CARBON_DIAGNOSTIC_KIND(RedeclPrevDecl)
+1
View File
@@ -159,6 +159,7 @@ CARBON_KEYWORD_TOKEN(Continue, "continue")
CARBON_KEYWORD_TOKEN(Default, "default")
CARBON_KEYWORD_TOKEN(Destructor, "destructor")
CARBON_KEYWORD_TOKEN(Else, "else")
CARBON_KEYWORD_TOKEN(Export, "export")
CARBON_KEYWORD_TOKEN(Extend, "extend")
CARBON_KEYWORD_TOKEN(Extern, "extern")
CARBON_KEYWORD_TOKEN(False, "false")
+11 -8
View File
@@ -19,7 +19,11 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool {
context.PopAndDiscardState();
return true;
}
// `import`, `library`, and `package` manage their packaging state.
// Packaging-related keywords manage their packaging state.
case Lex::TokenKind::Export: {
context.PushState(State::Export);
return true;
}
case Lex::TokenKind::Import: {
context.PushState(State::Import);
return true;
@@ -32,7 +36,7 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool {
context.PushState(State::Package);
return true;
}
default: {
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() !=
@@ -44,7 +48,6 @@ static auto TryHandleEndOrPackagingDecl(Context& context) -> bool {
Context::PackagingState::AfterNonPackagingDecl);
}
return false;
}
}
}
@@ -124,6 +127,11 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
HandleBaseAsDecl(context, state);
return true;
}
case Lex::TokenKind::Choice: {
ApplyIntroducer(context, state, NodeKind::ChoiceIntroducer,
State::ChoiceIntroducer);
return true;
}
case Lex::TokenKind::Class: {
ApplyIntroducer(context, state, NodeKind::ClassIntroducer,
State::TypeAfterIntroducerAsClass);
@@ -168,11 +176,6 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
State::VarAsDecl);
return true;
}
case Lex::TokenKind::Choice: {
ApplyIntroducer(context, state, NodeKind::ChoiceIntroducer,
State::ChoiceIntroducer);
return true;
}
case Lex::TokenKind::Semi: {
if (saw_modifier) {
+103 -36
View File
@@ -73,14 +73,23 @@ static auto HandleApiOrImpl(Context& context)
// Handles everything after the directive's introducer.
static auto HandleDirectiveContent(Context& context,
Context::StateStackEntry state,
NodeKind directive,
NodeKind directive, bool is_export,
llvm::function_ref<void()> on_parse_error)
-> void {
Tree::PackagingNames names{
.node_id = ImportDirectiveId(NodeId(state.subtree_start))};
.node_id = ImportDirectiveId(NodeId(state.subtree_start)),
.is_export = is_export};
if (directive != NodeKind::LibraryDirective) {
if (auto package_name_token =
context.ConsumeIf(Lex::TokenKind::Identifier)) {
if (names.is_export) {
names.is_export = false;
state.has_error = true;
CARBON_DIAGNOSTIC(ExportImportPackage, Error,
"`export` cannot be used when importing a package.");
context.emitter().Emit(*package_name_token, ExportImportPackage);
}
names.package_id = context.tokens().GetIdentifier(*package_name_token);
context.AddLeafNode(NodeKind::PackageName, *package_name_token);
} else if (directive == NodeKind::PackageDirective ||
@@ -157,47 +166,104 @@ static auto HandleDirectiveContent(Context& context,
}
}
auto HandleImport(Context& context) -> void {
auto state = context.PopState();
// Returns true if currently in a valid state for imports, false otherwise. May
// update the packaging state respectively.
static auto VerifyInImports(Context& context, Lex::TokenIndex intro_token)
-> bool {
switch (context.packaging_state()) {
case Context::PackagingState::FileStart:
// `package` is no longer allowed, but `import` may repeat.
context.set_packaging_state(Context::PackagingState::InImports);
return true;
case Context::PackagingState::InImports:
return true;
case Context::PackagingState::AfterNonPackagingDecl: {
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 "
"entities in the file.");
CARBON_DIAGNOSTIC(FirstDecl, Note, "First declaration is here.");
context.emitter()
.Build(intro_token, ImportTooLate)
.Note(context.first_non_packaging_token(), FirstDecl)
.Emit();
return false;
}
case Context::PackagingState::InImportsAfterNonPackagingDecl:
// There is a sequential block of misplaced `import` statements, which can
// occur if a declaration is added above `import`s. Avoid duplicate
// warnings.
return false;
}
}
// Common logic for both `import` and `export import`, distinguished by whether
// `export_token` is valid.
static auto HandleImportHelper(Context& context,
const Context::StateStackEntry& state,
Lex::TokenIndex export_token) -> void {
auto directive = NodeKind::ImportDirective;
auto on_parse_error = [&] { OnParseError(context, state, directive); };
auto intro_token = context.ConsumeChecked(Lex::TokenKind::Import);
context.AddLeafNode(NodeKind::ImportIntroducer, intro_token);
switch (context.packaging_state()) {
case Context::PackagingState::FileStart:
// `package` is no longer allowed, but `import` may repeat.
context.set_packaging_state(Context::PackagingState::InImports);
[[fallthrough]];
case Context::PackagingState::InImports:
HandleDirectiveContent(context, state, directive, on_parse_error);
break;
case Context::PackagingState::AfterNonPackagingDecl: {
context.set_packaging_state(
Context::PackagingState::InImportsAfterNonPackagingDecl);
CARBON_DIAGNOSTIC(
ImportTooLate, Error,
"`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()
.Build(intro_token, ImportTooLate)
.Note(context.first_non_packaging_token(), FirstDecl)
.Emit();
on_parse_error();
break;
}
case Context::PackagingState::InImportsAfterNonPackagingDecl:
// There is a sequential block of misplaced `import` statements, which can
// occur if a declaration is added above `import`s. Avoid duplicate
// warnings.
on_parse_error();
break;
if (export_token.is_valid()) {
context.AddLeafNode(NodeKind::ImportExport, export_token);
}
if (VerifyInImports(context, intro_token)) {
HandleDirectiveContent(context, state, directive, export_token.is_valid(),
on_parse_error);
} else {
on_parse_error();
}
}
auto HandleExport(Context& context) -> void {
auto state = context.PopState();
context.ConsumeChecked(Lex::TokenKind::Export);
// Error for both Main//default and every implementation file.
auto packaging = context.tree().packaging_directive();
if (!packaging || packaging->api_or_impl == Tree::ApiOrImpl::Impl) {
CARBON_DIAGNOSTIC(ExportFromImpl, Error,
"`export` is only allowed in API files.");
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 state = context.PopState();
context.AddNodeExpectingDeclSemi(state, NodeKind::ExportDirective,
Lex::TokenKind::Export,
/*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`.
@@ -229,7 +295,8 @@ static auto HandlePackageAndLibraryDirectives(Context& context,
// `package`/`library` is no longer allowed, but `import` may repeat.
context.set_packaging_state(Context::PackagingState::InImports);
HandleDirectiveContent(context, state, directive, on_parse_error);
HandleDirectiveContent(context, state, directive, /*is_export=*/false,
on_parse_error);
}
auto HandlePackage(Context& context) -> void {
+10
View File
@@ -194,12 +194,15 @@ CARBON_PARSE_NODE_KIND_BRACKET(PackageDirective, PackageIntroducer,
// `import`:
// ImportIntroducer
// _optional_: ImportExport
// _optional_ _external_: PackageName
// _optional_ _external_: LibrarySpecifier
// ImportDirective
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportIntroducer, 0, Import)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportExport, 0, Export)
CARBON_PARSE_NODE_KIND_BRACKET(ImportDirective, ImportIntroducer,
CARBON_IF_VALID(Semi))
// `library` as directive:
// LibraryIntroducer
// DefaultLibrary or _external_: LibraryName
@@ -215,6 +218,13 @@ CARBON_PARSE_NODE_KIND_BRACKET(LibraryDirective, LibraryIntroducer,
// LibrarySpecifier
CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, Library)
// `export`:
// ExportIntroducer
// _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))
// `namespace`:
// NamespaceStart
// _repeated_ _external_: modifier
+21
View File
@@ -670,12 +670,33 @@ CARBON_PARSE_STATE(FunctionSignatureFinish)
// (state done)
CARBON_PARSE_STATE(FunctionDefinitionFinish)
// Handles `export`.
//
// export import library "libname";
// ^~~~~~
// 1. Import
//
// export Name;
// ^~~~~~
// 1. DeclNameAndParamsAsNone
// 2. ExportFinish
CARBON_PARSE_STATE(Export)
// Finishes an `export`.
//
// export Name;
// ^
// (state done)
CARBON_PARSE_STATE(ExportFinish)
// Handles `import`.
//
// import pkgname [library "libname"] ;
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// import ??? ;
// ^~~~~~~~~~~~
// export import library "libname";
// ^~~~~~~~~~~~~~~~~~~~~~~~~
// (state done)
CARBON_PARSE_STATE(Import)
+267
View File
@@ -0,0 +1,267 @@
// 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
// --- name.carbon
package Pkg api;
export Foo;
// --- qual_name.carbon
package Pkg api;
export Foo.Bar;
// --- fail_expr.carbon
package Pkg api;
// CHECK:STDERR: fail_expr.carbon:[[@LINE+4]]:8: ERROR: `export` introducer should be followed by a name.
// CHECK:STDERR: export ();
// CHECK:STDERR: ^
// CHECK:STDERR:
export ();
// --- fail_package_in_name.carbon
package Pkg api;
// CHECK:STDERR: fail_package_in_name.carbon:[[@LINE+4]]:8: ERROR: `export` introducer should be followed by a name.
// CHECK:STDERR: export package.Bar;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
export package.Bar;
// --- fail_keyword_only
package Pkg api;
// CHECK:STDERR: fail_keyword_only:[[@LINE+4]]:1: ERROR: `export` introducer should be followed by a name.
// CHECK:STDERR: export
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
export
// --- fail_no_name.carbon
package Pkg api;
// CHECK:STDERR: fail_no_name.carbon:[[@LINE+4]]:8: ERROR: `export` introducer should be followed by a name.
// CHECK:STDERR: export ;
// CHECK:STDERR: ^
// CHECK:STDERR:
export ;
// --- fail_no_semi.carbon
package Pkg api;
export Foo
// CHECK:STDERR: fail_no_semi.carbon:[[@LINE+4]]:1: ERROR: `export` declarations must end with a `;`.
// CHECK:STDERR:
// CHECK:STDERR: ^
// CHECK:STDERR:
// --- fail_incomplete_qual_name.carbon
package Pkg api;
// CHECK:STDERR: fail_incomplete_qual_name.carbon:[[@LINE+4]]:12: ERROR: Expected identifier after `.`.
// CHECK:STDERR: export Foo.;
// CHECK:STDERR: ^
// CHECK:STDERR:
export Foo.;
// --- fail_incomplete_qual_name2.carbon
package Pkg api;
// CHECK:STDERR: fail_incomplete_qual_name2.carbon:[[@LINE+4]]:8: ERROR: `export` introducer should be followed by a name.
// CHECK:STDERR: export .Bar;
// CHECK:STDERR: ^
// CHECK:STDERR:
export .Bar;
// --- fail_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.
// 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;
// --- fail_in_default_library.carbon
// CHECK:STDERR: fail_in_default_library.carbon:[[@LINE+4]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export Foo;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
export Foo;
// --- fail_in_impl.carbon
package Pkg impl;
// CHECK:STDERR: fail_in_impl.carbon:[[@LINE+3]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export Foo;
// CHECK:STDERR: ^~~~~~
export Foo;
// CHECK:STDOUT: - filename: name.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: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: qual_name.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: 'IdentifierName', text: 'Bar'},
// CHECK:STDOUT: {kind: 'QualifiedName', text: '.', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_expr.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: 'InvalidParse', text: '(', has_error: yes},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_package_in_name.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: 'InvalidParse', text: 'package', has_error: yes},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_keyword_only
// 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: 'InvalidParse', text: '', has_error: yes},
// CHECK:STDOUT: {kind: 'ExportDirective', text: 'export', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_no_name.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: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_no_semi.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: 'Foo', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_incomplete_qual_name.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: 'IdentifierName', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'QualifiedName', text: '.', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_incomplete_qual_name2.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: 'InvalidParse', text: '.', has_error: yes},
// 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: 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: '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: 'IdentifierName', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// 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: 'IdentifierName', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_in_impl.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: 'PackageImpl', text: 'impl'},
// CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export', has_error: yes},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExportDirective', text: ';', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
+147
View File
@@ -0,0 +1,147 @@
// 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
// --- fail_package.carbon
package Pkg api;
// CHECK:STDERR: fail_package.carbon:[[@LINE+4]]:15: ERROR: `export` cannot be used when importing a package.
// CHECK:STDERR: export import Bar;
// CHECK:STDERR: ^~~
// CHECK:STDERR:
export import Bar;
// --- default.carbon
package Pkg api;
export import library default;
// --- named.carbon
package Pkg api;
export import library "lib";
// --- fail_order.carbon
package Pkg api;
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: export import library "b";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_order.carbon:[[@LINE-5]]:1: First declaration is here.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
export import library "b";
// --- fail_in_default_library.carbon
// CHECK:STDERR: fail_in_default_library.carbon:[[@LINE+4]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export import library "lib";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
export import library "lib";
// --- fail_in_impl.carbon
package Pkg impl;
// CHECK:STDERR: fail_in_impl.carbon:[[@LINE+3]]:1: ERROR: `export` is only allowed in API files.
// CHECK:STDERR: export import library "lib";
// CHECK:STDERR: ^~~~~~
export import library "lib";
// CHECK:STDOUT: - filename: fail_package.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: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'PackageName', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: default.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: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'DefaultLibrary', text: 'default'},
// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: named.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: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'LibraryName', text: '"lib"'},
// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_order.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: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'LibraryName', text: '"a"'},
// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 3},
// 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: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'LibraryName', text: '"lib"'},
// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_in_impl.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: 'PackageImpl', text: 'impl'},
// CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'},
// CHECK:STDOUT: {kind: 'ImportExport', text: 'export'},
// CHECK:STDOUT: {kind: 'LibraryName', text: '"lib"'},
// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
@@ -6,7 +6,7 @@
fn A();
// 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: 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: import B;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_after_decl.carbon:[[@LINE-5]]:1: First declaration is here.
@@ -6,7 +6,7 @@
fn A();
// 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: 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: 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` 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` and `export` 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.
+3
View File
@@ -92,6 +92,9 @@ class Tree : public Printable<Tree> {
ImportDirectiveId node_id;
IdentifierId package_id = IdentifierId::Invalid;
StringLiteralValueId library_id = StringLiteralValueId::Invalid;
// Whether an import is exported. This is on the file's packaging directive
// even though it doesn't apply, for consistency in structure.
bool is_export = false;
};
// The file's packaging.
+15 -3
View File
@@ -143,8 +143,8 @@ struct QualifiedName {
IdentifierNameId rhs;
};
// Library, package, import
// ------------------------
// Library, package, import, export
// --------------------------------
// The `package` keyword in an expression.
using PackageExpr = LeafNode<NodeKind::PackageExpr, NodeCategory::Expr>;
@@ -179,11 +179,13 @@ struct PackageDirective {
// `import TheirPackage library "TheirLibrary";`
using ImportIntroducer = LeafNode<NodeKind::ImportIntroducer>;
using ImportExport = LeafNode<NodeKind::ImportExport>;
struct ImportDirective {
static constexpr auto Kind =
NodeKind::ImportDirective.Define(NodeCategory::Decl);
ImportIntroducerId introducer;
std::optional<ImportExportId> export_modifier;
std::optional<PackageNameId> name;
std::optional<LibrarySpecifierId> library;
};
@@ -199,6 +201,16 @@ struct LibraryDirective {
NodeIdOneOf<PackageApi, PackageImpl> api_or_impl;
};
// `export` as a directive.
using ExportIntroducer = LeafNode<NodeKind::ExportIntroducer>;
struct ExportDirective {
static constexpr auto Kind =
NodeKind::ExportDirective.Define(NodeCategory::Decl);
ExportIntroducerId introducer;
AnyNameComponentId name;
};
// Namespace nodes
// ---------------
@@ -210,7 +222,7 @@ struct Namespace {
NamespaceStartId introducer;
llvm::SmallVector<AnyModifierId> modifiers;
NodeIdOneOf<IdentifierName, QualifiedName> name;
AnyNameComponentId name;
};
// Pattern nodes
+2
View File
@@ -19,6 +19,8 @@ struct ImportIR : public Printable<ImportIR> {
Parse::ImportDirectiveId node_id;
// The imported IR.
const File* sem_ir;
// True if this is part of an `export import`.
bool is_export;
};
// A reference to an instruction in an imported IR. Used for diagnostics with