remove usingnamespace from the language

closes #20663
This commit is contained in:
Andrew Kelley 2025-07-07 13:36:03 -07:00
parent aa52bb8327
commit 34f64432b0
43 changed files with 29 additions and 910 deletions

View File

@ -3842,37 +3842,6 @@ void do_a_thing(struct Foo *foo) {
{#header_close#}
{#header_close#}
{#header_open|usingnamespace#}
<p>
{#syntax#}usingnamespace{#endsyntax#} is a declaration that mixes all the public
declarations of the operand, which must be a {#link|struct#}, {#link|union#}, {#link|enum#},
or {#link|opaque#}, into the namespace:
</p>
{#code|test_usingnamespace.zig#}
<p>
{#syntax#}usingnamespace{#endsyntax#} has an important use case when organizing the public
API of a file or package. For example, one might have <code class="file">c.zig</code> with all of the
{#link|C imports|Import from C Header File#}:
</p>
{#syntax_block|zig|c.zig#}
pub usingnamespace @cImport({
@cInclude("epoxy/gl.h");
@cInclude("GLFW/glfw3.h");
@cDefine("STBI_ONLY_PNG", "");
@cDefine("STBI_NO_STDIO", "");
@cInclude("stb_image.h");
});
{#end_syntax_block#}
<p>
The above example demonstrates using {#syntax#}pub{#endsyntax#} to qualify the
{#syntax#}usingnamespace{#endsyntax#} additionally makes the imported declarations
{#syntax#}pub{#endsyntax#}. This can be used to forward declarations, giving precise control
over what declarations a given file exposes.
</p>
{#header_close#}
{#header_open|comptime#}
<p>
Zig places importance on the concept of whether an expression is known at compile-time.
@ -6545,7 +6514,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
<ul>
<li>If a call to {#syntax#}@import{#endsyntax#} is analyzed, the file being imported is analyzed.</li>
<li>If a type (including a file) is analyzed, all {#syntax#}comptime{#endsyntax#}, {#syntax#}usingnamespace{#endsyntax#}, and {#syntax#}export{#endsyntax#} declarations within it are analyzed.</li>
<li>If a type (including a file) is analyzed, all {#syntax#}comptime{#endsyntax#} and {#syntax#}export{#endsyntax#} declarations within it are analyzed.</li>
<li>If a type (including a file) is analyzed, and the compilation is for a {#link|test|Zig Test#}, and the module the type is within is the root module of the compilation, then all {#syntax#}test{#endsyntax#} declarations within it are also analyzed.</li>
<li>If a reference to a named declaration (i.e. a usage of it) is analyzed, the declaration being referenced is analyzed. Declarations are order-independent, so this reference may be above or below the declaration being referenced, or even in another file entirely.</li>
</ul>
@ -7782,18 +7751,6 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}usingnamespace{#endsyntax#}</pre>
</th>
<td>
{#syntax#}usingnamespace{#endsyntax#} is a top-level declaration that imports all the public declarations of the operand,
which must be a struct, union, or enum, into the current scope.
<ul>
<li>See also {#link|usingnamespace#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}var{#endsyntax#}</pre>
@ -7863,7 +7820,6 @@ ComptimeDecl <- KEYWORD_comptime Block
Decl
<- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
/ (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl
/ KEYWORD_usingnamespace Expr SEMICOLON
FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
@ -8408,7 +8364,6 @@ KEYWORD_threadlocal <- 'threadlocal' end_of_word
KEYWORD_try <- 'try' end_of_word
KEYWORD_union <- 'union' end_of_word
KEYWORD_unreachable <- 'unreachable' end_of_word
KEYWORD_usingnamespace <- 'usingnamespace' end_of_word
KEYWORD_var <- 'var' end_of_word
KEYWORD_volatile <- 'volatile' end_of_word
KEYWORD_while <- 'while' end_of_word
@ -8424,7 +8379,7 @@ keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
/ KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
/ KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test
/ KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable
/ KEYWORD_usingnamespace / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
/ KEYWORD_var / KEYWORD_volatile / KEYWORD_while
{#end_syntax_block#}
{#header_close#}
{#header_open|Zen#}

View File

@ -1,8 +0,0 @@
test "using std namespace" {
const S = struct {
usingnamespace @import("std");
};
try S.testing.expect(true);
}
// test

View File

@ -160,12 +160,6 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void {
try walkExpression(w, decl);
},
.@"usingnamespace" => {
try w.transformations.append(.{ .delete_node = decl });
const expr = ast.nodeData(decl).node;
try walkExpression(w, expr);
},
.global_var_decl,
.local_var_decl,
.simple_var_decl,
@ -520,7 +514,6 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
.local_var_decl => unreachable,
.simple_var_decl => unreachable,
.aligned_var_decl => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.asm_output => unreachable,
.asm_input => unreachable,

View File

@ -567,7 +567,6 @@ fn struct_decl(
},
.@"comptime",
.@"usingnamespace",
=> try w.expr(&namespace.base, parent_decl, ast.nodeData(member).node),
.test_decl => try w.expr(&namespace.base, parent_decl, ast.nodeData(member).opt_token_and_node[1]),
@ -639,7 +638,6 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index)
const ast = w.file.get_ast();
switch (ast.nodeTag(node)) {
.root => unreachable, // Top-level declaration.
.@"usingnamespace" => unreachable, // Top-level declaration.
.test_decl => unreachable, // Top-level declaration.
.container_field_init => unreachable, // Top-level declaration.
.container_field_align => unreachable, // Top-level declaration.

View File

@ -137,7 +137,6 @@ pub fn fileSourceHtml(
.keyword_try,
.keyword_union,
.keyword_unreachable,
.keyword_usingnamespace,
.keyword_var,
.keyword_volatile,
.keyword_allowzero,

View File

@ -755,13 +755,6 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
return i - end_offset;
},
.@"usingnamespace" => {
const main_token: TokenIndex = tree.nodeMainToken(n);
const has_visib_token = tree.isTokenPrecededByTags(main_token, &.{.keyword_pub});
end_offset += @intFromBool(has_visib_token);
return main_token - end_offset;
},
.container_field_init,
.container_field_align,
.container_field,
@ -881,7 +874,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
while (true) switch (tree.nodeTag(n)) {
.root => return @intCast(tree.tokens.len - 1),
.@"usingnamespace",
.bool_not,
.negation,
.bit_not,
@ -3033,12 +3025,6 @@ pub const Node = struct {
///
/// The `main_token` field is the first token for the source file.
root,
/// `usingnamespace expr;`.
///
/// The `data` field is a `.node` to expr.
///
/// The `main_token` field is the `usingnamespace` token.
@"usingnamespace",
/// `test {}`,
/// `test "name" {}`,
/// `test identifier {}`.

View File

@ -442,7 +442,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
const tree = astgen.tree;
switch (tree.nodeTag(node)) {
.root => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.global_var_decl => unreachable,
.local_var_decl => unreachable,
@ -637,7 +636,6 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
switch (tree.nodeTag(node)) {
.root => unreachable, // Top-level declaration.
.@"usingnamespace" => unreachable, // Top-level declaration.
.test_decl => unreachable, // Top-level declaration.
.container_field_init => unreachable, // Top-level declaration.
.container_field_align => unreachable, // Top-level declaration.
@ -4700,69 +4698,6 @@ fn comptimeDecl(
});
}
fn usingnamespaceDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
wip_members: *WipMembers,
node: Ast.Node.Index,
) InnerError!void {
const tree = astgen.tree;
const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher;
astgen.src_hasher = std.zig.SrcHasher.init(.{});
astgen.src_hasher.update(tree.getNodeSource(node));
astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
const type_expr = tree.nodeData(node).node;
const is_pub = tree.isTokenPrecededByTags(tree.nodeMainToken(node), &.{.keyword_pub});
// Up top so the ZIR instruction index marks the start range of this
// top-level declaration.
const decl_inst = try gz.makeDeclaration(node);
wip_members.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
// This is just needed for the `setDeclaration` call.
var dummy_gz = gz.makeSubBlock(scope);
defer dummy_gz.unstack();
var usingnamespace_gz: GenZir = .{
.is_comptime = true,
.decl_node_index = node,
.decl_line = astgen.source_line,
.parent = scope,
.astgen = astgen,
.instructions = gz.instructions,
.instructions_top = gz.instructions.items.len,
};
defer usingnamespace_gz.unstack();
const decl_column = astgen.source_column;
const namespace_inst = try typeExpr(&usingnamespace_gz, &usingnamespace_gz.base, type_expr);
_ = try usingnamespace_gz.addBreak(.break_inline, decl_inst, namespace_inst);
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
try setDeclaration(decl_inst, .{
.src_hash = hash,
.src_line = usingnamespace_gz.decl_line,
.src_column = decl_column,
.kind = .@"usingnamespace",
.name = .empty,
.is_pub = is_pub,
.is_threadlocal = false,
.linkage = .normal,
.type_gz = &dummy_gz,
.align_gz = &dummy_gz,
.linksection_gz = &dummy_gz,
.addrspace_gz = &dummy_gz,
.value_gz = &usingnamespace_gz,
});
}
fn testDecl(
astgen: *AstGen,
gz: *GenZir,
@ -5932,23 +5867,6 @@ fn containerMember(
},
};
},
.@"usingnamespace" => {
const prev_decl_index = wip_members.decl_index;
astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
wip_members.decl_index = prev_decl_index;
try addFailedDeclaration(
wip_members,
gz,
.@"usingnamespace",
.empty,
member_node,
tree.isTokenPrecededByTags(tree.nodeMainToken(member_node), &.{.keyword_pub}),
);
},
};
},
.test_decl => {
const prev_decl_index = wip_members.decl_index;
// We need to have *some* decl here so that the decl count matches what's expected.
@ -10398,7 +10316,6 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
while (true) {
switch (tree.nodeTag(node)) {
.root,
.@"usingnamespace",
.test_decl,
.switch_case,
.switch_case_inline,
@ -10606,7 +10523,6 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
while (true) {
switch (tree.nodeTag(node)) {
.root,
.@"usingnamespace",
.test_decl,
.switch_case,
.switch_case_inline,
@ -10845,7 +10761,6 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
while (true) {
switch (tree.nodeTag(node)) {
.root,
.@"usingnamespace",
.test_decl,
.switch_case,
.switch_case_inline,
@ -13518,7 +13433,7 @@ fn scanContainer(
break :blk .{ .decl, ident };
},
.@"comptime", .@"usingnamespace" => {
.@"comptime" => {
decl_count += 1;
continue;
},
@ -13896,7 +13811,6 @@ const DeclarationName = union(enum) {
decltest: Ast.TokenIndex,
unnamed_test,
@"comptime",
@"usingnamespace",
};
fn addFailedDeclaration(
@ -13986,7 +13900,6 @@ fn setDeclaration(
.@"test" => .@"test",
.decltest => .decltest,
.@"comptime" => .@"comptime",
.@"usingnamespace" => if (args.is_pub) .pub_usingnamespace else .@"usingnamespace",
.@"const" => switch (args.linkage) {
.normal => if (args.is_pub) id: {
if (has_special_body) break :id .pub_const;

View File

@ -165,10 +165,6 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
}
return false;
},
.@"usingnamespace" => {
_ = try astrl.expr(tree.nodeData(node).node, block, ResultInfo.type_only);
return false;
},
.test_decl => {
_ = try astrl.expr(tree.nodeData(node).opt_token_and_node[1], block, ResultInfo.none);
return false;

View File

@ -359,16 +359,6 @@ fn parseContainerMembers(p: *Parse) Allocator.Error!Members {
}
trailing = p.tokenTag(p.tok_i - 1) == .semicolon;
},
.keyword_usingnamespace => {
const opt_node = try p.expectUsingNamespaceRecoverable();
if (opt_node) |node| {
if (field_state == .seen) {
field_state = .{ .end = node };
}
try p.scratch.append(p.gpa, node);
}
trailing = p.tokenTag(p.tok_i - 1) == .semicolon;
},
.keyword_const,
.keyword_var,
.keyword_threadlocal,
@ -496,7 +486,6 @@ fn findNextContainerMember(p: *Parse) void {
.keyword_extern,
.keyword_inline,
.keyword_noinline,
.keyword_usingnamespace,
.keyword_threadlocal,
.keyword_const,
.keyword_var,
@ -601,7 +590,6 @@ fn expectTestDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
/// Decl
/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
/// / KEYWORD_usingnamespace Expr SEMICOLON
fn expectTopLevelDecl(p: *Parse) !?Node.Index {
const extern_export_inline_token = p.nextToken();
var is_extern: bool = false;
@ -664,10 +652,7 @@ fn expectTopLevelDecl(p: *Parse) !?Node.Index {
if (expect_var_or_fn) {
return p.fail(.expected_var_decl_or_fn);
}
if (p.tokenTag(p.tok_i) != .keyword_usingnamespace) {
return p.fail(.expected_pub_item);
}
return try p.expectUsingNamespace();
return p.fail(.expected_pub_item);
}
fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
@ -680,27 +665,6 @@ fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
};
}
fn expectUsingNamespace(p: *Parse) !Node.Index {
const usingnamespace_token = p.assertToken(.keyword_usingnamespace);
const expr = try p.expectExpr();
try p.expectSemicolon(.expected_semi_after_decl, false);
return p.addNode(.{
.tag = .@"usingnamespace",
.main_token = usingnamespace_token,
.data = .{ .node = expr },
});
}
fn expectUsingNamespaceRecoverable(p: *Parse) error{OutOfMemory}!?Node.Index {
return p.expectUsingNamespace() catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextContainerMember();
return null;
},
};
}
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
fn parseFnProto(p: *Parse) !?Node.Index {
const fn_token = p.eatToken(.keyword_fn) orelse return null;

View File

@ -2675,7 +2675,6 @@ pub const Inst = struct {
@"test",
decltest,
@"comptime",
@"usingnamespace",
@"const",
@"var",
};
@ -2692,7 +2691,7 @@ pub const Inst = struct {
src_column: u32,
kind: Kind,
/// Always `.empty` for `kind` of `unnamed_test`, `.@"comptime"`, `.@"usingnamespace"`.
/// Always `.empty` for `kind` of `unnamed_test`, `.@"comptime"`
name: NullTerminatedString,
/// Always `false` for `kind` of `unnamed_test`, `.@"test"`, `.decltest`, `.@"comptime"`.
is_pub: bool,
@ -2723,9 +2722,6 @@ pub const Inst = struct {
decltest,
@"comptime",
@"usingnamespace",
pub_usingnamespace,
const_simple,
const_typed,
@"const",
@ -2762,8 +2758,6 @@ pub const Inst = struct {
return switch (id) {
.unnamed_test,
.@"comptime",
.@"usingnamespace",
.pub_usingnamespace,
=> false,
else => true,
};
@ -2788,8 +2782,6 @@ pub const Inst = struct {
.@"test",
.decltest,
.@"comptime",
.@"usingnamespace",
.pub_usingnamespace,
=> false, // these constructs are untyped
.const_simple,
.pub_const_simple,
@ -2821,8 +2813,6 @@ pub const Inst = struct {
.@"test",
.decltest,
.@"comptime",
.@"usingnamespace",
.pub_usingnamespace,
=> false, // these constructs are untyped
.const_simple,
.const_typed,
@ -2865,7 +2855,6 @@ pub const Inst = struct {
.@"test" => .@"test",
.decltest => .decltest,
.@"comptime" => .@"comptime",
.@"usingnamespace", .pub_usingnamespace => .@"usingnamespace",
.const_simple,
.const_typed,
.@"const",
@ -2899,7 +2888,6 @@ pub const Inst = struct {
pub fn isPub(id: Id) bool {
return switch (id) {
.pub_usingnamespace,
.pub_const_simple,
.pub_const_typed,
.pub_const,
@ -2935,8 +2923,7 @@ pub const Inst = struct {
pub const Name = enum(u32) {
@"comptime" = std.math.maxInt(u32),
@"usingnamespace" = std.math.maxInt(u32) - 1,
unnamed_test = std.math.maxInt(u32) - 2,
unnamed_test = std.math.maxInt(u32) - 1,
/// Other values are `NullTerminatedString` values, i.e. index into
/// `string_bytes`. If the byte referenced is 0, the decl is a named
/// test, and the actual name begins at the following byte.
@ -2944,13 +2931,13 @@ pub const Inst = struct {
pub fn isNamedTest(name: Name, zir: Zir) bool {
return switch (name) {
.@"comptime", .@"usingnamespace", .unnamed_test => false,
.@"comptime", .unnamed_test => false,
_ => zir.string_bytes[@intFromEnum(name)] == 0,
};
}
pub fn toString(name: Name, zir: Zir) ?NullTerminatedString {
switch (name) {
.@"comptime", .@"usingnamespace", .unnamed_test => return null,
.@"comptime", .unnamed_test => return null,
_ => {},
}
const idx: u32 = @intFromEnum(name);

View File

@ -100,7 +100,6 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
switch (tree.nodeTag(node)) {
.root => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.container_field_init => unreachable,
.container_field_align => unreachable,

View File

@ -3936,14 +3936,6 @@ test "zig fmt: Block after if" {
);
}
test "zig fmt: usingnamespace" {
try testCanonical(
\\usingnamespace @import("std");
\\pub usingnamespace @import("std");
\\
);
}
test "zig fmt: string identifier" {
try testCanonical(
\\const @"a b" = @"c d".@"e f";
@ -5087,17 +5079,6 @@ test "zig fmt: line comment after multiline single expr if statement with multil
);
}
test "zig fmt: respect extra newline between fn and pub usingnamespace" {
try testCanonical(
\\fn foo() void {
\\ bar();
\\}
\\
\\pub usingnamespace baz;
\\
);
}
test "zig fmt: respect extra newline between switch items" {
try testCanonical(
\\const a = switch (b) {
@ -5666,34 +5647,6 @@ test "zig fmt: canonicalize symbols (primitive types)" {
);
}
// Never unescape names spelled like keywords.
test "zig fmt: canonicalize symbols (keywords)" {
try testCanonical(
\\const @"enum" = struct {
\\ @"error": @"struct" = true,
\\ const @"struct" = bool;
\\};
\\
\\fn @"usingnamespace"(@"union": @"enum") error{@"try"}!void {
\\ var @"struct" = @"union";
\\ @"struct".@"error" = false;
\\ if (@"struct".@"error") {
\\ return @"usingnamespace"(.{ .@"error" = false });
\\ } else {
\\ return error.@"try";
\\ }
\\}
\\
\\test @"usingnamespace" {
\\ try @"usingnamespace"(.{});
\\ _ = @"return": {
\\ break :@"return" 4;
\\ };
\\}
\\
);
}
test "zig fmt: no space before newline before multiline string" {
try testCanonical(
\\const S = struct {
@ -6156,22 +6109,6 @@ test "recovery: missing semicolon" {
});
}
test "recovery: invalid container members" {
try testError(
\\usingnamespace;
\\@foo()+
\\@bar()@,
\\while (a == 2) { test "" {}}
\\test "" {
\\ a & b
\\}
, &[_]Error{
.expected_expr,
.expected_comma_after_field,
.expected_semi_after_stmt,
});
}
// TODO after https://github.com/ziglang/zig/issues/35 is implemented,
// we should be able to recover from this *at any indentation level*,
// reporting a parse error and yet also parsing all the decls even

View File

@ -262,17 +262,6 @@ fn renderMember(
return renderToken(r, tree.lastToken(decl) + 1, space); // semicolon
},
.@"usingnamespace" => {
const main_token = tree.nodeMainToken(decl);
const expr = tree.nodeData(decl).node;
if (tree.isTokenPrecededByTags(main_token, &.{.keyword_pub})) {
try renderToken(r, main_token - 1, .space); // pub
}
try renderToken(r, main_token, .space); // usingnamespace
try renderExpression(r, expr, .none);
return renderToken(r, tree.lastToken(expr) + 1, space); // ;
},
.global_var_decl,
.local_var_decl,
.simple_var_decl,
@ -877,7 +866,6 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
.local_var_decl => unreachable,
.simple_var_decl => unreachable,
.aligned_var_decl => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.asm_output => unreachable,
.asm_input => unreachable,

View File

@ -53,7 +53,6 @@ pub const Token = struct {
.{ "try", .keyword_try },
.{ "union", .keyword_union },
.{ "unreachable", .keyword_unreachable },
.{ "usingnamespace", .keyword_usingnamespace },
.{ "var", .keyword_var },
.{ "volatile", .keyword_volatile },
.{ "while", .keyword_while },
@ -180,7 +179,6 @@ pub const Token = struct {
keyword_try,
keyword_union,
keyword_unreachable,
keyword_usingnamespace,
keyword_var,
keyword_volatile,
keyword_while,
@ -305,7 +303,6 @@ pub const Token = struct {
.keyword_try => "try",
.keyword_union => "union",
.keyword_unreachable => "unreachable",
.keyword_usingnamespace => "usingnamespace",
.keyword_var => "var",
.keyword_volatile => "volatile",
.keyword_while => "while",

View File

@ -518,8 +518,6 @@ pub const Nav = struct {
namespace: NamespaceIndex,
zir_index: TrackedInst.Index,
},
/// TODO: this is a hack! If #20663 isn't accepted, let's figure out something a bit better.
is_usingnamespace: bool,
status: union(enum) {
/// This `Nav` is pending semantic analysis.
unresolved,
@ -735,7 +733,7 @@ pub const Nav = struct {
@"addrspace": std.builtin.AddressSpace,
/// Populated only if `bits.status == .type_resolved`.
is_threadlocal: bool,
is_usingnamespace: bool,
_: u1 = 0,
};
fn unpack(repr: Repr) Nav {
@ -749,7 +747,6 @@ pub const Nav = struct {
assert(repr.analysis_zir_index == .none);
break :a null;
},
.is_usingnamespace = repr.bits.is_usingnamespace,
.status = switch (repr.bits.status) {
.unresolved => .unresolved,
.type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
@ -797,7 +794,6 @@ pub const Nav = struct {
.is_const = false,
.alignment = .none,
.@"addrspace" = .generic,
.is_usingnamespace = nav.is_usingnamespace,
.is_threadlocal = false,
},
.type_resolved => |r| .{
@ -805,7 +801,6 @@ pub const Nav = struct {
.is_const = r.is_const,
.alignment = r.alignment,
.@"addrspace" = r.@"addrspace",
.is_usingnamespace = nav.is_usingnamespace,
.is_threadlocal = r.is_threadlocal,
},
.fully_resolved => |r| .{
@ -813,7 +808,6 @@ pub const Nav = struct {
.is_const = r.is_const,
.alignment = r.alignment,
.@"addrspace" = r.@"addrspace",
.is_usingnamespace = nav.is_usingnamespace,
.is_threadlocal = false,
},
},
@ -6865,8 +6859,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
{
namespace.pub_decls.deinit(gpa);
namespace.priv_decls.deinit(gpa);
namespace.pub_usingnamespace.deinit(gpa);
namespace.priv_usingnamespace.deinit(gpa);
namespace.comptime_decls.deinit(gpa);
namespace.test_decls.deinit(gpa);
}
@ -11503,7 +11495,6 @@ pub fn createNav(
.@"linksection" = opts.@"linksection",
.@"addrspace" = opts.@"addrspace",
} },
.is_usingnamespace = false,
}));
return index_unwrapped.wrap(ip);
}
@ -11518,8 +11509,6 @@ pub fn createDeclNav(
fqn: NullTerminatedString,
zir_index: TrackedInst.Index,
namespace: NamespaceIndex,
/// TODO: this is hacky! See `Nav.is_usingnamespace`.
is_usingnamespace: bool,
) Allocator.Error!Nav.Index {
const navs = ip.getLocal(tid).getMutableNavs(gpa);
@ -11538,7 +11527,6 @@ pub fn createDeclNav(
.zir_index = zir_index,
},
.status = .unresolved,
.is_usingnamespace = is_usingnamespace,
}));
return nav;

View File

@ -2860,7 +2860,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
sema.code.nullTerminatedString(str),
.no_embedded_nulls,
);
const nav = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc?
const nav = try sema.lookupIdentifier(block, decl_name);
break :capture InternPool.CaptureValue.wrap(.{ .nav_val = nav });
},
.decl_ref => |str| capture: {
@ -2870,7 +2870,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
sema.code.nullTerminatedString(str),
.no_embedded_nulls,
);
const nav = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc?
const nav = try sema.lookupIdentifier(block, decl_name);
break :capture InternPool.CaptureValue.wrap(.{ .nav_ref = nav });
},
};
@ -6925,7 +6925,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
inst_data.get(sema.code),
.no_embedded_nulls,
);
const nav_index = try sema.lookupIdentifier(block, src, decl_name);
const nav_index = try sema.lookupIdentifier(block, decl_name);
return sema.analyzeNavRef(block, src, nav_index);
}
@ -6940,16 +6940,16 @@ fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
inst_data.get(sema.code),
.no_embedded_nulls,
);
const nav = try sema.lookupIdentifier(block, src, decl_name);
const nav = try sema.lookupIdentifier(block, decl_name);
return sema.analyzeNavVal(block, src, nav);
}
fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !InternPool.Nav.Index {
fn lookupIdentifier(sema: *Sema, block: *Block, name: InternPool.NullTerminatedString) !InternPool.Nav.Index {
const pt = sema.pt;
const zcu = pt.zcu;
var namespace = block.namespace;
while (true) {
if (try sema.lookupInNamespace(block, src, namespace, name, false)) |lookup| {
if (try sema.lookupInNamespace(block, namespace, name)) |lookup| {
assert(lookup.accessible);
return lookup.nav;
}
@ -6958,15 +6958,12 @@ fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPoo
unreachable; // AstGen detects use of undeclared identifiers.
}
/// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
/// only for ones in the specified namespace.
/// This looks up a member of a specific namespace.
fn lookupInNamespace(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
namespace_index: InternPool.NamespaceIndex,
ident_name: InternPool.NullTerminatedString,
observe_usingnamespace: bool,
) CompileError!?struct {
nav: InternPool.Nav.Index,
/// If `false`, the declaration is in a different file and is not `pub`.
@ -6975,7 +6972,6 @@ fn lookupInNamespace(
} {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
try pt.ensureNamespaceUpToDate(namespace_index);
@ -6992,75 +6988,7 @@ fn lookupInNamespace(
} });
}
if (observe_usingnamespace and (namespace.pub_usingnamespace.items.len != 0 or namespace.priv_usingnamespace.items.len != 0)) {
const gpa = sema.gpa;
var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .empty;
defer checked_namespaces.deinit(gpa);
// Keep track of name conflicts for error notes.
var candidates: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty;
defer candidates.deinit(gpa);
try checked_namespaces.put(gpa, namespace, {});
var check_i: usize = 0;
while (check_i < checked_namespaces.count()) : (check_i += 1) {
const check_ns = checked_namespaces.keys()[check_i];
const Pass = enum { @"pub", priv };
for ([2]Pass{ .@"pub", .priv }) |pass| {
if (pass == .priv and src_file != check_ns.file_scope) {
continue;
}
const decls, const usingnamespaces = switch (pass) {
.@"pub" => .{ &check_ns.pub_decls, &check_ns.pub_usingnamespace },
.priv => .{ &check_ns.priv_decls, &check_ns.priv_usingnamespace },
};
if (decls.getKeyAdapted(ident_name, adapter)) |nav_index| {
try candidates.append(gpa, nav_index);
}
for (usingnamespaces.items) |sub_ns_nav| {
try sema.ensureNavResolved(block, src, sub_ns_nav, .fully);
const sub_ns_ty: Type = .fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
try checked_namespaces.put(gpa, sub_ns, {});
}
}
}
ignore_self: {
const skip_nav = switch (sema.owner.unwrap()) {
.@"comptime", .type, .func, .memoized_state => break :ignore_self,
.nav_ty, .nav_val => |nav| nav,
};
var i: usize = 0;
while (i < candidates.items.len) {
if (candidates.items[i] == skip_nav) {
_ = candidates.orderedRemove(i);
} else {
i += 1;
}
}
}
switch (candidates.items.len) {
0 => {},
1 => return .{
.nav = candidates.items[0],
.accessible = true,
},
else => return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(src, "ambiguous reference", .{});
errdefer msg.destroy(gpa);
for (candidates.items) |candidate| {
try sema.errNote(zcu.navSrcLoc(candidate), msg, "declared here", .{});
}
break :msg msg;
}),
}
} else if (namespace.pub_decls.getKeyAdapted(ident_name, adapter)) |nav_index| {
if (namespace.pub_decls.getKeyAdapted(ident_name, adapter)) |nav_index| {
return .{
.nav = nav_index,
.accessible = true,
@ -13946,7 +13874,6 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src = block.nodeOffset(inst_data.src_node);
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
@ -13955,7 +13882,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
try sema.checkNamespaceType(block, lhs_src, container_type);
const namespace = container_type.getNamespace(zcu).unwrap() orelse return .bool_false;
if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| {
if (try sema.lookupInNamespace(block, namespace, decl_name)) |lookup| {
if (lookup.accessible) {
return .bool_true;
}
@ -17736,7 +17663,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
const decls_val = try sema.typeInfoDecls(block, src, ip.loadEnumType(ty.toIntern()).namespace.toOptional());
const decls_val = try sema.typeInfoDecls(src, ip.loadEnumType(ty.toIntern()).namespace.toOptional());
const type_enum_ty = try sema.getBuiltinType(src, .@"Type.Enum");
@ -17849,7 +17776,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespaceIndex(zcu).toOptional());
const decls_val = try sema.typeInfoDecls(src, ty.getNamespaceIndex(zcu).toOptional());
const enum_tag_ty_val = try pt.intern(.{ .opt = .{
.ty = (try pt.optionalType(.type_type)).toIntern(),
@ -18044,7 +17971,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespace(zcu));
const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu));
const backing_integer_val = try pt.intern(.{ .opt = .{
.ty = (try pt.optionalType(.type_type)).toIntern(),
@ -18083,7 +18010,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque");
try ty.resolveFields(pt);
const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespace(zcu));
const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu));
const field_values = .{
// decls: []const Declaration,
@ -18105,7 +18032,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
fn typeInfoDecls(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
opt_namespace: InternPool.OptionalNamespaceIndex,
) CompileError!InternPool.Index {
@ -18121,7 +18047,7 @@ fn typeInfoDecls(
var seen_namespaces = std.AutoHashMap(*Namespace, void).init(gpa);
defer seen_namespaces.deinit();
try sema.typeInfoNamespaceDecls(block, src, opt_namespace, declaration_ty, &decl_vals, &seen_namespaces);
try sema.typeInfoNamespaceDecls(opt_namespace, declaration_ty, &decl_vals, &seen_namespaces);
const array_decl_ty = try pt.arrayType(.{
.len = decl_vals.items.len,
@ -18155,8 +18081,6 @@ fn typeInfoDecls(
fn typeInfoNamespaceDecls(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
opt_namespace_index: InternPool.OptionalNamespaceIndex,
declaration_ty: Type,
decl_vals: *std.ArrayList(InternPool.Index),
@ -18212,15 +18136,6 @@ fn typeInfoNamespaceDecls(
.storage = .{ .elems = &fields },
} }));
}
for (namespace.pub_usingnamespace.items) |nav| {
if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
continue;
}
try sema.ensureNavResolved(block, src, nav, .fully);
const namespace_ty: Type = .fromInterned(ip.getNav(nav).status.fully_resolved.val);
try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
}
}
fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@ -27709,7 +27624,7 @@ fn namespaceLookup(
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| {
if (try sema.lookupInNamespace(block, namespace, decl_name)) |lookup| {
if (!lookup.accessible) {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(src, "'{}' is not marked 'pub'", .{

View File

@ -792,10 +792,6 @@ pub const Namespace = struct {
pub_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .empty,
/// Members of the namespace which are *not* marked `pub`.
priv_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .empty,
/// All `usingnamespace` declarations in this namespace which are marked `pub`.
pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
/// All `usingnamespace` declarations in this namespace which are *not* marked `pub`.
priv_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
/// All `comptime` declarations in this namespace. We store these purely so that incremental
/// compilation can re-use the existing `ComptimeUnit`s when a namespace changes.
comptime_decls: std.ArrayListUnmanaged(InternPool.ComptimeUnit.Id) = .empty,
@ -1303,9 +1299,6 @@ pub const SrcLoc = struct {
.simple_var_decl,
.aligned_var_decl,
=> tree.fullVarDecl(node).?,
.@"usingnamespace" => {
return tree.nodeToSpan(tree.nodeData(node).node);
},
else => unreachable,
};
if (full.ast.type_node.unwrap()) |type_node| {
@ -3391,9 +3384,6 @@ pub fn mapOldZirToNew(
// All comptime declarations, in order, for a best-effort match.
var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
defer comptime_decls.deinit(gpa);
// All usingnamespace declarations, in order, for a best-effort match.
var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
defer usingnamespace_decls.deinit(gpa);
{
var old_decl_it = old_zir.declIterator(match_item.old_inst);
@ -3401,7 +3391,6 @@ pub fn mapOldZirToNew(
const old_decl = old_zir.getDeclaration(old_decl_inst);
switch (old_decl.kind) {
.@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
.@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
.unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
.@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
.decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
@ -3412,7 +3401,6 @@ pub fn mapOldZirToNew(
var unnamed_test_idx: u32 = 0;
var comptime_decl_idx: u32 = 0;
var usingnamespace_decl_idx: u32 = 0;
var new_decl_it = new_zir.declIterator(match_item.new_inst);
while (new_decl_it.next()) |new_decl_inst| {
@ -3422,7 +3410,6 @@ pub fn mapOldZirToNew(
// * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name.
// * For unnamed tests, we match based on order.
// * For comptime blocks, we match based on order.
// * For usingnamespace decls, we match based on order.
// If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
const old_decl_inst = switch (new_decl.kind) {
.@"comptime" => inst: {
@ -3430,11 +3417,6 @@ pub fn mapOldZirToNew(
defer comptime_decl_idx += 1;
break :inst comptime_decls.items[comptime_decl_idx];
},
.@"usingnamespace" => inst: {
if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
defer usingnamespace_decl_idx += 1;
break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
},
.unnamed_test => inst: {
if (unnamed_test_idx == unnamed_tests.items.len) continue;
defer unnamed_test_idx += 1;
@ -4143,7 +4125,6 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
const want_analysis = switch (decl.kind) {
.@"usingnamespace" => unreachable,
.@"const", .@"var" => unreachable,
.@"comptime" => unreachable,
.unnamed_test => true,
@ -4201,16 +4182,6 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
}
}
}
// Incremental compilation does not support `usingnamespace`.
// These are only included to keep good reference traces in non-incremental updates.
for (zcu.namespacePtr(ns).pub_usingnamespace.items) |nav| {
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
}
for (zcu.namespacePtr(ns).priv_usingnamespace.items) |nav| {
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
}
continue;
}
if (unit_queue.pop()) |kv| {

View File

@ -1111,7 +1111,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
defer block.instructions.deinit(gpa);
const zir_decl = zir.getDeclaration(inst_resolved.inst);
assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero });
const init_src = block.src(.{ .node_offset_var_decl_init = .zero });
@ -1160,7 +1159,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
assert(nav_ty.zigTypeTag(zcu) == .@"fn");
break :is_const true;
},
.@"usingnamespace", .@"const" => true,
.@"const" => true,
.@"var" => {
try sema.validateVarType(
&block,
@ -1240,26 +1239,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
// this resolves the type `type` (which needs no resolution), not the struct itself.
try nav_ty.resolveLayout(pt);
// TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`.
if (zir_decl.kind == .@"usingnamespace") {
if (nav_ty.toIntern() != .type_type) {
return sema.fail(&block, ty_src, "expected type, found {}", .{nav_ty.fmt(pt)});
}
if (nav_val.toType().getNamespace(zcu) == .none) {
return sema.fail(&block, ty_src, "type {} has no namespace", .{nav_val.toType().fmt(pt)});
}
ip.resolveNavValue(nav_id, .{
.val = nav_val.toIntern(),
.is_const = is_const,
.alignment = .none,
.@"linksection" = .none,
.@"addrspace" = .generic,
});
// TODO: usingnamespace cannot participate in incremental compilation
assert(zcu.analysis_in_progress.swapRemove(anal_unit));
return .{ .val_changed = true };
}
const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
.func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
.variable => |v| .{ v.owner_nav == nav_id, false },
@ -1464,7 +1443,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
const zir_decl = zir.getDeclaration(inst_resolved.inst);
assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
const type_body = zir_decl.type_body.?;
var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
@ -1527,7 +1505,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
const is_const = switch (zir_decl.kind) {
.@"comptime" => unreachable,
.unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
.unnamed_test, .@"test", .decltest, .@"const" => true,
.@"var" => false,
};
@ -2541,7 +2519,6 @@ pub fn scanNamespace(
try existing_by_inst.ensureTotalCapacity(gpa, @intCast(
namespace.pub_decls.count() + namespace.priv_decls.count() +
namespace.pub_usingnamespace.items.len + namespace.priv_usingnamespace.items.len +
namespace.comptime_decls.items.len +
namespace.test_decls.items.len,
));
@ -2554,14 +2531,6 @@ pub fn scanNamespace(
const zir_index = ip.getNav(nav).analysis.?.zir_index;
existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
}
for (namespace.pub_usingnamespace.items) |nav| {
const zir_index = ip.getNav(nav).analysis.?.zir_index;
existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
}
for (namespace.priv_usingnamespace.items) |nav| {
const zir_index = ip.getNav(nav).analysis.?.zir_index;
existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
}
for (namespace.comptime_decls.items) |cu| {
const zir_index = ip.getComptimeUnit(cu).zir_index;
existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .@"comptime" = cu }));
@ -2578,8 +2547,6 @@ pub fn scanNamespace(
namespace.pub_decls.clearRetainingCapacity();
namespace.priv_decls.clearRetainingCapacity();
namespace.pub_usingnamespace.clearRetainingCapacity();
namespace.priv_usingnamespace.clearRetainingCapacity();
namespace.comptime_decls.clearRetainingCapacity();
namespace.test_decls.clearRetainingCapacity();
@ -2607,7 +2574,6 @@ const ScanDeclIter = struct {
/// Decl scanning is run in two passes, so that we can detect when a generated
/// name would clash with an explicit name and use a different one.
pass: enum { named, unnamed },
usingnamespace_index: usize = 0,
unnamed_test_index: usize = 0,
fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString {
@ -2646,12 +2612,6 @@ const ScanDeclIter = struct {
if (iter.pass != .unnamed) return;
break :name .none;
},
.@"usingnamespace" => name: {
if (iter.pass != .unnamed) return;
const i = iter.usingnamespace_index;
iter.usingnamespace_index += 1;
break :name (try iter.avoidNameConflict("usingnamespace_{d}", .{i})).toOptional();
},
.unnamed_test => name: {
if (iter.pass != .unnamed) return;
const i = iter.unnamed_test_index;
@ -2710,7 +2670,7 @@ const ScanDeclIter = struct {
const name = maybe_name.unwrap().?;
const fqn = try namespace.internFullyQualifiedName(ip, gpa, pt.tid, name);
const nav = if (existing_unit) |eu| eu.unwrap().nav_val else nav: {
const nav = try ip.createDeclNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index, decl.kind == .@"usingnamespace");
const nav = try ip.createDeclNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index);
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
break :nav nav;
};
@ -2722,17 +2682,6 @@ const ScanDeclIter = struct {
const want_analysis = switch (decl.kind) {
.@"comptime" => unreachable,
.@"usingnamespace" => a: {
if (comp.incremental) {
@panic("'usingnamespace' is not supported by incremental compilation");
}
if (decl.is_pub) {
try namespace.pub_usingnamespace.append(gpa, nav);
} else {
try namespace.priv_usingnamespace.append(gpa, nav);
}
break :a true;
},
.unnamed_test, .@"test", .decltest => a: {
const is_named = decl.kind != .unnamed_test;
try namespace.test_decls.append(gpa, nav);

View File

@ -2489,7 +2489,7 @@ fn initWipNavInner(
const addr: Loc = .{ .addr_reloc = sym_index };
const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
switch (decl.kind) {
.unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
.unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
.@"const" => {
const const_ty_reloc_index = try wip_nav.refForward();
try wip_nav.infoExprLoc(loc);
@ -2775,7 +2775,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
const is_test = switch (decl.kind) {
.unnamed_test, .@"test", .decltest => true,
.@"comptime", .@"usingnamespace", .@"const", .@"var" => false,
.@"comptime", .@"const", .@"var" => false,
};
if (is_test) {
// This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.

View File

@ -2588,7 +2588,6 @@ const Writer = struct {
}
switch (decl.kind) {
.@"comptime" => try stream.writeAll("comptime"),
.@"usingnamespace" => try stream.writeAll("usingnamespace"),
.unnamed_test => try stream.writeAll("test"),
.@"test", .decltest, .@"const", .@"var" => {
try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });

View File

@ -101,7 +101,6 @@ test {
_ = @import("behavior/underscore.zig");
_ = @import("behavior/union.zig");
_ = @import("behavior/union_with_members.zig");
_ = @import("behavior/usingnamespace.zig");
_ = @import("behavior/var_args.zig");
// https://github.com/llvm/llvm-project/issues/118879
// https://github.com/llvm/llvm-project/issues/134659

View File

@ -1107,27 +1107,6 @@ test "inline call of function with a switch inside the return statement" {
try expect(S.foo(1) == 1);
}
test "ambiguous reference error ignores current declaration" {
const S = struct {
const foo = 666;
const a = @This();
const b = struct {
const foo = a.foo;
const bar = struct {
bar: u32 = b.foo,
};
comptime {
_ = b.foo;
}
};
usingnamespace b;
};
try expect(S.b.foo == 666);
}
test "pointer to zero sized global is mutable" {
const S = struct {
const Thing = struct {};

View File

@ -507,29 +507,6 @@ test "call inline fn through pointer" {
try f(123);
}
test "call coerced function" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const T = struct {
x: f64,
const T = @This();
usingnamespace Implement(1);
const F = fn (comptime f64) type;
const Implement: F = opaque {
fn implementer(comptime val: anytype) type {
return opaque {
fn incr(self: T) T {
return .{ .x = self.x + val };
}
};
}
}.implementer;
};
const a = T{ .x = 3 };
try std.testing.expect(a.incr().x == 4);
}
test "call function in comptime field" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO

View File

@ -18,16 +18,6 @@ test "importing the same thing gives the same import" {
try expect(@import("std") == @import("std"));
}
test "import in non-toplevel scope" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
usingnamespace @import("import/a_namespace.zig");
};
try expect(@as(i32, 1234) == S.foo());
}
test "import empty file" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

View File

@ -236,17 +236,6 @@ test "call method with mutable reference to struct with no fields" {
try expect(s.do());
}
test "usingnamespace within struct scope" {
const S = struct {
usingnamespace struct {
pub fn inner() i32 {
return 42;
}
};
};
try expect(@as(i32, 42) == S.inner());
}
test "struct field init with catch" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO

View File

@ -592,24 +592,6 @@ test "StructField.is_comptime" {
try expect(info.fields[1].is_comptime);
}
test "typeInfo resolves usingnamespace declarations" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const A = struct {
pub const f1 = 42;
};
const B = struct {
pub const f0 = 42;
pub usingnamespace A;
};
const decls = @typeInfo(B).@"struct".decls;
try expect(decls.len == 2);
try expectEqualStrings(decls[0].name, "f0");
try expectEqualStrings(decls[1].name, "f1");
}
test "value from struct @typeInfo default_value_ptr can be loaded at comptime" {
comptime {
const a = @typeInfo(@TypeOf(.{ .foo = @as(u8, 1) })).@"struct".fields[0].default_value_ptr;
@ -617,77 +599,12 @@ test "value from struct @typeInfo default_value_ptr can be loaded at comptime" {
}
}
test "@typeInfo decls and usingnamespace" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const A = struct {
pub const x = 5;
pub const y = 34;
comptime {}
};
const B = struct {
pub usingnamespace A;
pub const z = 56;
test {}
};
const decls = @typeInfo(B).@"struct".decls;
try expect(decls.len == 3);
try expectEqualStrings(decls[0].name, "z");
try expectEqualStrings(decls[1].name, "x");
try expectEqualStrings(decls[2].name, "y");
}
test "@typeInfo decls ignore dependency loops" {
const S = struct {
pub fn Def(comptime T: type) type {
std.debug.assert(@typeInfo(T).@"struct".decls.len == 1);
return struct {
const foo = u32;
};
}
usingnamespace Def(@This());
};
_ = S.foo;
}
test "type info of tuple of string literal default value" {
const struct_field = @typeInfo(@TypeOf(.{"hi"})).@"struct".fields[0];
const value = struct_field.defaultValue().?;
comptime std.debug.assert(value[0] == 'h');
}
test "@typeInfo only contains pub decls" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const other = struct {
const std = @import("std");
usingnamespace struct {
pub const inside_non_pub_usingnamespace = 0;
};
pub const Enum = enum {
a,
b,
c,
};
pub const Struct = struct {
foo: i32,
};
};
const ti = @typeInfo(other);
const decls = ti.@"struct".decls;
try std.testing.expectEqual(2, decls.len);
try std.testing.expectEqualStrings("Enum", decls[0].name);
try std.testing.expectEqualStrings("Struct", decls[1].name);
}
test "@typeInfo function with generic return type and inferred error set" {
const S = struct {
fn testFn(comptime T: type) !T {}

View File

@ -1,125 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
const A = struct {
pub const B = bool;
};
const C = struct {
usingnamespace A;
};
test "basic usingnamespace" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
try std.testing.expect(C.B == bool);
}
fn Foo(comptime T: type) type {
return struct {
usingnamespace T;
};
}
test "usingnamespace inside a generic struct" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const std2 = Foo(std);
const testing2 = Foo(std.testing);
try std2.testing.expect(true);
try testing2.expect(true);
}
usingnamespace struct {
pub const foo = 42;
};
test "usingnamespace does not redeclare an imported variable" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
try comptime std.testing.expect(@This().foo == 42);
}
usingnamespace @import("usingnamespace/foo.zig");
test "usingnamespace omits mixing in private functions" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
try expect(@This().privateFunction());
try expect(!@This().printText());
}
fn privateFunction() bool {
return true;
}
test {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
_ = @import("usingnamespace/import_segregation.zig");
}
usingnamespace @import("usingnamespace/a.zig");
test "two files usingnamespace import each other" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
try expect(@This().ok());
}
test {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const AA = struct {
x: i32,
fn b(x: i32) @This() {
return .{ .x = x };
}
fn c() type {
return if (true) struct {
const expected: i32 = 42;
} else struct {};
}
usingnamespace c();
};
const a = AA.b(42);
try expect(a.x == AA.c().expected);
}
const Bar = struct {
usingnamespace Mixin;
};
const Mixin = struct {
pub fn two(self: Bar) void {
_ = self;
}
};
test "container member access usingnamespace decls" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
var foo = Bar{};
foo.two();
}
usingnamespace opaque {};
usingnamespace @Type(.{ .@"struct" = .{
.layout = .auto,
.fields = &.{},
.decls = &.{},
.is_tuple = false,
} });

View File

@ -1,7 +0,0 @@
usingnamespace @import("b.zig");
pub const a_text = "OK\n";
pub fn ok() bool {
return @import("std").mem.eql(u8, @This().b_text, "OK\n");
}

View File

@ -1,3 +0,0 @@
usingnamespace @import("a.zig");
pub const b_text = @This().a_text;

View File

@ -1,8 +0,0 @@
usingnamespace @import("other.zig");
pub var saw_bar_function = false;
pub fn bar_function() void {
if (@This().foo_function()) {
saw_bar_function = true;
}
}

View File

@ -1,14 +0,0 @@
// purposefully conflicting function with main source file
// but it's private so it should be OK
fn privateFunction() bool {
return false;
}
pub fn printText() bool {
return privateFunction();
}
pub var saw_foo_function = false;
pub fn foo_function() void {
saw_foo_function = true;
}

View File

@ -1,20 +0,0 @@
const expect = @import("std").testing.expect;
const builtin = @import("builtin");
usingnamespace @import("foo.zig");
usingnamespace @import("bar.zig");
test "no clobbering happened" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
// https://github.com/ziglang/zig/issues/16846
return error.SkipZigTest;
}
@This().foo_function();
@This().bar_function();
try expect(@This().saw_foo_function);
try expect(@This().saw_bar_function);
}

View File

@ -1,4 +0,0 @@
pub fn foo_function() bool {
// this one conflicts with the one from foo
return true;
}

View File

@ -1,31 +0,0 @@
//! The full test name would be:
//! struct field type resolution marks transitive error from bad usingnamespace in @typeInfo call from non-initial field type
//!
//! This test is rather esoteric. It's ensuring that errors triggered by `@typeInfo` analyzing
//! a bad `usingnamespace` correctly trigger transitive errors when analyzed by struct field type
//! resolution, meaning we don't incorrectly analyze code past the uses of `S`.
const S = struct {
ok: u32,
bad: @typeInfo(T),
};
const T = struct {
pub usingnamespace @compileError("usingnamespace analyzed");
};
comptime {
const a: S = .{ .ok = 123, .bad = undefined };
_ = a;
@compileError("should not be reached");
}
comptime {
const b: S = .{ .ok = 123, .bad = undefined };
_ = b;
@compileError("should not be reached");
}
// error
//
// :14:24: error: usingnamespace analyzed

View File

@ -1,7 +0,0 @@
usingnamespace void;
// error
// backend=stage2
// target=native
//
// :1:16: error: type void has no namespace

View File

@ -48,9 +48,6 @@
.pkg_import = .{
.path = "pkg_import",
},
.use_alias = .{
.path = "use_alias",
},
.install_raw_hex = .{
.path = "install_raw_hex",
},

View File

@ -1,17 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test it");
b.default_step = test_step;
const optimize: std.builtin.OptimizeMode = .Debug;
const main = b.addTest(.{ .root_module = b.createModule(.{
.root_source_file = b.path("main.zig"),
.target = b.graph.host,
.optimize = optimize,
}) });
main.root_module.addIncludePath(b.path("."));
test_step.dependOn(&b.addRunArtifact(main).step);
}

View File

@ -1 +0,0 @@
pub usingnamespace @cImport(@cInclude("foo.h"));

View File

@ -1,4 +0,0 @@
struct Foo {
int a;
int b;
};

View File

@ -1,11 +0,0 @@
const c = @import("c.zig");
const expect = @import("std").testing.expect;
test "symbol exists" {
var foo = c.Foo{
.a = 1,
.b = 1,
};
_ = &foo;
try expect(foo.a + foo.b == 2);
}

View File

@ -746,7 +746,6 @@ fn tokenizeAndPrintRaw(
.keyword_try,
.keyword_union,
.keyword_unreachable,
.keyword_usingnamespace,
.keyword_var,
.keyword_volatile,
.keyword_allowzero,

View File

@ -689,7 +689,6 @@ fn tokenizeAndPrint(arena: Allocator, out: anytype, raw_src: []const u8) !void {
.keyword_try,
.keyword_union,
.keyword_unreachable,
.keyword_usingnamespace,
.keyword_var,
.keyword_volatile,
.keyword_allowzero,

View File

@ -86,7 +86,6 @@ zig_keywords = {
'try',
'union',
'unreachable',
'usingnamespace',
'var',
'volatile',
'while',