mirror of
https://github.com/ziglang/zig.git
synced 2026-02-09 11:03:30 +00:00
Merge pull request #14015 from Vexu/recursive-inline
Sema: add error for recursive inline call
This commit is contained in:
commit
1b86a628ac
@ -12062,24 +12062,24 @@ ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerFiel
|
||||
|
||||
ContainerDeclarations
|
||||
<- TestDecl ContainerDeclarations
|
||||
/ TopLevelComptime ContainerDeclarations
|
||||
/ doc_comment? KEYWORD_pub? TopLevelDecl ContainerDeclarations
|
||||
/ ComptimeDecl ContainerDeclarations
|
||||
/ doc_comment? KEYWORD_pub? Decl ContainerDeclarations
|
||||
/
|
||||
|
||||
TestDecl <- doc_comment? KEYWORD_test STRINGLITERALSINGLE? Block
|
||||
TestDecl <- KEYWORD_test STRINGLITERALSINGLE? Block
|
||||
|
||||
TopLevelComptime <- doc_comment? KEYWORD_comptime BlockExpr
|
||||
ComptimeDecl <- KEYWORD_comptime Block
|
||||
|
||||
TopLevelDecl
|
||||
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
|
||||
|
||||
FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
|
||||
FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
|
||||
|
||||
VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||
VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||
|
||||
ContainerField <- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON (KEYWORD_anytype / TypeExpr) ByteAlign?)? (EQUAL Expr)?
|
||||
ContainerField <- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
|
||||
|
||||
# *** Block Level ***
|
||||
Statement
|
||||
@ -12240,6 +12240,8 @@ WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
|
||||
|
||||
LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
|
||||
|
||||
AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
|
||||
|
||||
# Fn specific
|
||||
CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
|
||||
|
||||
@ -12267,7 +12269,7 @@ PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
|
||||
|
||||
|
||||
# Switch specific
|
||||
SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
|
||||
SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr
|
||||
|
||||
SwitchCase
|
||||
<- SwitchItem (COMMA SwitchItem)* COMMA?
|
||||
@ -12278,11 +12280,15 @@ SwitchItem <- Expr (DOT3 Expr)?
|
||||
# Operators
|
||||
AssignOp
|
||||
<- ASTERISKEQUAL
|
||||
/ ASTERISKPIPEEQUAL
|
||||
/ SLASHEQUAL
|
||||
/ PERCENTEQUAL
|
||||
/ PLUSEQUAL
|
||||
/ PLUSPIPEEQUAL
|
||||
/ MINUSEQUAL
|
||||
/ MINUSPIPEEQUAL
|
||||
/ LARROW2EQUAL
|
||||
/ LARROW2PIPEEQUAL
|
||||
/ RARROW2EQUAL
|
||||
/ AMPERSANDEQUAL
|
||||
/ CARETEQUAL
|
||||
@ -12310,6 +12316,7 @@ BitwiseOp
|
||||
BitShiftOp
|
||||
<- LARROW2
|
||||
/ RARROW2
|
||||
/ LARROW2PIPE
|
||||
|
||||
AdditionOp
|
||||
<- PLUS
|
||||
@ -12317,6 +12324,8 @@ AdditionOp
|
||||
/ PLUS2
|
||||
/ PLUSPERCENT
|
||||
/ MINUSPERCENT
|
||||
/ PLUSPIPE
|
||||
/ MINUSPIPE
|
||||
|
||||
MultiplyOp
|
||||
<- PIPE2
|
||||
@ -12325,6 +12334,7 @@ MultiplyOp
|
||||
/ PERCENT
|
||||
/ ASTERISK2
|
||||
/ ASTERISKPERCENT
|
||||
/ ASTERISKPIPE
|
||||
|
||||
PrefixOp
|
||||
<- EXCLAMATIONMARK
|
||||
@ -12338,8 +12348,8 @@ PrefixOp
|
||||
PrefixTypeOp
|
||||
<- QUESTIONMARK
|
||||
/ KEYWORD_anyframe MINUSRARROW
|
||||
/ SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
/ PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
/ SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
/ PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
/ ArrayTypeStart
|
||||
|
||||
SuffixOp
|
||||
@ -12364,7 +12374,7 @@ ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET
|
||||
ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
|
||||
|
||||
ContainerDeclType
|
||||
<- KEYWORD_struct
|
||||
<- KEYWORD_struct (LPAREN Expr RPAREN)?
|
||||
/ KEYWORD_opaque
|
||||
/ KEYWORD_enum (LPAREN Expr RPAREN)?
|
||||
/ KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
|
||||
@ -12455,7 +12465,7 @@ string_char
|
||||
/ [^\\"\n]
|
||||
|
||||
container_doc_comment <- ('//!' [^\n]* [ \n]*)+
|
||||
doc_comment <- ('///' [^\n]* [ \n]*)+
|
||||
doc_comment <- ('///' [^\n]* [ \n]*)+ skip
|
||||
line_comment <- '//' ![!/][^\n]* / '////' [^\n]*
|
||||
line_string <- ("\\\\" [^\n]* [ \n]*)+
|
||||
skip <- ([ \n] / line_comment)*
|
||||
@ -12483,11 +12493,13 @@ BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip
|
||||
|
||||
AMPERSAND <- '&' ![=] skip
|
||||
AMPERSANDEQUAL <- '&=' skip
|
||||
ASTERISK <- '*' ![*%=] skip
|
||||
ASTERISK <- '*' ![*%=|] skip
|
||||
ASTERISK2 <- '**' skip
|
||||
ASTERISKEQUAL <- '*=' skip
|
||||
ASTERISKPERCENT <- '*%' ![=] skip
|
||||
ASTERISKPERCENTEQUAL <- '*%=' skip
|
||||
ASTERISKPIPE <- '*|' ![=] skip
|
||||
ASTERISKPIPEEQUAL <- '*|=' skip
|
||||
CARET <- '^' ![=] skip
|
||||
CARETEQUAL <- '^=' skip
|
||||
COLON <- ':' skip
|
||||
@ -12503,27 +12515,33 @@ EQUALRARROW <- '=>' skip
|
||||
EXCLAMATIONMARK <- '!' ![=] skip
|
||||
EXCLAMATIONMARKEQUAL <- '!=' skip
|
||||
LARROW <- '<' ![<=] skip
|
||||
LARROW2 <- '<<' ![=] skip
|
||||
LARROW2 <- '<<' ![=|] skip
|
||||
LARROW2EQUAL <- '<<=' skip
|
||||
LARROW2PIPE <- '<<|' ![=] skip
|
||||
LARROW2PIPEEQUAL <- '<<|=' skip
|
||||
LARROWEQUAL <- '<=' skip
|
||||
LBRACE <- '{' skip
|
||||
LBRACKET <- '[' skip
|
||||
LPAREN <- '(' skip
|
||||
MINUS <- '-' ![%=>] skip
|
||||
MINUS <- '-' ![%=>|] skip
|
||||
MINUSEQUAL <- '-=' skip
|
||||
MINUSPERCENT <- '-%' ![=] skip
|
||||
MINUSPERCENTEQUAL <- '-%=' skip
|
||||
MINUSPIPE <- '-|' ![=] skip
|
||||
MINUSPIPEEQUAL <- '-|=' skip
|
||||
MINUSRARROW <- '->' skip
|
||||
PERCENT <- '%' ![=] skip
|
||||
PERCENTEQUAL <- '%=' skip
|
||||
PIPE <- '|' ![|=] skip
|
||||
PIPE2 <- '||' skip
|
||||
PIPEEQUAL <- '|=' skip
|
||||
PLUS <- '+' ![%+=] skip
|
||||
PLUS <- '+' ![%+=|] skip
|
||||
PLUS2 <- '++' skip
|
||||
PLUSEQUAL <- '+=' skip
|
||||
PLUSPERCENT <- '+%' ![=] skip
|
||||
PLUSPERCENTEQUAL <- '+%=' skip
|
||||
PLUSPIPE <- '+|' ![=] skip
|
||||
PLUSPIPEEQUAL <- '+|=' skip
|
||||
LETTERC <- 'c' skip
|
||||
QUESTIONMARK <- '?' skip
|
||||
RARROW <- '>' ![>=] skip
|
||||
@ -12539,6 +12557,7 @@ SLASHEQUAL <- '/=' skip
|
||||
TILDE <- '~' skip
|
||||
|
||||
end_of_word <- ![a-zA-Z0-9_] skip
|
||||
KEYWORD_addrspace <- 'addrspace' end_of_word
|
||||
KEYWORD_align <- 'align' end_of_word
|
||||
KEYWORD_allowzero <- 'allowzero' end_of_word
|
||||
KEYWORD_and <- 'and' end_of_word
|
||||
@ -12588,11 +12607,11 @@ KEYWORD_var <- 'var' end_of_word
|
||||
KEYWORD_volatile <- 'volatile' end_of_word
|
||||
KEYWORD_while <- 'while' end_of_word
|
||||
|
||||
keyword <- KEYWORD_align / KEYWORD_allowzero / KEYWORD_and / KEYWORD_anyframe
|
||||
/ KEYWORD_anytype / KEYWORD_asm / KEYWORD_async / KEYWORD_await
|
||||
/ KEYWORD_break / KEYWORD_callconv / KEYWORD_catch / KEYWORD_comptime
|
||||
/ KEYWORD_const / KEYWORD_continue / KEYWORD_defer / KEYWORD_else
|
||||
/ KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
|
||||
keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
|
||||
/ KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm / KEYWORD_async
|
||||
/ KEYWORD_await / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch
|
||||
/ KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer
|
||||
/ KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
|
||||
/ KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if
|
||||
/ KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline
|
||||
/ KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed
|
||||
|
||||
@ -240,10 +240,10 @@ const Parser = struct {
|
||||
/// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations)
|
||||
/// ContainerDeclarations
|
||||
/// <- TestDecl ContainerDeclarations
|
||||
/// / TopLevelComptime ContainerDeclarations
|
||||
/// / KEYWORD_pub? TopLevelDecl ContainerDeclarations
|
||||
/// / ComptimeDecl ContainerDeclarations
|
||||
/// / doc_comment? KEYWORD_pub? Decl ContainerDeclarations
|
||||
/// /
|
||||
/// TopLevelComptime <- KEYWORD_comptime Block
|
||||
/// ComptimeDecl <- KEYWORD_comptime Block
|
||||
fn parseContainerMembers(p: *Parser) !Members {
|
||||
const scratch_top = p.scratch.items.len;
|
||||
defer p.scratch.shrinkRetainingCapacity(scratch_top);
|
||||
@ -622,7 +622,7 @@ const Parser = struct {
|
||||
};
|
||||
}
|
||||
|
||||
/// TopLevelDecl
|
||||
/// 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
|
||||
|
||||
48
src/Sema.zig
48
src/Sema.zig
@ -335,6 +335,7 @@ pub const Block = struct {
|
||||
/// It is shared among all the blocks in an inline or comptime called
|
||||
/// function.
|
||||
pub const Inlining = struct {
|
||||
func: ?*Module.Fn,
|
||||
comptime_result: Air.Inst.Ref,
|
||||
merges: Merges,
|
||||
};
|
||||
@ -6428,7 +6429,6 @@ fn analyzeCall(
|
||||
}),
|
||||
else => unreachable,
|
||||
};
|
||||
if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail;
|
||||
if (func_ty_info.is_var_args) {
|
||||
return sema.fail(block, call_src, "{s} call of variadic function", .{
|
||||
@as([]const u8, if (is_comptime_call) "comptime" else "inline"),
|
||||
@ -6448,6 +6448,7 @@ fn analyzeCall(
|
||||
// This one is shared among sub-blocks within the same callee, but not
|
||||
// shared among the entire inline/comptime call stack.
|
||||
var inlining: Block.Inlining = .{
|
||||
.func = null,
|
||||
.comptime_result = undefined,
|
||||
.merges = .{
|
||||
.results = .{},
|
||||
@ -6534,6 +6535,7 @@ fn analyzeCall(
|
||||
const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
|
||||
try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body);
|
||||
|
||||
var has_comptime_args = false;
|
||||
var arg_i: usize = 0;
|
||||
for (fn_info.param_body) |inst| {
|
||||
sema.analyzeInlineCallArg(
|
||||
@ -6549,6 +6551,7 @@ fn analyzeCall(
|
||||
memoized_call_key,
|
||||
func_ty_info.param_types,
|
||||
func,
|
||||
&has_comptime_args,
|
||||
) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => {
|
||||
_ = sema.inst_map.remove(inst);
|
||||
@ -6566,6 +6569,7 @@ fn analyzeCall(
|
||||
memoized_call_key,
|
||||
func_ty_info.param_types,
|
||||
func,
|
||||
&has_comptime_args,
|
||||
);
|
||||
unreachable;
|
||||
},
|
||||
@ -6573,6 +6577,19 @@ fn analyzeCall(
|
||||
};
|
||||
}
|
||||
|
||||
if (!has_comptime_args and module_fn.state == .sema_failure) return error.AnalysisFail;
|
||||
|
||||
const recursive_msg = "inline call is recursive";
|
||||
var head = if (!has_comptime_args) block else null;
|
||||
while (head) |some| {
|
||||
const parent_inlining = some.inlining orelse break;
|
||||
if (parent_inlining.func == module_fn) {
|
||||
return sema.fail(block, call_src, recursive_msg, .{});
|
||||
}
|
||||
head = some.parent;
|
||||
}
|
||||
if (!has_comptime_args) inlining.func = module_fn;
|
||||
|
||||
// In case it is a generic function with an expression for the return type that depends
|
||||
// on parameters, we must now do the same for the return type as we just did with
|
||||
// each of the parameters, resolving the return type and providing it to the child
|
||||
@ -6657,6 +6674,7 @@ fn analyzeCall(
|
||||
error.ComptimeReturn => break :result inlining.comptime_result,
|
||||
error.AnalysisFail => {
|
||||
const err_msg = sema.err orelse return err;
|
||||
if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err;
|
||||
try sema.errNote(block, call_src, err_msg, "called from here", .{});
|
||||
err_msg.clearTrace(sema.gpa);
|
||||
return err;
|
||||
@ -6814,8 +6832,13 @@ fn analyzeInlineCallArg(
|
||||
memoized_call_key: Module.MemoizedCall.Key,
|
||||
raw_param_types: []const Type,
|
||||
func_inst: Air.Inst.Ref,
|
||||
has_comptime_args: *bool,
|
||||
) !void {
|
||||
const zir_tags = sema.code.instructions.items(.tag);
|
||||
switch (zir_tags[inst]) {
|
||||
.param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
|
||||
else => {},
|
||||
}
|
||||
switch (zir_tags[inst]) {
|
||||
.param, .param_comptime => {
|
||||
// Evaluate the parameter type expression now that previous ones have
|
||||
@ -6870,23 +6893,20 @@ fn analyzeInlineCallArg(
|
||||
.ty = param_ty,
|
||||
.val = arg_val,
|
||||
};
|
||||
} else if (zir_tags[inst] == .param_comptime or try sema.typeRequiresComptime(param_ty)) {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
|
||||
} else if (try sema.resolveMaybeUndefVal(casted_arg)) |val| {
|
||||
// We have a comptime value but we need a runtime value to preserve inlining semantics,
|
||||
const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, wrapped);
|
||||
} else {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
|
||||
}
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(casted_arg)) |_| {
|
||||
has_comptime_args.* = true;
|
||||
}
|
||||
|
||||
arg_i.* += 1;
|
||||
},
|
||||
.param_anytype, .param_anytype_comptime => {
|
||||
// No coercion needed.
|
||||
const uncasted_arg = uncasted_args[arg_i.*];
|
||||
new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);
|
||||
const param_ty = sema.typeOf(uncasted_arg);
|
||||
|
||||
if (is_comptime_call) {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
|
||||
@ -6912,16 +6932,14 @@ fn analyzeInlineCallArg(
|
||||
.ty = sema.typeOf(uncasted_arg),
|
||||
.val = arg_val,
|
||||
};
|
||||
} else if (zir_tags[inst] == .param_anytype_comptime or try sema.typeRequiresComptime(param_ty)) {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
|
||||
} else if (try sema.resolveMaybeUndefVal(uncasted_arg)) |val| {
|
||||
// We have a comptime value but we need a runtime value to preserve inlining semantics,
|
||||
const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, wrapped);
|
||||
} else {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
|
||||
}
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| {
|
||||
has_comptime_args.* = true;
|
||||
}
|
||||
|
||||
arg_i.* += 1;
|
||||
},
|
||||
else => {},
|
||||
@ -33075,7 +33093,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
|
||||
host_size: u16 = 0,
|
||||
alignment: u32 = 0,
|
||||
vector_index: VI = .none,
|
||||
} = if (parent_ty.tag() == .vector) blk: {
|
||||
} = if (parent_ty.tag() == .vector and ptr_info.size == .One) blk: {
|
||||
const elem_bits = elem_ty.bitSize(target);
|
||||
if (elem_bits == 0) break :blk .{};
|
||||
const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
|
||||
|
||||
@ -3361,6 +3361,10 @@ pub const DeclGen = struct {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return llvm_type.constNull();
|
||||
},
|
||||
.opt_payload => {
|
||||
const payload = tv.val.castTag(.opt_payload).?.data;
|
||||
return dg.lowerParentPtr(payload, tv.ty);
|
||||
},
|
||||
else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
|
||||
tv.ty.fmtDebug(), tag,
|
||||
}),
|
||||
|
||||
@ -133,7 +133,6 @@ test {
|
||||
_ = @import("behavior/bugs/13113.zig");
|
||||
_ = @import("behavior/bugs/13128.zig");
|
||||
_ = @import("behavior/bugs/13159.zig");
|
||||
_ = @import("behavior/bugs/13164.zig");
|
||||
_ = @import("behavior/bugs/13171.zig");
|
||||
_ = @import("behavior/bugs/13209.zig");
|
||||
_ = @import("behavior/bugs/13285.zig");
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
inline fn setLimits(min: ?u32, max: ?u32) !void {
|
||||
if (min != null and max != null) {
|
||||
try std.testing.expect(min.? <= max.?);
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
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_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
||||
var x: u32 = 42;
|
||||
try setLimits(x, null);
|
||||
}
|
||||
@ -381,3 +381,17 @@ test "generic function with generic function parameter" {
|
||||
};
|
||||
try S.f(S.g, 123);
|
||||
}
|
||||
|
||||
test "recursive inline call with comptime known argument" {
|
||||
const S = struct {
|
||||
inline fn foo(x: i32) i32 {
|
||||
if (x <= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return x * 2 + foo(x - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try expect(S.foo(4) == 20);
|
||||
}
|
||||
|
||||
@ -1261,3 +1261,19 @@ test "store packed vector element" {
|
||||
v[0] = 0;
|
||||
try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v);
|
||||
}
|
||||
|
||||
test "store to vector in slice" {
|
||||
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_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
|
||||
var v = [_]@Vector(3, f32){
|
||||
.{ 1, 1, 1 },
|
||||
.{ 0, 0, 0 },
|
||||
};
|
||||
var s: []@Vector(3, f32) = &v;
|
||||
var i: usize = 1;
|
||||
s[i] = s[0];
|
||||
try expectEqual(v[1], v[0]);
|
||||
}
|
||||
|
||||
18
test/cases/compile_errors/recursive_inline_fn.zig
Normal file
18
test/cases/compile_errors/recursive_inline_fn.zig
Normal file
@ -0,0 +1,18 @@
|
||||
inline fn foo(x: i32) i32 {
|
||||
if (x <= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return x * 2 + foo(x - 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub export fn entry() void {
|
||||
var x: i32 = 4;
|
||||
_ = foo(x) == 20;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :5:27: error: inline call is recursive
|
||||
Loading…
x
Reference in New Issue
Block a user