mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
Merge remote-tracking branch 'origin/master' into llvm9
This commit is contained in:
commit
63ebd9d12e
@ -209,7 +209,7 @@ else()
|
||||
else()
|
||||
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Wno-comment")
|
||||
if(MINGW)
|
||||
set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format")
|
||||
set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO")
|
||||
endif()
|
||||
endif()
|
||||
set_target_properties(embedded_lld_lib PROPERTIES
|
||||
@ -511,19 +511,23 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
|
||||
|
||||
set(EXE_LDFLAGS " ")
|
||||
if(MSVC)
|
||||
set(EXE_LDFLAGS "/STACK:16777216")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216")
|
||||
elseif(MINGW)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
|
||||
endif()
|
||||
|
||||
if(ZIG_STATIC)
|
||||
if(APPLE)
|
||||
set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++")
|
||||
elseif(MINGW)
|
||||
set(EXE_LDFLAGS "-static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -lz3 -lz -lgomp -Wl,--no-whole-archive")
|
||||
else()
|
||||
set(EXE_LDFLAGS "-static")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++ -Wl,-Bstatic, -lwinpthread -lz3 -lz -lgomp")
|
||||
elseif(NOT MSVC)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static")
|
||||
endif()
|
||||
else()
|
||||
if(MINGW)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -lz3")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ZIG_TEST_COVERAGE)
|
||||
@ -559,11 +563,6 @@ if(NOT MSVC)
|
||||
target_link_libraries(compiler LINK_PUBLIC ${LIBXML2})
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
find_library(Z3_LIBRARIES NAMES z3 z3.dll)
|
||||
target_link_libraries(compiler LINK_PUBLIC ${Z3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(ZIG_DIA_GUIDS_LIB)
|
||||
target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})
|
||||
endif()
|
||||
|
||||
234
doc/docgen.zig
234
doc/docgen.zig
@ -742,101 +742,101 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
const token = tokenizer.next();
|
||||
try writeEscaped(out, src[index..token.start]);
|
||||
switch (token.id) {
|
||||
std.zig.Token.Id.Eof => break,
|
||||
.Eof => break,
|
||||
|
||||
std.zig.Token.Id.Keyword_align,
|
||||
std.zig.Token.Id.Keyword_and,
|
||||
std.zig.Token.Id.Keyword_asm,
|
||||
std.zig.Token.Id.Keyword_async,
|
||||
std.zig.Token.Id.Keyword_await,
|
||||
std.zig.Token.Id.Keyword_break,
|
||||
std.zig.Token.Id.Keyword_cancel,
|
||||
std.zig.Token.Id.Keyword_catch,
|
||||
std.zig.Token.Id.Keyword_comptime,
|
||||
std.zig.Token.Id.Keyword_const,
|
||||
std.zig.Token.Id.Keyword_continue,
|
||||
std.zig.Token.Id.Keyword_defer,
|
||||
std.zig.Token.Id.Keyword_else,
|
||||
std.zig.Token.Id.Keyword_enum,
|
||||
std.zig.Token.Id.Keyword_errdefer,
|
||||
std.zig.Token.Id.Keyword_error,
|
||||
std.zig.Token.Id.Keyword_export,
|
||||
std.zig.Token.Id.Keyword_extern,
|
||||
std.zig.Token.Id.Keyword_for,
|
||||
std.zig.Token.Id.Keyword_if,
|
||||
std.zig.Token.Id.Keyword_inline,
|
||||
std.zig.Token.Id.Keyword_nakedcc,
|
||||
std.zig.Token.Id.Keyword_noalias,
|
||||
std.zig.Token.Id.Keyword_or,
|
||||
std.zig.Token.Id.Keyword_orelse,
|
||||
std.zig.Token.Id.Keyword_packed,
|
||||
std.zig.Token.Id.Keyword_promise,
|
||||
std.zig.Token.Id.Keyword_pub,
|
||||
std.zig.Token.Id.Keyword_resume,
|
||||
std.zig.Token.Id.Keyword_return,
|
||||
std.zig.Token.Id.Keyword_linksection,
|
||||
std.zig.Token.Id.Keyword_stdcallcc,
|
||||
std.zig.Token.Id.Keyword_struct,
|
||||
std.zig.Token.Id.Keyword_suspend,
|
||||
std.zig.Token.Id.Keyword_switch,
|
||||
std.zig.Token.Id.Keyword_test,
|
||||
std.zig.Token.Id.Keyword_threadlocal,
|
||||
std.zig.Token.Id.Keyword_try,
|
||||
std.zig.Token.Id.Keyword_union,
|
||||
std.zig.Token.Id.Keyword_unreachable,
|
||||
std.zig.Token.Id.Keyword_usingnamespace,
|
||||
std.zig.Token.Id.Keyword_var,
|
||||
std.zig.Token.Id.Keyword_volatile,
|
||||
std.zig.Token.Id.Keyword_allowzero,
|
||||
std.zig.Token.Id.Keyword_while,
|
||||
.Keyword_align,
|
||||
.Keyword_and,
|
||||
.Keyword_asm,
|
||||
.Keyword_async,
|
||||
.Keyword_await,
|
||||
.Keyword_break,
|
||||
.Keyword_cancel,
|
||||
.Keyword_catch,
|
||||
.Keyword_comptime,
|
||||
.Keyword_const,
|
||||
.Keyword_continue,
|
||||
.Keyword_defer,
|
||||
.Keyword_else,
|
||||
.Keyword_enum,
|
||||
.Keyword_errdefer,
|
||||
.Keyword_error,
|
||||
.Keyword_export,
|
||||
.Keyword_extern,
|
||||
.Keyword_for,
|
||||
.Keyword_if,
|
||||
.Keyword_inline,
|
||||
.Keyword_nakedcc,
|
||||
.Keyword_noalias,
|
||||
.Keyword_or,
|
||||
.Keyword_orelse,
|
||||
.Keyword_packed,
|
||||
.Keyword_promise,
|
||||
.Keyword_pub,
|
||||
.Keyword_resume,
|
||||
.Keyword_return,
|
||||
.Keyword_linksection,
|
||||
.Keyword_stdcallcc,
|
||||
.Keyword_struct,
|
||||
.Keyword_suspend,
|
||||
.Keyword_switch,
|
||||
.Keyword_test,
|
||||
.Keyword_threadlocal,
|
||||
.Keyword_try,
|
||||
.Keyword_union,
|
||||
.Keyword_unreachable,
|
||||
.Keyword_usingnamespace,
|
||||
.Keyword_var,
|
||||
.Keyword_volatile,
|
||||
.Keyword_allowzero,
|
||||
.Keyword_while,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-kw\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Keyword_fn => {
|
||||
.Keyword_fn => {
|
||||
try out.write("<span class=\"tok-kw\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
next_tok_is_fn = true;
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Keyword_undefined,
|
||||
std.zig.Token.Id.Keyword_null,
|
||||
std.zig.Token.Id.Keyword_true,
|
||||
std.zig.Token.Id.Keyword_false,
|
||||
.Keyword_undefined,
|
||||
.Keyword_null,
|
||||
.Keyword_true,
|
||||
.Keyword_false,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-null\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.StringLiteral,
|
||||
std.zig.Token.Id.MultilineStringLiteralLine,
|
||||
std.zig.Token.Id.CharLiteral,
|
||||
.StringLiteral,
|
||||
.MultilineStringLiteralLine,
|
||||
.CharLiteral,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-str\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Builtin => {
|
||||
.Builtin => {
|
||||
try out.write("<span class=\"tok-builtin\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.LineComment,
|
||||
std.zig.Token.Id.DocComment,
|
||||
std.zig.Token.Id.ShebangLine,
|
||||
.LineComment,
|
||||
.DocComment,
|
||||
.ShebangLine,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-comment\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Identifier => {
|
||||
.Identifier => {
|
||||
if (prev_tok_was_fn) {
|
||||
try out.write("<span class=\"tok-fn\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
@ -864,72 +864,72 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
}
|
||||
},
|
||||
|
||||
std.zig.Token.Id.IntegerLiteral,
|
||||
std.zig.Token.Id.FloatLiteral,
|
||||
.IntegerLiteral,
|
||||
.FloatLiteral,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-number\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Bang,
|
||||
std.zig.Token.Id.Pipe,
|
||||
std.zig.Token.Id.PipePipe,
|
||||
std.zig.Token.Id.PipeEqual,
|
||||
std.zig.Token.Id.Equal,
|
||||
std.zig.Token.Id.EqualEqual,
|
||||
std.zig.Token.Id.EqualAngleBracketRight,
|
||||
std.zig.Token.Id.BangEqual,
|
||||
std.zig.Token.Id.LParen,
|
||||
std.zig.Token.Id.RParen,
|
||||
std.zig.Token.Id.Semicolon,
|
||||
std.zig.Token.Id.Percent,
|
||||
std.zig.Token.Id.PercentEqual,
|
||||
std.zig.Token.Id.LBrace,
|
||||
std.zig.Token.Id.RBrace,
|
||||
std.zig.Token.Id.LBracket,
|
||||
std.zig.Token.Id.RBracket,
|
||||
std.zig.Token.Id.Period,
|
||||
std.zig.Token.Id.Ellipsis2,
|
||||
std.zig.Token.Id.Ellipsis3,
|
||||
std.zig.Token.Id.Caret,
|
||||
std.zig.Token.Id.CaretEqual,
|
||||
std.zig.Token.Id.Plus,
|
||||
std.zig.Token.Id.PlusPlus,
|
||||
std.zig.Token.Id.PlusEqual,
|
||||
std.zig.Token.Id.PlusPercent,
|
||||
std.zig.Token.Id.PlusPercentEqual,
|
||||
std.zig.Token.Id.Minus,
|
||||
std.zig.Token.Id.MinusEqual,
|
||||
std.zig.Token.Id.MinusPercent,
|
||||
std.zig.Token.Id.MinusPercentEqual,
|
||||
std.zig.Token.Id.Asterisk,
|
||||
std.zig.Token.Id.AsteriskEqual,
|
||||
std.zig.Token.Id.AsteriskAsterisk,
|
||||
std.zig.Token.Id.AsteriskPercent,
|
||||
std.zig.Token.Id.AsteriskPercentEqual,
|
||||
std.zig.Token.Id.Arrow,
|
||||
std.zig.Token.Id.Colon,
|
||||
std.zig.Token.Id.Slash,
|
||||
std.zig.Token.Id.SlashEqual,
|
||||
std.zig.Token.Id.Comma,
|
||||
std.zig.Token.Id.Ampersand,
|
||||
std.zig.Token.Id.AmpersandEqual,
|
||||
std.zig.Token.Id.QuestionMark,
|
||||
std.zig.Token.Id.AngleBracketLeft,
|
||||
std.zig.Token.Id.AngleBracketLeftEqual,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketLeft,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketLeftEqual,
|
||||
std.zig.Token.Id.AngleBracketRight,
|
||||
std.zig.Token.Id.AngleBracketRightEqual,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRight,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
|
||||
std.zig.Token.Id.Tilde,
|
||||
std.zig.Token.Id.BracketStarBracket,
|
||||
std.zig.Token.Id.BracketStarCBracket,
|
||||
.Bang,
|
||||
.Pipe,
|
||||
.PipePipe,
|
||||
.PipeEqual,
|
||||
.Equal,
|
||||
.EqualEqual,
|
||||
.EqualAngleBracketRight,
|
||||
.BangEqual,
|
||||
.LParen,
|
||||
.RParen,
|
||||
.Semicolon,
|
||||
.Percent,
|
||||
.PercentEqual,
|
||||
.LBrace,
|
||||
.RBrace,
|
||||
.LBracket,
|
||||
.RBracket,
|
||||
.Period,
|
||||
.Ellipsis2,
|
||||
.Ellipsis3,
|
||||
.Caret,
|
||||
.CaretEqual,
|
||||
.Plus,
|
||||
.PlusPlus,
|
||||
.PlusEqual,
|
||||
.PlusPercent,
|
||||
.PlusPercentEqual,
|
||||
.Minus,
|
||||
.MinusEqual,
|
||||
.MinusPercent,
|
||||
.MinusPercentEqual,
|
||||
.Asterisk,
|
||||
.AsteriskEqual,
|
||||
.AsteriskAsterisk,
|
||||
.AsteriskPercent,
|
||||
.AsteriskPercentEqual,
|
||||
.Arrow,
|
||||
.Colon,
|
||||
.Slash,
|
||||
.SlashEqual,
|
||||
.Comma,
|
||||
.Ampersand,
|
||||
.AmpersandEqual,
|
||||
.QuestionMark,
|
||||
.AngleBracketLeft,
|
||||
.AngleBracketLeftEqual,
|
||||
.AngleBracketAngleBracketLeft,
|
||||
.AngleBracketAngleBracketLeftEqual,
|
||||
.AngleBracketRight,
|
||||
.AngleBracketRightEqual,
|
||||
.AngleBracketAngleBracketRight,
|
||||
.AngleBracketAngleBracketRightEqual,
|
||||
.Tilde,
|
||||
.BracketStarBracket,
|
||||
.BracketStarCBracket,
|
||||
=> try writeEscaped(out, src[token.start..token.end]),
|
||||
|
||||
std.zig.Token.Id.Invalid => return parseError(
|
||||
.Invalid, .Invalid_ampersands => return parseError(
|
||||
docgen_tokenizer,
|
||||
source_token,
|
||||
"syntax error",
|
||||
|
||||
@ -6330,6 +6330,22 @@ comptime {
|
||||
TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
|
||||
we can remove this restriction
|
||||
</p>
|
||||
<p>
|
||||
Supported operations:
|
||||
</p>
|
||||
<ul>
|
||||
<li>{#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified.</li>
|
||||
<li>{#syntax#}.Add{#endsyntax#} - for integers, twos complement wraparound addition.
|
||||
Also supports {#link|Floats#}.</li>
|
||||
<li>{#syntax#}.Sub{#endsyntax#} - for integers, twos complement wraparound subtraction.
|
||||
Also supports {#link|Floats#}.</li>
|
||||
<li>{#syntax#}.And{#endsyntax#} - bitwise and</li>
|
||||
<li>{#syntax#}.Nand{#endsyntax#} - bitwise nand</li>
|
||||
<li>{#syntax#}.Or{#endsyntax#} - bitwise or</li>
|
||||
<li>{#syntax#}.Xor{#endsyntax#} - bitwise xor</li>
|
||||
<li>{#syntax#}.Max{#endsyntax#} - stores the operand if it is larger. Supports integers and floats.</li>
|
||||
<li>{#syntax#}.Min{#endsyntax#} - stores the operand if it is smaller. Supports integers and floats.</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
{#header_open|@bitCast#}
|
||||
<pre>{#syntax#}@bitCast(comptime DestType: type, value: var) DestType{#endsyntax#}</pre>
|
||||
|
||||
@ -366,6 +366,7 @@ enum TldId {
|
||||
TldIdFn,
|
||||
TldIdContainer,
|
||||
TldIdCompTime,
|
||||
TldIdUsingNamespace,
|
||||
};
|
||||
|
||||
enum TldResolution {
|
||||
@ -413,6 +414,12 @@ struct TldCompTime {
|
||||
Tld base;
|
||||
};
|
||||
|
||||
struct TldUsingNamespace {
|
||||
Tld base;
|
||||
|
||||
ConstExprValue *using_namespace_value;
|
||||
};
|
||||
|
||||
struct TypeEnumField {
|
||||
Buf *name;
|
||||
BigInt value;
|
||||
@ -453,7 +460,7 @@ enum NodeType {
|
||||
NodeTypeFieldAccessExpr,
|
||||
NodeTypePtrDeref,
|
||||
NodeTypeUnwrapOptional,
|
||||
NodeTypeUse,
|
||||
NodeTypeUsingNamespace,
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeUndefinedLiteral,
|
||||
@ -715,9 +722,6 @@ struct AstNodeArrayType {
|
||||
struct AstNodeUsingNamespace {
|
||||
VisibMod visib_mod;
|
||||
AstNode *expr;
|
||||
|
||||
TldResolution resolution;
|
||||
ConstExprValue *using_namespace_value;
|
||||
};
|
||||
|
||||
struct AstNodeIfBoolExpr {
|
||||
@ -1745,8 +1749,6 @@ struct CodeGen {
|
||||
|
||||
ZigList<Tld *> resolve_queue;
|
||||
size_t resolve_queue_index;
|
||||
ZigList<AstNode *> use_queue;
|
||||
size_t use_queue_index;
|
||||
ZigList<TimeEvent> timing_events;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
@ -2005,7 +2007,7 @@ struct ScopeDecls {
|
||||
Scope base;
|
||||
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
|
||||
ZigList<AstNode *> use_decls;
|
||||
ZigList<TldUsingNamespace *> use_decls;
|
||||
AstNode *safety_set_node;
|
||||
AstNode *fast_math_set_node;
|
||||
ZigType *import;
|
||||
@ -2541,6 +2543,7 @@ struct IrInstructionLoadPtrGen {
|
||||
struct IrInstructionStorePtr {
|
||||
IrInstruction base;
|
||||
|
||||
bool allow_write_through_const;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *value;
|
||||
};
|
||||
@ -3705,6 +3708,7 @@ enum ResultLocId {
|
||||
struct ResultLoc {
|
||||
ResultLocId id;
|
||||
bool written;
|
||||
bool allow_write_through_const;
|
||||
IrInstruction *resolved_loc; // result ptr
|
||||
IrInstruction *source_instruction;
|
||||
IrInstruction *gen_instruction; // value to store to the result loc
|
||||
|
||||
266
src/analyze.cpp
266
src/analyze.cpp
@ -28,6 +28,8 @@ static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *uni
|
||||
static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type);
|
||||
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
|
||||
static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
|
||||
static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
|
||||
static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
|
||||
|
||||
static bool is_top_level_struct(ZigType *import) {
|
||||
return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
|
||||
@ -2854,6 +2856,8 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
|
||||
add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body"));
|
||||
return;
|
||||
}
|
||||
} else if (tld->id == TldIdUsingNamespace) {
|
||||
g->resolve_queue.append(tld);
|
||||
}
|
||||
if (is_export) {
|
||||
g->resolve_queue.append(tld);
|
||||
@ -2867,7 +2871,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (tld->name != nullptr) {
|
||||
auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
|
||||
if (entry) {
|
||||
Tld *other_tld = entry->value;
|
||||
@ -2875,9 +2879,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
|
||||
add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ZigType *type;
|
||||
if (get_primitive_type(g, tld->name, &type) != ErrorPrimitiveTypeNotFound) {
|
||||
add_node_error(g, tld->source_node,
|
||||
@ -2977,12 +2979,14 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
|
||||
break;
|
||||
}
|
||||
case NodeTypeUse:
|
||||
{
|
||||
g->use_queue.append(node);
|
||||
decls_scope->use_decls.append(node);
|
||||
break;
|
||||
}
|
||||
case NodeTypeUsingNamespace: {
|
||||
VisibMod visib_mod = node->data.using_namespace.visib_mod;
|
||||
TldUsingNamespace *tld_using_namespace = allocate<TldUsingNamespace>(1);
|
||||
init_tld(&tld_using_namespace->base, TldIdUsingNamespace, nullptr, visib_mod, node, &decls_scope->base);
|
||||
add_top_level_decl(g, decls_scope, &tld_using_namespace->base);
|
||||
decls_scope->use_decls.append(tld_using_namespace);
|
||||
break;
|
||||
}
|
||||
case NodeTypeTestDecl:
|
||||
preview_test_decl(g, node, decls_scope);
|
||||
break;
|
||||
@ -3266,6 +3270,118 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
|
||||
g->global_vars.append(tld_var);
|
||||
}
|
||||
|
||||
static void add_symbols_from_container(CodeGen *g, TldUsingNamespace *src_using_namespace,
|
||||
TldUsingNamespace *dst_using_namespace, ScopeDecls* dest_decls_scope)
|
||||
{
|
||||
if (src_using_namespace->base.resolution == TldResolutionUnresolved ||
|
||||
src_using_namespace->base.resolution == TldResolutionResolving)
|
||||
{
|
||||
assert(src_using_namespace->base.parent_scope->id == ScopeIdDecls);
|
||||
ScopeDecls *src_decls_scope = (ScopeDecls *)src_using_namespace->base.parent_scope;
|
||||
preview_use_decl(g, src_using_namespace, src_decls_scope);
|
||||
if (src_using_namespace != dst_using_namespace) {
|
||||
resolve_use_decl(g, src_using_namespace, src_decls_scope);
|
||||
}
|
||||
}
|
||||
|
||||
ConstExprValue *use_expr = src_using_namespace->using_namespace_value;
|
||||
if (type_is_invalid(use_expr->type)) {
|
||||
dest_decls_scope->any_imports_failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
dst_using_namespace->base.resolution = TldResolutionOk;
|
||||
|
||||
assert(use_expr->special != ConstValSpecialRuntime);
|
||||
|
||||
// The source scope for the imported symbols
|
||||
ScopeDecls *src_scope = get_container_scope(use_expr->data.x_type);
|
||||
// The top-level container where the symbols are defined, it's used in the
|
||||
// loop below in order to exclude the ones coming from an import statement
|
||||
ZigType *src_import = get_scope_import(&src_scope->base);
|
||||
assert(src_import != nullptr);
|
||||
|
||||
if (src_scope->any_imports_failed) {
|
||||
dest_decls_scope->any_imports_failed = true;
|
||||
}
|
||||
|
||||
auto it = src_scope->decl_table.entry_iterator();
|
||||
for (;;) {
|
||||
auto *entry = it.next();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
Buf *target_tld_name = entry->key;
|
||||
Tld *target_tld = entry->value;
|
||||
|
||||
if (target_tld->visib_mod == VisibModPrivate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_tld->import != src_import) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto existing_entry = dest_decls_scope->decl_table.put_unique(target_tld_name, target_tld);
|
||||
if (existing_entry) {
|
||||
Tld *existing_decl = existing_entry->value;
|
||||
if (existing_decl != target_tld) {
|
||||
ErrorMsg *msg = add_node_error(g, dst_using_namespace->base.source_node,
|
||||
buf_sprintf("import of '%s' overrides existing definition",
|
||||
buf_ptr(target_tld_name)));
|
||||
add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
|
||||
add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
|
||||
TldUsingNamespace *tld_using_namespace = src_scope->use_decls.at(i);
|
||||
if (tld_using_namespace->base.visib_mod != VisibModPrivate)
|
||||
add_symbols_from_container(g, tld_using_namespace, dst_using_namespace, dest_decls_scope);
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope) {
|
||||
if (tld_using_namespace->base.resolution == TldResolutionOk ||
|
||||
tld_using_namespace->base.resolution == TldResolutionInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
add_symbols_from_container(g, tld_using_namespace, tld_using_namespace, dest_decls_scope);
|
||||
}
|
||||
|
||||
static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) {
|
||||
if (using_namespace->base.resolution == TldResolutionOk ||
|
||||
using_namespace->base.resolution == TldResolutionInvalid ||
|
||||
using_namespace->using_namespace_value != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using_namespace->base.resolution = TldResolutionResolving;
|
||||
assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace);
|
||||
ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base,
|
||||
using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
|
||||
using_namespace->using_namespace_value = result;
|
||||
|
||||
if (type_is_invalid(result->type)) {
|
||||
dest_decls_scope->any_imports_failed = true;
|
||||
using_namespace->base.resolution = TldResolutionInvalid;
|
||||
using_namespace->using_namespace_value = &g->invalid_instruction->value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_container(result->data.x_type)) {
|
||||
add_node_error(g, using_namespace->base.source_node,
|
||||
buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name)));
|
||||
dest_decls_scope->any_imports_failed = true;
|
||||
using_namespace->base.resolution = TldResolutionInvalid;
|
||||
using_namespace->using_namespace_value = &g->invalid_instruction->value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
|
||||
if (tld->resolution != TldResolutionUnresolved)
|
||||
return;
|
||||
@ -3299,6 +3415,14 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
|
||||
resolve_decl_comptime(g, tld_comptime);
|
||||
break;
|
||||
}
|
||||
case TldIdUsingNamespace: {
|
||||
TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld;
|
||||
assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls);
|
||||
ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope;
|
||||
preview_use_decl(g, tld_using_namespace, dest_decls_scope);
|
||||
resolve_use_decl(g, tld_using_namespace, dest_decls_scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tld->resolution = TldResolutionOk;
|
||||
@ -3308,10 +3432,10 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
|
||||
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
|
||||
// resolve all the using_namespace decls
|
||||
for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
|
||||
AstNode *use_decl_node = decls_scope->use_decls.at(i);
|
||||
if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
|
||||
preview_use_decl(g, use_decl_node, decls_scope);
|
||||
resolve_use_decl(g, use_decl_node, decls_scope);
|
||||
TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i);
|
||||
if (tld_using_namespace->base.resolution == TldResolutionUnresolved) {
|
||||
preview_use_decl(g, tld_using_namespace, decls_scope);
|
||||
resolve_use_decl(g, tld_using_namespace, decls_scope);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3752,110 +3876,6 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
|
||||
analyze_fn_ir(g, fn_table_entry, return_type_node);
|
||||
}
|
||||
|
||||
static void add_symbols_from_container(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node, ScopeDecls* decls_scope) {
|
||||
if (src_use_node->data.using_namespace.resolution == TldResolutionUnresolved) {
|
||||
preview_use_decl(g, src_use_node, decls_scope);
|
||||
}
|
||||
|
||||
ConstExprValue *use_expr = src_use_node->data.using_namespace.using_namespace_value;
|
||||
if (type_is_invalid(use_expr->type)) {
|
||||
decls_scope->any_imports_failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
dst_use_node->data.using_namespace.resolution = TldResolutionOk;
|
||||
|
||||
assert(use_expr->special != ConstValSpecialRuntime);
|
||||
|
||||
// The source struct for the imported symbols
|
||||
ZigType *src_ty = use_expr->data.x_type;
|
||||
assert(src_ty);
|
||||
|
||||
if (!is_container(src_ty)) {
|
||||
add_node_error(g, dst_use_node,
|
||||
buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&src_ty->name)));
|
||||
decls_scope->any_imports_failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// The source scope for the imported symbols
|
||||
ScopeDecls *src_scope = get_container_scope(src_ty);
|
||||
// The top-level container where the symbols are defined, it's used in the
|
||||
// loop below in order to exclude the ones coming from an import statement
|
||||
ZigType *src_import = get_scope_import(&src_scope->base);
|
||||
assert(src_import != nullptr);
|
||||
|
||||
if (src_scope->any_imports_failed) {
|
||||
decls_scope->any_imports_failed = true;
|
||||
}
|
||||
|
||||
auto it = src_scope->decl_table.entry_iterator();
|
||||
for (;;) {
|
||||
auto *entry = it.next();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
Buf *target_tld_name = entry->key;
|
||||
Tld *target_tld = entry->value;
|
||||
|
||||
if (target_tld->visib_mod == VisibModPrivate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_tld->import != src_import) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto existing_entry = decls_scope->decl_table.put_unique(target_tld_name, target_tld);
|
||||
if (existing_entry) {
|
||||
Tld *existing_decl = existing_entry->value;
|
||||
if (existing_decl != target_tld) {
|
||||
ErrorMsg *msg = add_node_error(g, dst_use_node,
|
||||
buf_sprintf("import of '%s' overrides existing definition",
|
||||
buf_ptr(target_tld_name)));
|
||||
add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
|
||||
add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
|
||||
AstNode *use_decl_node = src_scope->use_decls.at(i);
|
||||
if (use_decl_node->data.using_namespace.visib_mod != VisibModPrivate)
|
||||
add_symbols_from_container(g, use_decl_node, dst_use_node, decls_scope);
|
||||
}
|
||||
}
|
||||
|
||||
void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
|
||||
assert(node->type == NodeTypeUse);
|
||||
|
||||
if (node->data.using_namespace.resolution == TldResolutionOk ||
|
||||
node->data.using_namespace.resolution == TldResolutionInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
add_symbols_from_container(g, node, node, decls_scope);
|
||||
}
|
||||
|
||||
void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
|
||||
assert(node->type == NodeTypeUse);
|
||||
|
||||
if (node->data.using_namespace.resolution == TldResolutionOk ||
|
||||
node->data.using_namespace.resolution == TldResolutionInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
node->data.using_namespace.resolution = TldResolutionResolving;
|
||||
ConstExprValue *result = analyze_const_value(g, &decls_scope->base,
|
||||
node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
|
||||
|
||||
if (type_is_invalid(result->type))
|
||||
decls_scope->any_imports_failed = true;
|
||||
|
||||
node->data.using_namespace.using_namespace_value = result;
|
||||
}
|
||||
|
||||
ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code,
|
||||
SourceKind source_kind)
|
||||
{
|
||||
@ -3975,18 +3995,8 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
|
||||
|
||||
void semantic_analyze(CodeGen *g) {
|
||||
while (g->resolve_queue_index < g->resolve_queue.length ||
|
||||
g->fn_defs_index < g->fn_defs.length ||
|
||||
g->use_queue_index < g->use_queue.length)
|
||||
g->fn_defs_index < g->fn_defs.length)
|
||||
{
|
||||
for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
|
||||
AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
|
||||
// Get the top-level scope where `using_namespace` is used
|
||||
ScopeDecls *decls_scope = get_container_scope(use_decl_node->owner);
|
||||
if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
|
||||
preview_use_decl(g, use_decl_node, decls_scope);
|
||||
resolve_use_decl(g, use_decl_node, decls_scope);
|
||||
}
|
||||
}
|
||||
for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
|
||||
Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
|
||||
AstNode *source_node = nullptr;
|
||||
|
||||
@ -86,8 +86,6 @@ bool is_array_ref(ZigType *type_entry);
|
||||
bool is_container_ref(ZigType *type_entry);
|
||||
bool is_valid_vector_elem_type(ZigType *elem_type);
|
||||
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||
void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
|
||||
void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
|
||||
ZigFn *scope_fn_entry(Scope *scope);
|
||||
ZigPackage *scope_package(Scope *scope);
|
||||
ZigType *get_scope_import(Scope *scope);
|
||||
|
||||
@ -193,8 +193,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "Symbol";
|
||||
case NodeTypePrefixOpExpr:
|
||||
return "PrefixOpExpr";
|
||||
case NodeTypeUse:
|
||||
return "Use";
|
||||
case NodeTypeUsingNamespace:
|
||||
return "UsingNamespace";
|
||||
case NodeTypeBoolLiteral:
|
||||
return "BoolLiteral";
|
||||
case NodeTypeNullLiteral:
|
||||
@ -319,6 +319,9 @@ static bool is_digit(uint8_t c) {
|
||||
}
|
||||
|
||||
static bool is_printable(uint8_t c) {
|
||||
if (c == 0) {
|
||||
return false;
|
||||
}
|
||||
static const uint8_t printables[] =
|
||||
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.~`!@#$%^&*()_-+=\\{}[];'\"?/<>,:";
|
||||
for (size_t i = 0; i < array_length(printables); i += 1) {
|
||||
@ -337,20 +340,12 @@ static void string_literal_escape(Buf *source, Buf *dest) {
|
||||
buf_append_str(dest, "\\\"");
|
||||
} else if (c == '\\') {
|
||||
buf_append_str(dest, "\\\\");
|
||||
} else if (c == '\a') {
|
||||
buf_append_str(dest, "\\a");
|
||||
} else if (c == '\b') {
|
||||
buf_append_str(dest, "\\b");
|
||||
} else if (c == '\f') {
|
||||
buf_append_str(dest, "\\f");
|
||||
} else if (c == '\n') {
|
||||
buf_append_str(dest, "\\n");
|
||||
} else if (c == '\r') {
|
||||
buf_append_str(dest, "\\r");
|
||||
} else if (c == '\t') {
|
||||
buf_append_str(dest, "\\t");
|
||||
} else if (c == '\v') {
|
||||
buf_append_str(dest, "\\v");
|
||||
} else if (is_printable(c)) {
|
||||
buf_append_char(dest, c);
|
||||
} else {
|
||||
@ -630,7 +625,19 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypeCharLiteral:
|
||||
{
|
||||
uint8_t c = node->data.char_literal.value;
|
||||
if (is_printable(c)) {
|
||||
if (c == '\'') {
|
||||
fprintf(ar->f, "'\\''");
|
||||
} else if (c == '\"') {
|
||||
fprintf(ar->f, "'\\\"'");
|
||||
} else if (c == '\\') {
|
||||
fprintf(ar->f, "'\\\\'");
|
||||
} else if (c == '\n') {
|
||||
fprintf(ar->f, "'\\n'");
|
||||
} else if (c == '\r') {
|
||||
fprintf(ar->f, "'\\r'");
|
||||
} else if (c == '\t') {
|
||||
fprintf(ar->f, "'\\t'");
|
||||
} else if (is_printable(c)) {
|
||||
fprintf(ar->f, "'%c'", c);
|
||||
} else {
|
||||
fprintf(ar->f, "'\\x%02x'", (int)c);
|
||||
@ -791,7 +798,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
AstNode *decls_node = node->data.container_decl.decls.at(decl_i);
|
||||
render_node_grouped(ar, decls_node);
|
||||
|
||||
if (decls_node->type == NodeTypeUse ||
|
||||
if (decls_node->type == NodeTypeUsingNamespace ||
|
||||
decls_node->type == NodeTypeVariableDeclaration ||
|
||||
decls_node->type == NodeTypeFnProto)
|
||||
{
|
||||
@ -1170,7 +1177,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeTestDecl:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeUsingNamespace:
|
||||
zig_panic("TODO more ast rendering");
|
||||
}
|
||||
}
|
||||
|
||||
293
src/codegen.cpp
293
src/codegen.cpp
@ -89,126 +89,6 @@ static const char *symbols_that_llvm_depends_on[] = {
|
||||
// TODO probably all of compiler-rt needs to go here
|
||||
};
|
||||
|
||||
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
|
||||
OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir,
|
||||
ZigLibCInstallation *libc, Buf *cache_dir)
|
||||
{
|
||||
CodeGen *g = allocate<CodeGen>(1);
|
||||
|
||||
codegen_add_time_event(g, "Initialize");
|
||||
|
||||
g->subsystem = TargetSubsystemAuto;
|
||||
g->libc = libc;
|
||||
g->zig_target = target;
|
||||
g->cache_dir = cache_dir;
|
||||
|
||||
if (override_lib_dir == nullptr) {
|
||||
g->zig_lib_dir = get_zig_lib_dir();
|
||||
} else {
|
||||
g->zig_lib_dir = override_lib_dir;
|
||||
}
|
||||
|
||||
if (override_std_dir == nullptr) {
|
||||
g->zig_std_dir = buf_alloc();
|
||||
os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
|
||||
} else {
|
||||
g->zig_std_dir = override_std_dir;
|
||||
}
|
||||
|
||||
g->zig_c_headers_dir = buf_alloc();
|
||||
os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
|
||||
|
||||
g->build_mode = build_mode;
|
||||
g->out_type = out_type;
|
||||
g->import_table.init(32);
|
||||
g->builtin_fn_table.init(32);
|
||||
g->primitive_type_table.init(32);
|
||||
g->type_table.init(32);
|
||||
g->fn_type_table.init(32);
|
||||
g->error_table.init(16);
|
||||
g->generic_table.init(16);
|
||||
g->llvm_fn_table.init(16);
|
||||
g->memoized_fn_eval_table.init(16);
|
||||
g->exported_symbol_names.init(8);
|
||||
g->external_prototypes.init(8);
|
||||
g->string_literals_table.init(16);
|
||||
g->type_info_cache.init(32);
|
||||
g->is_test_build = false;
|
||||
g->is_single_threaded = false;
|
||||
buf_resize(&g->global_asm, 0);
|
||||
|
||||
for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
|
||||
g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
|
||||
}
|
||||
|
||||
if (root_src_path) {
|
||||
Buf *root_pkg_path;
|
||||
Buf *rel_root_src_path;
|
||||
if (main_pkg_path == nullptr) {
|
||||
Buf *src_basename = buf_alloc();
|
||||
Buf *src_dir = buf_alloc();
|
||||
os_path_split(root_src_path, src_dir, src_basename);
|
||||
|
||||
if (buf_len(src_basename) == 0) {
|
||||
fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
|
||||
exit(1);
|
||||
}
|
||||
root_pkg_path = src_dir;
|
||||
rel_root_src_path = src_basename;
|
||||
} else {
|
||||
Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
|
||||
Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
|
||||
|
||||
if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
|
||||
fprintf(stderr, "Root source path '%s' outside main package path '%s'",
|
||||
buf_ptr(root_src_path), buf_ptr(main_pkg_path));
|
||||
exit(1);
|
||||
}
|
||||
root_pkg_path = main_pkg_path;
|
||||
rel_root_src_path = buf_create_from_mem(
|
||||
buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
|
||||
buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
|
||||
}
|
||||
|
||||
g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
|
||||
g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
|
||||
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
|
||||
} else {
|
||||
g->root_package = new_package(".", "", "");
|
||||
}
|
||||
|
||||
g->root_package->package_table.put(buf_create_from_str("root"), g->root_package);
|
||||
|
||||
g->zig_std_special_dir = buf_alloc();
|
||||
os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
|
||||
|
||||
assert(target != nullptr);
|
||||
if (!target->is_native) {
|
||||
g->each_lib_rpath = false;
|
||||
} else {
|
||||
g->each_lib_rpath = true;
|
||||
|
||||
if (target_os_is_darwin(g->zig_target->os)) {
|
||||
init_darwin_native(g);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (target_os_requires_libc(g->zig_target->os)) {
|
||||
g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
|
||||
g->link_libs_list.append(g->libc_link_lib);
|
||||
}
|
||||
|
||||
target_triple_llvm(&g->llvm_triple_str, g->zig_target);
|
||||
g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8;
|
||||
|
||||
if (!target_has_debug_info(g->zig_target)) {
|
||||
g->strip_debug_symbols = true;
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
|
||||
g->clang_argv = args;
|
||||
g->clang_argv_len = len;
|
||||
@ -233,10 +113,6 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc
|
||||
g->version_patch = patch;
|
||||
}
|
||||
|
||||
void codegen_set_is_test(CodeGen *g, bool is_test_build) {
|
||||
g->is_test_build = is_test_build;
|
||||
}
|
||||
|
||||
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) {
|
||||
g->emit_file_type = emit_file_type;
|
||||
}
|
||||
@ -4582,8 +4458,14 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
|
||||
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
|
||||
}
|
||||
|
||||
// When the cmpxchg is discarded, the result location will have no bits.
|
||||
if (!type_has_bits(instruction->result_loc->value.type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
|
||||
assert(type_has_bits(child_type));
|
||||
src_assert(result_loc != nullptr, instruction->base.source_node);
|
||||
src_assert(type_has_bits(child_type), instruction->base.source_node);
|
||||
|
||||
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
|
||||
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
|
||||
@ -5486,7 +5368,8 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
|
||||
LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
|
||||
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
|
||||
LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
|
||||
gen_store_untyped(g, vector, casted_ptr, get_ptr_align(g, instruction->result_loc->value.type), false);
|
||||
uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
|
||||
gen_store_untyped(g, vector, casted_ptr, alignment, false);
|
||||
return result_loc;
|
||||
}
|
||||
|
||||
@ -5499,7 +5382,10 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
|
||||
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
|
||||
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
|
||||
LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
|
||||
return gen_load_untyped(g, casted_ptr, 0, false, "");
|
||||
ZigType *array_type = instruction->array->value.type;
|
||||
assert(array_type->id == ZigTypeIdArray);
|
||||
uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
|
||||
return gen_load_untyped(g, casted_ptr, alignment, false, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
|
||||
@ -7994,6 +7880,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
return contents;
|
||||
}
|
||||
|
||||
static ZigPackage *create_test_runner_pkg(CodeGen *g) {
|
||||
return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
|
||||
}
|
||||
|
||||
static ZigPackage *create_panic_pkg(CodeGen *g) {
|
||||
return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
|
||||
}
|
||||
|
||||
static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
if (g->std_package == nullptr)
|
||||
return ErrorNone;
|
||||
@ -8078,8 +7972,16 @@ static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("std"), g->std_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("root"),
|
||||
g->is_test_build ? g->test_runner_package : g->root_package);
|
||||
ZigPackage *root_pkg;
|
||||
if (g->is_test_build) {
|
||||
if (g->test_runner_package == nullptr) {
|
||||
g->test_runner_package = create_test_runner_pkg(g);
|
||||
}
|
||||
root_pkg = g->test_runner_package;
|
||||
} else {
|
||||
root_pkg = g->root_package;
|
||||
}
|
||||
g->std_package->package_table.put(buf_create_from_str("root"), root_pkg);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents,
|
||||
SourceKindPkgMain);
|
||||
|
||||
@ -8586,14 +8488,6 @@ static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) {
|
||||
return package;
|
||||
}
|
||||
|
||||
static ZigPackage *create_test_runner_pkg(CodeGen *g) {
|
||||
return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
|
||||
}
|
||||
|
||||
static ZigPackage *create_panic_pkg(CodeGen *g) {
|
||||
return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
|
||||
}
|
||||
|
||||
static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
Error err;
|
||||
|
||||
@ -8643,7 +8537,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true);
|
||||
|
||||
update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice);
|
||||
g->test_runner_package = create_test_runner_pkg(g);
|
||||
assert(g->test_runner_package != nullptr);
|
||||
g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
|
||||
}
|
||||
|
||||
@ -9757,7 +9651,8 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
|
||||
ZigLibCInstallation *libc)
|
||||
{
|
||||
CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path());
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path(),
|
||||
false);
|
||||
child_gen->disable_gen_h = true;
|
||||
child_gen->want_stack_check = WantStackCheckDisabled;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
@ -9784,3 +9679,123 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
|
||||
return child_gen;
|
||||
}
|
||||
|
||||
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
|
||||
OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir,
|
||||
ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build)
|
||||
{
|
||||
CodeGen *g = allocate<CodeGen>(1);
|
||||
|
||||
codegen_add_time_event(g, "Initialize");
|
||||
|
||||
g->subsystem = TargetSubsystemAuto;
|
||||
g->libc = libc;
|
||||
g->zig_target = target;
|
||||
g->cache_dir = cache_dir;
|
||||
|
||||
if (override_lib_dir == nullptr) {
|
||||
g->zig_lib_dir = get_zig_lib_dir();
|
||||
} else {
|
||||
g->zig_lib_dir = override_lib_dir;
|
||||
}
|
||||
|
||||
if (override_std_dir == nullptr) {
|
||||
g->zig_std_dir = buf_alloc();
|
||||
os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
|
||||
} else {
|
||||
g->zig_std_dir = override_std_dir;
|
||||
}
|
||||
|
||||
g->zig_c_headers_dir = buf_alloc();
|
||||
os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
|
||||
|
||||
g->build_mode = build_mode;
|
||||
g->out_type = out_type;
|
||||
g->import_table.init(32);
|
||||
g->builtin_fn_table.init(32);
|
||||
g->primitive_type_table.init(32);
|
||||
g->type_table.init(32);
|
||||
g->fn_type_table.init(32);
|
||||
g->error_table.init(16);
|
||||
g->generic_table.init(16);
|
||||
g->llvm_fn_table.init(16);
|
||||
g->memoized_fn_eval_table.init(16);
|
||||
g->exported_symbol_names.init(8);
|
||||
g->external_prototypes.init(8);
|
||||
g->string_literals_table.init(16);
|
||||
g->type_info_cache.init(32);
|
||||
g->is_test_build = is_test_build;
|
||||
g->is_single_threaded = false;
|
||||
buf_resize(&g->global_asm, 0);
|
||||
|
||||
for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
|
||||
g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
|
||||
}
|
||||
|
||||
if (root_src_path) {
|
||||
Buf *root_pkg_path;
|
||||
Buf *rel_root_src_path;
|
||||
if (main_pkg_path == nullptr) {
|
||||
Buf *src_basename = buf_alloc();
|
||||
Buf *src_dir = buf_alloc();
|
||||
os_path_split(root_src_path, src_dir, src_basename);
|
||||
|
||||
if (buf_len(src_basename) == 0) {
|
||||
fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
|
||||
exit(1);
|
||||
}
|
||||
root_pkg_path = src_dir;
|
||||
rel_root_src_path = src_basename;
|
||||
} else {
|
||||
Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
|
||||
Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
|
||||
|
||||
if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
|
||||
fprintf(stderr, "Root source path '%s' outside main package path '%s'",
|
||||
buf_ptr(root_src_path), buf_ptr(main_pkg_path));
|
||||
exit(1);
|
||||
}
|
||||
root_pkg_path = main_pkg_path;
|
||||
rel_root_src_path = buf_create_from_mem(
|
||||
buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
|
||||
buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
|
||||
}
|
||||
|
||||
g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
|
||||
g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
|
||||
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
|
||||
} else {
|
||||
g->root_package = new_package(".", "", "");
|
||||
}
|
||||
|
||||
g->root_package->package_table.put(buf_create_from_str("root"), g->root_package);
|
||||
|
||||
g->zig_std_special_dir = buf_alloc();
|
||||
os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
|
||||
|
||||
assert(target != nullptr);
|
||||
if (!target->is_native) {
|
||||
g->each_lib_rpath = false;
|
||||
} else {
|
||||
g->each_lib_rpath = true;
|
||||
|
||||
if (target_os_is_darwin(g->zig_target->os)) {
|
||||
init_darwin_native(g);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (target_os_requires_libc(g->zig_target->os)) {
|
||||
g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
|
||||
g->link_libs_list.append(g->libc_link_lib);
|
||||
}
|
||||
|
||||
target_triple_llvm(&g->llvm_triple_str, g->zig_target);
|
||||
g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8;
|
||||
|
||||
if (!target_has_debug_info(g->zig_target)) {
|
||||
g->strip_debug_symbols = true;
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
@ -18,14 +18,13 @@
|
||||
|
||||
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
|
||||
OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir,
|
||||
ZigLibCInstallation *libc, Buf *cache_dir);
|
||||
ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build);
|
||||
|
||||
CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
|
||||
ZigLibCInstallation *libc);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_is_test(CodeGen *codegen, bool is_test);
|
||||
void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
|
||||
|
||||
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type);
|
||||
|
||||
134
src/ir.cpp
134
src/ir.cpp
@ -189,7 +189,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
|
||||
static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
|
||||
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime,
|
||||
bool non_null_comptime, bool allow_discard);
|
||||
static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *base_ptr, bool safety_check_on, bool initializing);
|
||||
static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
@ -197,7 +198,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
|
||||
static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *base_ptr, bool initializing);
|
||||
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value);
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const);
|
||||
static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
|
||||
LVal lval, ResultLoc *parent_result_loc);
|
||||
@ -1612,7 +1613,7 @@ static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode
|
||||
return &unreachable_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *ptr, IrInstruction *value)
|
||||
{
|
||||
IrInstructionStorePtr *instruction = ir_build_instruction<IrInstructionStorePtr>(irb, scope, source_node);
|
||||
@ -1624,7 +1625,7 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
|
||||
ir_ref_instruction(ptr, irb->current_basic_block);
|
||||
ir_ref_instruction(value, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
return instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
@ -4001,12 +4002,20 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
|
||||
|
||||
static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
|
||||
IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
|
||||
|
||||
if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
|
||||
if (lvalue == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = lvalue;
|
||||
ir_ref_instruction(lvalue, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, node, &result_loc_inst->base);
|
||||
|
||||
IrInstruction *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone,
|
||||
&result_loc_inst->base);
|
||||
if (rvalue == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
|
||||
return ir_build_const_void(irb, scope, node);
|
||||
}
|
||||
|
||||
@ -6042,6 +6051,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
|
||||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = field_ptr;
|
||||
result_loc_inst->base.allow_write_through_const = true;
|
||||
ir_ref_instruction(field_ptr, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
|
||||
|
||||
@ -6080,6 +6090,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
|
||||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = elem_ptr;
|
||||
result_loc_inst->base.allow_write_through_const = true;
|
||||
ir_ref_instruction(elem_ptr, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
|
||||
|
||||
@ -6637,7 +6648,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
|
||||
ir_set_cursor_at_end_and_append_block(irb, continue_block);
|
||||
IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
|
||||
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
|
||||
ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true;
|
||||
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
|
||||
|
||||
IrInstruction *else_result = nullptr;
|
||||
@ -8430,7 +8441,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
switch (node->type) {
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeUsingNamespace:
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeStructField:
|
||||
@ -11155,7 +11166,8 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
|
||||
}
|
||||
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true,
|
||||
false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -11615,7 +11627,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so
|
||||
}
|
||||
IrInstruction *result_loc_inst = nullptr;
|
||||
if (result_loc != nullptr) {
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -11658,7 +11670,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
|
||||
IrInstruction *result_loc_inst;
|
||||
if (handle_is_ptr(wanted_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -11743,7 +11755,7 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
|
||||
IrInstruction *result_loc_inst;
|
||||
if (handle_is_ptr(wanted_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -11816,7 +11828,8 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
|
||||
|
||||
IrInstruction *result_loc;
|
||||
if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) {
|
||||
result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, false);
|
||||
result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true,
|
||||
false, true);
|
||||
} else {
|
||||
result_loc = nullptr;
|
||||
}
|
||||
@ -11860,7 +11873,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
|
||||
if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
|
||||
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -12516,7 +12530,8 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *
|
||||
if (result_loc == nullptr) {
|
||||
result_loc = no_result_loc();
|
||||
}
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -13097,7 +13112,8 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
||||
IrInstruction *result_loc_inst;
|
||||
if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
@ -14597,7 +14613,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
|
||||
for (uint64_t x = 0; x < mult_amt; x += 1) {
|
||||
for (uint64_t y = 0; y < old_array_len; y += 1) {
|
||||
copy_const_val(&out_val->data.x_array.data.s_none.elements[i],
|
||||
&array_val->data.x_array.data.s_none.elements[y], true);
|
||||
&array_val->data.x_array.data.s_none.elements[y], false);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
@ -14834,7 +14850,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
|
||||
// instruction.
|
||||
assert(deref->value.special != ConstValSpecialRuntime);
|
||||
var_ptr->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
|
||||
ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false);
|
||||
}
|
||||
|
||||
if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) {
|
||||
@ -15352,7 +15368,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
|
||||
if (peer_parent->peers.length == 1) {
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
value_type, value, force_runtime, non_null_comptime);
|
||||
value_type, value, force_runtime, non_null_comptime, true);
|
||||
result_peer->suspend_pos.basic_block_index = SIZE_MAX;
|
||||
result_peer->suspend_pos.instruction_index = SIZE_MAX;
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
@ -15372,7 +15388,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
if (peer_parent->skipped) {
|
||||
if (non_null_comptime) {
|
||||
return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
value_type, value, force_runtime, non_null_comptime);
|
||||
value_type, value, force_runtime, non_null_comptime, true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -15390,7 +15406,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
}
|
||||
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime);
|
||||
peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime, true);
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
|
||||
{
|
||||
@ -15440,7 +15456,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
}
|
||||
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent,
|
||||
dest_type, bitcasted_value, force_runtime, non_null_comptime);
|
||||
dest_type, bitcasted_value, force_runtime, non_null_comptime, true);
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
|
||||
{
|
||||
@ -15469,8 +15485,15 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
|
||||
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime,
|
||||
bool non_null_comptime)
|
||||
bool non_null_comptime, bool allow_discard)
|
||||
{
|
||||
if (!allow_discard && result_loc_pass1->id == ResultLocIdInstruction &&
|
||||
instr_is_comptime(result_loc_pass1->source_instruction) &&
|
||||
result_loc_pass1->source_instruction->value.type->id == ZigTypeIdPointer &&
|
||||
result_loc_pass1->source_instruction->value.data.x_ptr.special == ConstPtrSpecialDiscard)
|
||||
{
|
||||
result_loc_pass1 = no_result_loc();
|
||||
}
|
||||
IrInstruction *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type,
|
||||
value, force_runtime, non_null_comptime);
|
||||
if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type)))
|
||||
@ -15525,7 +15548,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
|
||||
if (type_is_invalid(implicit_elem_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
implicit_elem_type, nullptr, false, true);
|
||||
implicit_elem_type, nullptr, false, true, true);
|
||||
if (result_loc != nullptr)
|
||||
return result_loc;
|
||||
|
||||
@ -15534,7 +15557,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
|
||||
instruction->result_loc->id == ResultLocIdReturn)
|
||||
{
|
||||
result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(),
|
||||
implicit_elem_type, nullptr, false, true);
|
||||
implicit_elem_type, nullptr, false, true, true);
|
||||
if (result_loc != nullptr &&
|
||||
(type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
|
||||
{
|
||||
@ -15623,7 +15646,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc
|
||||
ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(),
|
||||
async_return_type, nullptr, true, true);
|
||||
async_return_type, nullptr, true, true, false);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -15841,7 +15864,7 @@ no_mem_slot:
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value)
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const)
|
||||
{
|
||||
assert(ptr->value.type->id == ZigTypeIdPointer);
|
||||
|
||||
@ -15857,7 +15880,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
|
||||
|
||||
ZigType *child_type = ptr->value.type->data.pointer.child_type;
|
||||
|
||||
if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
|
||||
if (ptr->value.type->data.pointer.is_const && !allow_write_through_const) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
@ -15936,10 +15959,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
|
||||
break;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
|
||||
ptr, value);
|
||||
result->value.type = ira->codegen->builtin_types.entry_void;
|
||||
return result;
|
||||
IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, ptr, value);
|
||||
return &store_ptr->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
|
||||
@ -16382,7 +16404,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(impl_fn_type_id->return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
impl_fn_type_id->return_type, nullptr, true, true);
|
||||
impl_fn_type_id->return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||
|
||||
instr_is_unreachable(result_loc)))
|
||||
{
|
||||
@ -16504,7 +16526,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
return_type, nullptr, true, true);
|
||||
return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -17020,7 +17042,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
|
||||
|
||||
// In case resolving the parent activates a suspend, do it now
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent,
|
||||
peer_parent->resolved_type, nullptr, false, false);
|
||||
peer_parent->resolved_type, nullptr, false, false, true);
|
||||
if (parent_result_loc != nullptr &&
|
||||
(type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc)))
|
||||
{
|
||||
@ -17477,6 +17499,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
|
||||
return result;
|
||||
} else if (is_slice(array_type)) {
|
||||
ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
|
||||
ir_assert(ptr_field != nullptr, &elem_ptr_instruction->base);
|
||||
if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
|
||||
elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false,
|
||||
@ -17663,7 +17686,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (type_is_invalid(struct_val->type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (struct_val->special == ConstValSpecialUndef && initializing) {
|
||||
if (initializing && struct_val->special == ConstValSpecialUndef) {
|
||||
struct_val->data.x_struct.fields = create_const_vals(struct_type->data.structure.src_field_count);
|
||||
struct_val->special = ConstValSpecialStatic;
|
||||
for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
|
||||
@ -17847,6 +17870,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_
|
||||
switch (tld->id) {
|
||||
case TldIdContainer:
|
||||
case TldIdCompTime:
|
||||
case TldIdUsingNamespace:
|
||||
zig_unreachable();
|
||||
case TldIdVar:
|
||||
{
|
||||
@ -18260,7 +18284,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
|
||||
if (type_is_invalid(value->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
|
||||
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value, instruction->allow_write_through_const);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
|
||||
@ -18763,7 +18787,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
|
||||
if (optional_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (initializing && optional_val->special == ConstValSpecialUndef) {
|
||||
if (initializing) {
|
||||
switch (type_has_one_possible_value(ira->codegen, child_type)) {
|
||||
case OnePossibleValueInvalid:
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -19668,7 +19692,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
|
||||
|
||||
IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, instruction, field, result_loc,
|
||||
container_type, true);
|
||||
ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst);
|
||||
ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst, false);
|
||||
if (instr_is_comptime(field_ptr) && field_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
|
||||
const_ptrs.append(field_ptr);
|
||||
} else {
|
||||
@ -19685,7 +19709,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
|
||||
IrInstruction *field_result_loc = const_ptrs.at(i);
|
||||
IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc, nullptr);
|
||||
field_result_loc->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref);
|
||||
ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19812,7 +19836,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
|
||||
assert(elem_result_loc->value.special == ConstValSpecialStatic);
|
||||
IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr);
|
||||
elem_result_loc->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref);
|
||||
ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21531,7 +21555,7 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
|
||||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(result_type)) {
|
||||
result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
result_type, nullptr, true, false);
|
||||
result_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -21788,7 +21812,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
|
||||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
dest_slice_type, nullptr, true, false);
|
||||
dest_slice_type, nullptr, true, false, true);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -21865,7 +21889,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
|
||||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
dest_slice_type, nullptr, true, false);
|
||||
dest_slice_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -22607,7 +22631,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
|
||||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
return_type, nullptr, true, false);
|
||||
return_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
@ -23259,7 +23283,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
|
||||
ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
|
||||
if (err_union_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (err_union_val->special == ConstValSpecialUndef && initializing) {
|
||||
if (initializing && err_union_val->special == ConstValSpecialUndef) {
|
||||
ConstExprValue *vals = create_const_vals(2);
|
||||
ConstExprValue *err_set_val = &vals[0];
|
||||
ConstExprValue *payload_val = &vals[1];
|
||||
@ -24734,10 +24758,11 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
|
||||
operand_type->data.integral.bit_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
|
||||
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
|
||||
if (operand_type->data.integral.bit_count > max_atomic_bits) {
|
||||
ir_add_error(ira, op,
|
||||
buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
|
||||
operand_type->data.integral.bit_count));
|
||||
buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type",
|
||||
max_atomic_bits, operand_type->data.integral.bit_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (!is_power_of_2(operand_type->data.integral.bit_count)) {
|
||||
@ -25386,7 +25411,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
|
||||
|
||||
bool was_written = instruction->result_loc->written;
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
value->value.type, value, false, false);
|
||||
value->value.type, value, false, false, true);
|
||||
if (result_loc != nullptr) {
|
||||
if (type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -25394,7 +25419,8 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
|
||||
return result_loc;
|
||||
|
||||
if (!was_written) {
|
||||
IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
|
||||
IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,
|
||||
instruction->result_loc->allow_write_through_const);
|
||||
if (type_is_invalid(store_ptr->value.type)) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
@ -25418,7 +25444,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst
|
||||
return operand;
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base,
|
||||
&instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false);
|
||||
&instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false, true);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
|
||||
return result_loc;
|
||||
|
||||
|
||||
@ -583,7 +583,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe,
|
||||
BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir);
|
||||
BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir, false);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->enable_time_report = timing_info;
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
@ -1011,7 +1011,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
case CmdBuiltin: {
|
||||
CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
|
||||
out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr);
|
||||
out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr, false);
|
||||
codegen_set_strip(g, strip);
|
||||
for (size_t i = 0; i < link_libs.length; i += 1) {
|
||||
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
|
||||
@ -1115,7 +1115,7 @@ int main(int argc, char **argv) {
|
||||
cache_dir_buf = buf_create_from_str(cache_dir);
|
||||
}
|
||||
CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
|
||||
override_lib_dir, override_std_dir, libc, cache_dir_buf);
|
||||
override_lib_dir, override_std_dir, libc, cache_dir_buf, cmd == CmdTest);
|
||||
if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2);
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->want_pic = want_pic;
|
||||
@ -1125,7 +1125,6 @@ int main(int argc, char **argv) {
|
||||
g->enable_time_report = timing_info;
|
||||
codegen_set_out_name(g, buf_out_name);
|
||||
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
|
||||
codegen_set_is_test(g, cmd == CmdTest);
|
||||
g->want_single_threaded = want_single_threaded;
|
||||
codegen_set_linker_script(g, linker_script);
|
||||
g->version_script_path = version_script;
|
||||
|
||||
@ -676,7 +676,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) {
|
||||
AstNode *expr = ast_expect(pc, ast_parse_expr);
|
||||
expect_token(pc, TokenIdSemicolon);
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeUse, usingnamespace);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeUsingNamespace, usingnamespace);
|
||||
res->data.using_namespace.visib_mod = visib_mod;
|
||||
res->data.using_namespace.expr = expr;
|
||||
return res;
|
||||
@ -2938,7 +2938,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeUnwrapOptional:
|
||||
visit_field(&node->data.unwrap_optional.expr, visit, context);
|
||||
break;
|
||||
case NodeTypeUse:
|
||||
case NodeTypeUsingNamespace:
|
||||
visit_field(&node->data.using_namespace.expr, visit, context);
|
||||
break;
|
||||
case NodeTypeBoolLiteral:
|
||||
|
||||
@ -878,6 +878,72 @@ uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch) {
|
||||
switch (arch) {
|
||||
case ZigLLVM_UnknownArch:
|
||||
zig_unreachable();
|
||||
|
||||
case ZigLLVM_avr:
|
||||
case ZigLLVM_msp430:
|
||||
return 16;
|
||||
|
||||
case ZigLLVM_arc:
|
||||
case ZigLLVM_arm:
|
||||
case ZigLLVM_armeb:
|
||||
case ZigLLVM_hexagon:
|
||||
case ZigLLVM_le32:
|
||||
case ZigLLVM_mips:
|
||||
case ZigLLVM_mipsel:
|
||||
case ZigLLVM_nvptx:
|
||||
case ZigLLVM_ppc:
|
||||
case ZigLLVM_r600:
|
||||
case ZigLLVM_riscv32:
|
||||
case ZigLLVM_sparc:
|
||||
case ZigLLVM_sparcel:
|
||||
case ZigLLVM_tce:
|
||||
case ZigLLVM_tcele:
|
||||
case ZigLLVM_thumb:
|
||||
case ZigLLVM_thumbeb:
|
||||
case ZigLLVM_x86:
|
||||
case ZigLLVM_xcore:
|
||||
case ZigLLVM_amdil:
|
||||
case ZigLLVM_hsail:
|
||||
case ZigLLVM_spir:
|
||||
case ZigLLVM_kalimba:
|
||||
case ZigLLVM_lanai:
|
||||
case ZigLLVM_shave:
|
||||
case ZigLLVM_wasm32:
|
||||
case ZigLLVM_renderscript32:
|
||||
return 32;
|
||||
|
||||
case ZigLLVM_aarch64:
|
||||
case ZigLLVM_aarch64_be:
|
||||
case ZigLLVM_aarch64_32:
|
||||
case ZigLLVM_amdgcn:
|
||||
case ZigLLVM_bpfel:
|
||||
case ZigLLVM_bpfeb:
|
||||
case ZigLLVM_le64:
|
||||
case ZigLLVM_mips64:
|
||||
case ZigLLVM_mips64el:
|
||||
case ZigLLVM_nvptx64:
|
||||
case ZigLLVM_ppc64:
|
||||
case ZigLLVM_ppc64le:
|
||||
case ZigLLVM_riscv64:
|
||||
case ZigLLVM_sparcv9:
|
||||
case ZigLLVM_systemz:
|
||||
case ZigLLVM_amdil64:
|
||||
case ZigLLVM_hsail64:
|
||||
case ZigLLVM_spir64:
|
||||
case ZigLLVM_wasm64:
|
||||
case ZigLLVM_renderscript64:
|
||||
return 64;
|
||||
|
||||
case ZigLLVM_x86_64:
|
||||
return 128;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
switch (target->os) {
|
||||
case OsFreestanding:
|
||||
@ -1524,9 +1590,9 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
|
||||
case OsKFreeBSD:
|
||||
case OsNetBSD:
|
||||
case OsHurd:
|
||||
case OsWindows:
|
||||
return ZigLLVM_GNU;
|
||||
case OsUefi:
|
||||
case OsWindows:
|
||||
return ZigLLVM_MSVC;
|
||||
case OsLinux:
|
||||
case OsWASI:
|
||||
|
||||
@ -195,6 +195,7 @@ const char *target_arch_musl_name(ZigLLVM_ArchType arch);
|
||||
bool target_supports_libunwind(const ZigTarget *target);
|
||||
|
||||
uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch);
|
||||
uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
|
||||
|
||||
size_t target_libc_count(void);
|
||||
void target_libc_enum(size_t index, ZigTarget *out_target);
|
||||
|
||||
@ -43,7 +43,7 @@ ATTRIBUTE_NORETURN
|
||||
ATTRIBUTE_PRINTF(1, 2)
|
||||
void zig_panic(const char *format, ...);
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ enum ZigClangAPValueKind {
|
||||
struct ZigClangAPValue {
|
||||
enum ZigClangAPValueKind Kind;
|
||||
// experimentally-derived size of clang::APValue::DataType
|
||||
#if defined(WIN32) && defined(_MSC_VER)
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
char Data[52];
|
||||
#else
|
||||
char Data[68];
|
||||
|
||||
@ -41,9 +41,11 @@ pub const Builder = struct {
|
||||
env_map: *BufMap,
|
||||
top_level_steps: ArrayList(*TopLevelStep),
|
||||
install_prefix: ?[]const u8,
|
||||
search_prefixes: ArrayList([]const u8),
|
||||
dest_dir: ?[]const u8,
|
||||
lib_dir: ?[]const u8,
|
||||
exe_dir: ?[]const u8,
|
||||
install_path: []const u8,
|
||||
search_prefixes: ArrayList([]const u8),
|
||||
installed_files: ArrayList(InstalledFile),
|
||||
build_root: []const u8,
|
||||
cache_root: []const u8,
|
||||
@ -125,10 +127,11 @@ pub const Builder = struct {
|
||||
.top_level_steps = ArrayList(*TopLevelStep).init(allocator),
|
||||
.default_step = undefined,
|
||||
.env_map = env_map,
|
||||
.install_prefix = null,
|
||||
.search_prefixes = ArrayList([]const u8).init(allocator),
|
||||
.install_prefix = null,
|
||||
.lib_dir = null,
|
||||
.exe_dir = null,
|
||||
.dest_dir = env_map.get("DESTDIR"),
|
||||
.installed_files = ArrayList(InstalledFile).init(allocator),
|
||||
.install_tls = TopLevelStep{
|
||||
.step = Step.initNoOp("install", allocator),
|
||||
@ -142,6 +145,7 @@ pub const Builder = struct {
|
||||
.is_release = false,
|
||||
.override_std_dir = null,
|
||||
.override_lib_dir = null,
|
||||
.install_path = undefined,
|
||||
};
|
||||
try self.top_level_steps.append(&self.install_tls);
|
||||
try self.top_level_steps.append(&self.uninstall_tls);
|
||||
@ -164,14 +168,19 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
fn resolveInstallPrefix(self: *Builder) void {
|
||||
const prefix = if (self.install_prefix) |prefix| prefix else blk: {
|
||||
const prefix = self.cache_root;
|
||||
self.install_prefix = prefix;
|
||||
break :blk prefix;
|
||||
};
|
||||
|
||||
self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ prefix, "lib" }) catch unreachable;
|
||||
self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ prefix, "bin" }) catch unreachable;
|
||||
if (self.dest_dir) |dest_dir| {
|
||||
const install_prefix = self.install_prefix orelse "/usr";
|
||||
self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable;
|
||||
} else {
|
||||
const install_prefix = self.install_prefix orelse blk: {
|
||||
const p = self.cache_root;
|
||||
self.install_prefix = p;
|
||||
break :blk p;
|
||||
};
|
||||
self.install_path = install_prefix;
|
||||
}
|
||||
self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "lib" }) catch unreachable;
|
||||
self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "bin" }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
@ -796,11 +805,7 @@ pub const Builder = struct {
|
||||
return name;
|
||||
}
|
||||
const full_path = try fs.path.join(self.allocator, [_][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
|
||||
if (fs.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
continue;
|
||||
}
|
||||
return fs.realpathAlloc(self.allocator, full_path) catch continue;
|
||||
}
|
||||
}
|
||||
if (self.env_map.get("PATH")) |PATH| {
|
||||
@ -808,14 +813,10 @@ pub const Builder = struct {
|
||||
if (fs.path.isAbsolute(name)) {
|
||||
return name;
|
||||
}
|
||||
var it = mem.tokenize(PATH, []u8{fs.path.delimiter});
|
||||
var it = mem.tokenize(PATH, [_]u8{fs.path.delimiter});
|
||||
while (it.next()) |path| {
|
||||
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (fs.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
continue;
|
||||
}
|
||||
return fs.realpathAlloc(self.allocator, full_path) catch continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -825,11 +826,7 @@ pub const Builder = struct {
|
||||
}
|
||||
for (paths) |path| {
|
||||
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (fs.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
continue;
|
||||
}
|
||||
return fs.realpathAlloc(self.allocator, full_path) catch continue;
|
||||
}
|
||||
}
|
||||
return error.FileNotFound;
|
||||
@ -884,7 +881,7 @@ pub const Builder = struct {
|
||||
|
||||
fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
|
||||
const base_dir = switch (dir) {
|
||||
.Prefix => self.install_prefix.?,
|
||||
.Prefix => self.install_path,
|
||||
.Bin => self.exe_dir.?,
|
||||
.Lib => self.lib_dir.?,
|
||||
};
|
||||
@ -895,6 +892,15 @@ pub const Builder = struct {
|
||||
}
|
||||
};
|
||||
|
||||
test "builder.findProgram compiles" {
|
||||
//allocator: *Allocator,
|
||||
//zig_exe: []const u8,
|
||||
//build_root: []const u8,
|
||||
//cache_root: []const u8,
|
||||
const builder = try Builder.create(std.heap.direct_allocator, "zig", "zig-cache", "zig-cache");
|
||||
_ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null;
|
||||
}
|
||||
|
||||
pub const Version = struct {
|
||||
major: u32,
|
||||
minor: u32,
|
||||
@ -1113,6 +1119,9 @@ pub const Target = union(enum) {
|
||||
}
|
||||
|
||||
pub fn libPrefix(self: Target) []const u8 {
|
||||
if (self.isWasm()) {
|
||||
return "";
|
||||
}
|
||||
switch (self.getAbi()) {
|
||||
.msvc => return "",
|
||||
else => return "lib",
|
||||
@ -1255,6 +1264,8 @@ pub const LibExeObjStep = struct {
|
||||
libc_file: ?[]const u8 = null,
|
||||
target_glibc: ?Version = null,
|
||||
|
||||
valgrind_support: ?bool = null,
|
||||
|
||||
const LinkObject = union(enum) {
|
||||
StaticPath: []const u8,
|
||||
OtherStep: *LibExeObjStep,
|
||||
@ -1791,7 +1802,7 @@ pub const LibExeObjStep = struct {
|
||||
try zig_args.append("--bundle-compiler-rt");
|
||||
}
|
||||
if (self.disable_stack_probing) {
|
||||
try zig_args.append("--disable-stack-probing");
|
||||
try zig_args.append("-fno-stack-check");
|
||||
}
|
||||
|
||||
switch (self.target) {
|
||||
@ -1882,6 +1893,14 @@ pub const LibExeObjStep = struct {
|
||||
try zig_args.append("--system-linker-hack");
|
||||
}
|
||||
|
||||
if (self.valgrind_support) |valgrind_support| {
|
||||
if (valgrind_support) {
|
||||
try zig_args.append("--enable-valgrind");
|
||||
} else {
|
||||
try zig_args.append("--disable-valgrind");
|
||||
}
|
||||
}
|
||||
|
||||
if (self.override_std_dir) |dir| {
|
||||
try zig_args.append("--override-std-dir");
|
||||
try zig_args.append(builder.pathFromRoot(dir));
|
||||
|
||||
52
std/coff.zig
52
std/coff.zig
@ -19,6 +19,7 @@ const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
|
||||
const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
|
||||
|
||||
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
|
||||
const IMAGE_DEBUG_TYPE_CODEVIEW = 2;
|
||||
const DEBUG_DIRECTORY = 6;
|
||||
|
||||
pub const CoffError = error{
|
||||
@ -28,6 +29,7 @@ pub const CoffError = error{
|
||||
MissingCoffSection,
|
||||
};
|
||||
|
||||
// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
pub const Coff = struct {
|
||||
in_file: File,
|
||||
allocator: *mem.Allocator,
|
||||
@ -120,16 +122,43 @@ pub const Coff = struct {
|
||||
|
||||
pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
|
||||
try self.loadSections();
|
||||
const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
|
||||
|
||||
// The linker puts a chunk that contains the .pdb path right after the
|
||||
// debug_directory.
|
||||
const header = blk: {
|
||||
if (self.getSection(".buildid")) |section| {
|
||||
break :blk section.header;
|
||||
} else if (self.getSection(".rdata")) |section| {
|
||||
break :blk section.header;
|
||||
} else {
|
||||
return error.MissingCoffSection;
|
||||
}
|
||||
};
|
||||
|
||||
const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
|
||||
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
|
||||
try self.in_file.seekTo(file_offset + debug_dir.size);
|
||||
|
||||
var file_stream = self.in_file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
try self.in_file.seekTo(file_offset);
|
||||
|
||||
// Find the correct DebugDirectoryEntry, and where its data is stored.
|
||||
// It can be in any section.
|
||||
const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
|
||||
var i: u32 = 0;
|
||||
blk: while (i < debug_dir_entry_count) : (i += 1) {
|
||||
const debug_dir_entry = try in.readStruct(DebugDirectoryEntry);
|
||||
if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {
|
||||
for (self.sections.toSlice()) |*section| {
|
||||
const section_start = section.header.virtual_address;
|
||||
const section_size = section.header.misc.virtual_size;
|
||||
const rva = debug_dir_entry.address_of_raw_data;
|
||||
const offset = rva - section_start;
|
||||
if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
|
||||
try self.in_file.seekTo(section.header.pointer_to_raw_data + offset);
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cv_signature: [4]u8 = undefined; // CodeView signature
|
||||
try in.readNoEof(cv_signature[0..]);
|
||||
@ -141,7 +170,7 @@ pub const Coff = struct {
|
||||
|
||||
// Finally read the null-terminated string.
|
||||
var byte = try in.readByte();
|
||||
var i: usize = 0;
|
||||
i = 0;
|
||||
while (byte != 0 and i < buffer.len) : (i += 1) {
|
||||
buffer[i] = byte;
|
||||
byte = try in.readByte();
|
||||
@ -170,7 +199,7 @@ pub const Coff = struct {
|
||||
try self.sections.append(Section{
|
||||
.header = SectionHeader{
|
||||
.name = name,
|
||||
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
|
||||
.misc = SectionHeader.Misc{ .virtual_size = try in.readIntLittle(u32) },
|
||||
.virtual_address = try in.readIntLittle(u32),
|
||||
.size_of_raw_data = try in.readIntLittle(u32),
|
||||
.pointer_to_raw_data = try in.readIntLittle(u32),
|
||||
@ -214,6 +243,17 @@ const OptionalHeader = struct {
|
||||
data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
|
||||
};
|
||||
|
||||
const DebugDirectoryEntry = packed struct {
|
||||
characteristiccs: u32,
|
||||
time_date_stamp: u32,
|
||||
major_version: u16,
|
||||
minor_version: u16,
|
||||
@"type": u32,
|
||||
size_of_data: u32,
|
||||
address_of_raw_data: u32,
|
||||
pointer_to_raw_data: u32,
|
||||
};
|
||||
|
||||
pub const Section = struct {
|
||||
header: SectionHeader,
|
||||
};
|
||||
|
||||
@ -12,6 +12,7 @@ const coff = std.coff;
|
||||
const pdb = std.pdb;
|
||||
const ArrayList = std.ArrayList;
|
||||
const builtin = @import("builtin");
|
||||
const root = @import("root");
|
||||
const maxInt = std.math.maxInt;
|
||||
const File = std.fs.File;
|
||||
const windows = std.os.windows;
|
||||
@ -217,6 +218,12 @@ var panicking: u8 = 0; // TODO make this a bool
|
||||
pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
|
||||
@setCold(true);
|
||||
|
||||
if (enable_segfault_handler) {
|
||||
// If a segfault happens while panicking, we want it to actually segfault, not trigger
|
||||
// the handler.
|
||||
resetSegfaultHandler();
|
||||
}
|
||||
|
||||
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
|
||||
// Panicked during a panic.
|
||||
|
||||
@ -368,7 +375,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
||||
const obj_basename = fs.path.basename(mod.obj_file_name);
|
||||
|
||||
var symbol_i: usize = 0;
|
||||
const symbol_name = while (symbol_i != mod.symbols.len) {
|
||||
const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
|
||||
const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
|
||||
if (prefix.RecordLen < 2)
|
||||
return error.InvalidDebugInfo;
|
||||
@ -851,8 +858,10 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
||||
const age = try pdb_stream.stream.readIntLittle(u32);
|
||||
var guid: [16]u8 = undefined;
|
||||
try pdb_stream.stream.readNoEof(guid[0..]);
|
||||
if (version != 20000404) // VC70, only value observed by LLVM team
|
||||
return error.UnknownPDBVersion;
|
||||
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
|
||||
return error.InvalidDebugInfo;
|
||||
return error.PDBMismatch;
|
||||
// We validated the executable and pdb match.
|
||||
|
||||
const string_table_index = str_tab_index: {
|
||||
@ -896,13 +905,18 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
||||
return error.MissingDebugInfo;
|
||||
};
|
||||
|
||||
di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
|
||||
di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.MissingDebugInfo;
|
||||
di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
|
||||
|
||||
const dbi = di.pdb.dbi;
|
||||
|
||||
// Dbi Header
|
||||
const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
|
||||
if (dbi_stream_header.VersionHeader != 19990903) // V70, only value observed by LLVM team
|
||||
return error.UnknownPDBVersion;
|
||||
if (dbi_stream_header.Age != age)
|
||||
return error.UnmatchingPDB;
|
||||
|
||||
const mod_info_size = dbi_stream_header.ModInfoSize;
|
||||
const section_contrib_size = dbi_stream_header.SectionContributionSize;
|
||||
|
||||
@ -2312,39 +2326,58 @@ fn getDebugInfoAllocator() *mem.Allocator {
|
||||
|
||||
/// Whether or not the current target can print useful debug information when a segfault occurs.
|
||||
pub const have_segfault_handling_support = (builtin.arch == builtin.Arch.x86_64 and builtin.os == .linux) or builtin.os == .windows;
|
||||
pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
|
||||
root.enable_segfault_handler
|
||||
else
|
||||
runtime_safety and have_segfault_handling_support;
|
||||
|
||||
pub fn maybeEnableSegfaultHandler() void {
|
||||
if (enable_segfault_handler) {
|
||||
std.debug.attachSegfaultHandler();
|
||||
}
|
||||
}
|
||||
|
||||
var windows_segfault_handle: ?windows.HANDLE = null;
|
||||
|
||||
/// Attaches a global SIGSEGV handler which calls @panic("segmentation fault");
|
||||
pub fn attachSegfaultHandler() void {
|
||||
if (!have_segfault_handling_support) {
|
||||
@compileError("segfault handler not supported for this target");
|
||||
}
|
||||
switch (builtin.os) {
|
||||
.linux => {
|
||||
var act = os.Sigaction{
|
||||
.sigaction = handleSegfaultLinux,
|
||||
.mask = os.empty_sigset,
|
||||
.flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
|
||||
};
|
||||
|
||||
os.sigaction(os.SIGSEGV, &act, null);
|
||||
},
|
||||
.windows => {
|
||||
_ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||
},
|
||||
else => unreachable,
|
||||
if (windows.is_the_target) {
|
||||
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||
return;
|
||||
}
|
||||
var act = os.Sigaction{
|
||||
.sigaction = handleSegfaultLinux,
|
||||
.mask = os.empty_sigset,
|
||||
.flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
|
||||
};
|
||||
|
||||
os.sigaction(os.SIGSEGV, &act, null);
|
||||
}
|
||||
|
||||
extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
|
||||
// Reset to the default handler so that if a segfault happens in this handler it will crash
|
||||
// the process. Also when this handler returns, the original instruction will be repeated
|
||||
// and the resulting segfault will crash the process rather than continually dump stack traces.
|
||||
fn resetSegfaultHandler() void {
|
||||
if (windows.is_the_target) {
|
||||
if (windows_segfault_handle) |handle| {
|
||||
assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
|
||||
windows_segfault_handle = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var act = os.Sigaction{
|
||||
.sigaction = os.SIG_DFL,
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
os.sigaction(os.SIGSEGV, &act, null);
|
||||
}
|
||||
|
||||
extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
|
||||
// Reset to the default handler so that if a segfault happens in this handler it will crash
|
||||
// the process. Also when this handler returns, the original instruction will be repeated
|
||||
// and the resulting segfault will crash the process rather than continually dump stack traces.
|
||||
resetSegfaultHandler();
|
||||
|
||||
const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
|
||||
const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);
|
||||
|
||||
21
std/fmt.zig
21
std/fmt.zig
@ -374,9 +374,10 @@ pub fn formatType(
|
||||
return output(context, "{ ... }");
|
||||
}
|
||||
comptime var field_i = 0;
|
||||
try output(context, "{");
|
||||
inline while (field_i < @memberCount(T)) : (field_i += 1) {
|
||||
if (field_i == 0) {
|
||||
try output(context, "{ .");
|
||||
try output(context, " .");
|
||||
} else {
|
||||
try output(context, ", .");
|
||||
}
|
||||
@ -425,6 +426,9 @@ pub fn formatType(
|
||||
if (info.child == u8) {
|
||||
return formatText(value, fmt, options, context, Errors, output);
|
||||
}
|
||||
if (value.len == 0) {
|
||||
return format(context, Errors, output, "[0]{}", @typeName(T.Child));
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
|
||||
},
|
||||
.Fn => {
|
||||
@ -1439,6 +1443,21 @@ test "struct.self-referential" {
|
||||
try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
|
||||
}
|
||||
|
||||
test "struct.zero-size" {
|
||||
const A = struct {
|
||||
fn foo() void {}
|
||||
};
|
||||
const B = struct {
|
||||
a: A,
|
||||
c: i32,
|
||||
};
|
||||
|
||||
const a = A{};
|
||||
const b = B{ .a = a, .c = 0 };
|
||||
|
||||
try testFmt("B{ .a = A{ }, .c = 0 }", "{}", b);
|
||||
}
|
||||
|
||||
test "bytes.hex" {
|
||||
const some_bytes = "\xCA\xFE\xBA\xBE";
|
||||
try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
|
||||
|
||||
21
std/os.zig
21
std/os.zig
@ -133,6 +133,11 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
|
||||
const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
|
||||
defer close(fd);
|
||||
|
||||
const st = try fstat(fd);
|
||||
if (!S_ISCHR(st.mode)) {
|
||||
return error.NoDevice;
|
||||
}
|
||||
|
||||
const stream = &std.fs.File.openHandle(fd).inStream().stream;
|
||||
stream.readNoEof(buf) catch return error.Unexpected;
|
||||
}
|
||||
@ -2053,6 +2058,22 @@ pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
|
||||
/// Otherwise use `access` or `accessC`.
|
||||
/// TODO currently this ignores `mode`.
|
||||
pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!void {
|
||||
const ret = try windows.GetFileAttributesW(path);
|
||||
if (ret != windows.INVALID_FILE_ATTRIBUTES) {
|
||||
return;
|
||||
}
|
||||
switch (windows.kernel32.GetLastError()) {
|
||||
windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
|
||||
windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
|
||||
windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
|
||||
else => |err| return windows.unexpectedError(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub const PipeError = error{
|
||||
SystemFdQuotaExceeded,
|
||||
ProcessFdQuotaExceeded,
|
||||
|
||||
@ -1116,3 +1116,62 @@ pub const stack_t = extern struct {
|
||||
ss_size: isize,
|
||||
ss_flags: i32,
|
||||
};
|
||||
|
||||
pub const S_IFMT = 0o170000;
|
||||
|
||||
pub const S_IFIFO = 0o010000;
|
||||
pub const S_IFCHR = 0o020000;
|
||||
pub const S_IFDIR = 0o040000;
|
||||
pub const S_IFBLK = 0o060000;
|
||||
pub const S_IFREG = 0o100000;
|
||||
pub const S_IFLNK = 0o120000;
|
||||
pub const S_IFSOCK = 0o140000;
|
||||
pub const S_IFWHT = 0o160000;
|
||||
|
||||
pub const S_ISUID = 0o4000;
|
||||
pub const S_ISGID = 0o2000;
|
||||
pub const S_ISVTX = 0o1000;
|
||||
pub const S_IRWXU = 0o700;
|
||||
pub const S_IRUSR = 0o400;
|
||||
pub const S_IWUSR = 0o200;
|
||||
pub const S_IXUSR = 0o100;
|
||||
pub const S_IRWXG = 0o070;
|
||||
pub const S_IRGRP = 0o040;
|
||||
pub const S_IWGRP = 0o020;
|
||||
pub const S_IXGRP = 0o010;
|
||||
pub const S_IRWXO = 0o007;
|
||||
pub const S_IROTH = 0o004;
|
||||
pub const S_IWOTH = 0o002;
|
||||
pub const S_IXOTH = 0o001;
|
||||
|
||||
pub fn S_ISFIFO(m: u32) bool {
|
||||
return m & S_IFMT == S_IFIFO;
|
||||
}
|
||||
|
||||
pub fn S_ISCHR(m: u32) bool {
|
||||
return m & S_IFMT == S_IFCHR;
|
||||
}
|
||||
|
||||
pub fn S_ISDIR(m: u32) bool {
|
||||
return m & S_IFMT == S_IFDIR;
|
||||
}
|
||||
|
||||
pub fn S_ISBLK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFBLK;
|
||||
}
|
||||
|
||||
pub fn S_ISREG(m: u32) bool {
|
||||
return m & S_IFMT == S_IFREG;
|
||||
}
|
||||
|
||||
pub fn S_ISLNK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFLNK;
|
||||
}
|
||||
|
||||
pub fn S_ISSOCK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFSOCK;
|
||||
}
|
||||
|
||||
pub fn S_IWHT(m: u32) bool {
|
||||
return m & S_IFMT == S_IFWHT;
|
||||
}
|
||||
|
||||
@ -876,3 +876,62 @@ pub const stack_t = extern struct {
|
||||
ss_size: isize,
|
||||
ss_flags: i32,
|
||||
};
|
||||
|
||||
pub const S_IFMT = 0o170000;
|
||||
|
||||
pub const S_IFIFO = 0o010000;
|
||||
pub const S_IFCHR = 0o020000;
|
||||
pub const S_IFDIR = 0o040000;
|
||||
pub const S_IFBLK = 0o060000;
|
||||
pub const S_IFREG = 0o100000;
|
||||
pub const S_IFLNK = 0o120000;
|
||||
pub const S_IFSOCK = 0o140000;
|
||||
pub const S_IFWHT = 0o160000;
|
||||
|
||||
pub const S_ISUID = 0o4000;
|
||||
pub const S_ISGID = 0o2000;
|
||||
pub const S_ISVTX = 0o1000;
|
||||
pub const S_IRWXU = 0o700;
|
||||
pub const S_IRUSR = 0o400;
|
||||
pub const S_IWUSR = 0o200;
|
||||
pub const S_IXUSR = 0o100;
|
||||
pub const S_IRWXG = 0o070;
|
||||
pub const S_IRGRP = 0o040;
|
||||
pub const S_IWGRP = 0o020;
|
||||
pub const S_IXGRP = 0o010;
|
||||
pub const S_IRWXO = 0o007;
|
||||
pub const S_IROTH = 0o004;
|
||||
pub const S_IWOTH = 0o002;
|
||||
pub const S_IXOTH = 0o001;
|
||||
|
||||
pub fn S_ISFIFO(m: u32) bool {
|
||||
return m & S_IFMT == S_IFIFO;
|
||||
}
|
||||
|
||||
pub fn S_ISCHR(m: u32) bool {
|
||||
return m & S_IFMT == S_IFCHR;
|
||||
}
|
||||
|
||||
pub fn S_ISDIR(m: u32) bool {
|
||||
return m & S_IFMT == S_IFDIR;
|
||||
}
|
||||
|
||||
pub fn S_ISBLK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFBLK;
|
||||
}
|
||||
|
||||
pub fn S_ISREG(m: u32) bool {
|
||||
return m & S_IFMT == S_IFREG;
|
||||
}
|
||||
|
||||
pub fn S_ISLNK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFLNK;
|
||||
}
|
||||
|
||||
pub fn S_ISSOCK(m: u32) bool {
|
||||
return m & S_IFMT == S_IFSOCK;
|
||||
}
|
||||
|
||||
pub fn S_IWHT(m: u32) bool {
|
||||
return m & S_IFMT == S_IFWHT;
|
||||
}
|
||||
|
||||
@ -5,3 +5,4 @@ pub const is_the_target = switch (builtin.os) {
|
||||
else => false,
|
||||
};
|
||||
pub usingnamespace std.c;
|
||||
pub usingnamespace @import("bits.zig");
|
||||
@ -2,3 +2,4 @@ const std = @import("../std.zig");
|
||||
const builtin = @import("builtin");
|
||||
pub const is_the_target = builtin.os == .freebsd;
|
||||
pub usingnamespace std.c;
|
||||
pub usingnamespace @import("bits.zig");
|
||||
@ -1,6 +1,7 @@
|
||||
usingnamespace @import("bits.zig");
|
||||
|
||||
pub extern "kernel32" stdcallcc fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) ?*c_void;
|
||||
pub extern "kernel32" stdcallcc fn RemoveVectoredExceptionHandler(Handle: HANDLE) c_ulong;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
|
||||
|
||||
|
||||
117
std/pdb.zig
117
std/pdb.zig
@ -499,45 +499,78 @@ const Msf = struct {
|
||||
|
||||
const superblock = try in.readStruct(SuperBlock);
|
||||
|
||||
// Sanity checks
|
||||
if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
if (superblock.FreeBlockMapBlock != 1 and superblock.FreeBlockMapBlock != 2)
|
||||
return error.InvalidDebugInfo;
|
||||
if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
|
||||
return error.InvalidDebugInfo;
|
||||
switch (superblock.BlockSize) {
|
||||
// llvm only supports 4096 but we can handle any of these values
|
||||
512, 1024, 2048, 4096 => {},
|
||||
else => return error.InvalidDebugInfo,
|
||||
}
|
||||
|
||||
if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
|
||||
return error.InvalidDebugInfo;
|
||||
const dir_block_count = blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize);
|
||||
if (dir_block_count > superblock.BlockSize / @sizeOf(u32))
|
||||
return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.
|
||||
|
||||
self.directory = try MsfStream.init(
|
||||
try file.seekTo(superblock.BlockSize * superblock.BlockMapAddr);
|
||||
var dir_blocks = try allocator.alloc(u32, dir_block_count);
|
||||
for (dir_blocks) |*b| {
|
||||
b.* = try in.readIntLittle(u32);
|
||||
}
|
||||
self.directory = MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
|
||||
superblock.BlockSize * superblock.BlockMapAddr,
|
||||
file,
|
||||
allocator,
|
||||
dir_blocks,
|
||||
);
|
||||
|
||||
const begin = self.directory.pos;
|
||||
const stream_count = try self.directory.stream.readIntLittle(u32);
|
||||
|
||||
const stream_sizes = try allocator.alloc(u32, stream_count);
|
||||
for (stream_sizes) |*s| {
|
||||
defer allocator.free(stream_sizes);
|
||||
|
||||
// Microsoft's implementation uses u32(-1) for inexistant streams.
|
||||
// These streams are not used, but still participate in the file
|
||||
// and must be taken into account when resolving stream indices.
|
||||
const Nil = 0xFFFFFFFF;
|
||||
for (stream_sizes) |*s, i| {
|
||||
const size = try self.directory.stream.readIntLittle(u32);
|
||||
s.* = blockCountFromSize(size, superblock.BlockSize);
|
||||
s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);
|
||||
}
|
||||
|
||||
self.streams = try allocator.alloc(MsfStream, stream_count);
|
||||
for (self.streams) |*stream, i| {
|
||||
stream.* = try MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
stream_sizes[i],
|
||||
// MsfStream.init expects the file to be at the part where it reads [N]u32
|
||||
try file.getPos(),
|
||||
file,
|
||||
allocator,
|
||||
);
|
||||
const size = stream_sizes[i];
|
||||
if (size == 0) {
|
||||
stream.* = MsfStream{
|
||||
.blocks = [_]u32{},
|
||||
};
|
||||
} else {
|
||||
var blocks = try allocator.alloc(u32, size);
|
||||
var j: u32 = 0;
|
||||
while (j < size) : (j += 1) {
|
||||
const block_id = try self.directory.stream.readIntLittle(u32);
|
||||
const n = (block_id % superblock.BlockSize);
|
||||
// 0 is for SuperBlock, 1 and 2 for FPMs.
|
||||
if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())
|
||||
return error.InvalidBlockIndex;
|
||||
blocks[j] = block_id;
|
||||
}
|
||||
|
||||
stream.* = MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
file,
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const end = self.directory.pos;
|
||||
if (end - begin != superblock.NumDirectoryBytes)
|
||||
return error.InvalidStreamDirectory;
|
||||
}
|
||||
};
|
||||
|
||||
@ -574,7 +607,6 @@ const SuperBlock = packed struct {
|
||||
NumDirectoryBytes: u32,
|
||||
|
||||
Unknown: u32,
|
||||
|
||||
/// The index of a block within the MSF file. At this block is an array of
|
||||
/// ulittle32_t’s listing the blocks that the stream directory resides on.
|
||||
/// For large MSF files, the stream directory (which describes the block
|
||||
@ -584,45 +616,41 @@ const SuperBlock = packed struct {
|
||||
/// and the stream directory itself can be stitched together accordingly.
|
||||
/// The number of ulittle32_t’s in this array is given by
|
||||
/// ceil(NumDirectoryBytes / BlockSize).
|
||||
// Note: microsoft-pdb code actually suggests this is a variable-length
|
||||
// array. If the indices of blocks occupied by the Stream Directory didn't
|
||||
// fit in one page, there would be other u32 following it.
|
||||
// This would mean the Stream Directory is bigger than BlockSize / sizeof(u32)
|
||||
// blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't
|
||||
// implement it so we're kind of safe making this assumption for now.
|
||||
BlockMapAddr: u32,
|
||||
};
|
||||
|
||||
const MsfStream = struct {
|
||||
in_file: File,
|
||||
pos: u64,
|
||||
blocks: []u32,
|
||||
block_size: u32,
|
||||
in_file: File = undefined,
|
||||
pos: u64 = undefined,
|
||||
blocks: []u32 = undefined,
|
||||
block_size: u32 = undefined,
|
||||
|
||||
/// Implementation of InStream trait for Pdb.MsfStream
|
||||
stream: Stream,
|
||||
stream: Stream = undefined,
|
||||
|
||||
pub const Error = @typeOf(read).ReturnType.ErrorSet;
|
||||
pub const Stream = io.InStream(Error);
|
||||
|
||||
fn init(block_size: u32, block_count: u32, pos: u64, file: File, allocator: *mem.Allocator) !MsfStream {
|
||||
var stream = MsfStream{
|
||||
fn init(block_size: u32, file: File, blocks: []u32) MsfStream {
|
||||
const stream = MsfStream{
|
||||
.in_file = file,
|
||||
.pos = 0,
|
||||
.blocks = try allocator.alloc(u32, block_count),
|
||||
.blocks = blocks,
|
||||
.block_size = block_size,
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
|
||||
var file_stream = file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
try file.seekTo(pos);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < block_count) : (i += 1) {
|
||||
stream.blocks[i] = try in.readIntLittle(u32);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
|
||||
var list = ArrayList(u8).init(allocator);
|
||||
defer list.deinit();
|
||||
while (true) {
|
||||
const byte = try self.stream.readByte();
|
||||
if (byte == 0) {
|
||||
@ -642,11 +670,12 @@ const MsfStream = struct {
|
||||
const in = &file_stream.stream;
|
||||
|
||||
var size: usize = 0;
|
||||
for (buffer) |*byte| {
|
||||
byte.* = try in.readByte();
|
||||
|
||||
offset += 1;
|
||||
size += 1;
|
||||
var rem_buffer = buffer;
|
||||
while (size < buffer.len) {
|
||||
const size_to_read = math.min(self.block_size - offset, rem_buffer.len);
|
||||
size += try in.read(rem_buffer[0..size_to_read]);
|
||||
rem_buffer = buffer[size..];
|
||||
offset += size_to_read;
|
||||
|
||||
// If we're at the end of a block, go to the next one.
|
||||
if (offset == self.block_size) {
|
||||
@ -657,8 +686,8 @@ const MsfStream = struct {
|
||||
}
|
||||
}
|
||||
|
||||
self.pos += size;
|
||||
return size;
|
||||
self.pos += buffer.len;
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
fn seekBy(self: *MsfStream, len: i64) !void {
|
||||
|
||||
@ -146,13 +146,12 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
|
||||
error.Unexpected => return error.EnvironmentVariableNotFound,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
if (result > buf.len) {
|
||||
buf = try allocator.realloc(buf, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
|
||||
return std.unicode.utf16leToUtf8Alloc(allocator, buf[0..result]) catch |err| switch (err) {
|
||||
error.DanglingSurrogateHalf => return error.InvalidUtf8,
|
||||
error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
|
||||
error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
|
||||
|
||||
54
std/rb.zig
54
std/rb.zig
@ -93,7 +93,8 @@ pub const Node = struct {
|
||||
comptime {
|
||||
assert(@alignOf(*Node) >= 2);
|
||||
}
|
||||
return @intToPtr(*Node, node.parent_and_color & ~mask);
|
||||
const maybe_ptr = node.parent_and_color & ~mask;
|
||||
return if (maybe_ptr == 0) null else @intToPtr(*Node, maybe_ptr);
|
||||
}
|
||||
|
||||
fn setColor(node: *Node, color: Color) void {
|
||||
@ -233,10 +234,13 @@ pub const Tree = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// lookup searches for the value of key, using binary search. It will
|
||||
/// return a pointer to the node if it is there, otherwise it will return null.
|
||||
/// Complexity guaranteed O(log n), where n is the number of nodes book-kept
|
||||
/// by tree.
|
||||
pub fn lookup(tree: *Tree, key: *Node) ?*Node {
|
||||
var parent: *Node = undefined;
|
||||
var parent: ?*Node = undefined;
|
||||
var is_left: bool = undefined;
|
||||
|
||||
return doLookup(key, tree, &parent, &is_left);
|
||||
}
|
||||
|
||||
@ -544,3 +548,47 @@ test "rb" {
|
||||
num = testGetNumber(num.node.next().?);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test "inserting and looking up" {
|
||||
var tree: Tree = undefined;
|
||||
tree.init(testCompare);
|
||||
var number: testNumber = undefined;
|
||||
number.value = 1000;
|
||||
_ = tree.insert(&number.node);
|
||||
var dup: testNumber = undefined;
|
||||
//Assert that tuples with identical value fields finds the same pointer
|
||||
dup.value = 1000;
|
||||
assert(tree.lookup(&dup.node) == &number.node);
|
||||
//Assert that tuples with identical values do not clobber when inserted.
|
||||
_ = tree.insert(&dup.node);
|
||||
assert(tree.lookup(&dup.node) == &number.node);
|
||||
assert(tree.lookup(&number.node) != &dup.node);
|
||||
assert(testGetNumber(tree.lookup(&dup.node).?).value == testGetNumber(&dup.node).value);
|
||||
//Assert that if looking for a non-existing value, return null.
|
||||
var non_existing_value: testNumber = undefined;
|
||||
non_existing_value.value = 1234;
|
||||
assert(tree.lookup(&non_existing_value.node) == null);
|
||||
}
|
||||
|
||||
test "multiple inserts, followed by calling first and last" {
|
||||
var tree: Tree = undefined;
|
||||
tree.init(testCompare);
|
||||
var zeroth: testNumber = undefined;
|
||||
zeroth.value = 0;
|
||||
var first: testNumber = undefined;
|
||||
first.value = 1;
|
||||
var second: testNumber = undefined;
|
||||
second.value = 2;
|
||||
var third: testNumber = undefined;
|
||||
third.value = 3;
|
||||
_ = tree.insert(&zeroth.node);
|
||||
_ = tree.insert(&first.node);
|
||||
_ = tree.insert(&second.node);
|
||||
_ = tree.insert(&third.node);
|
||||
assert(testGetNumber(tree.first().?).value == 0);
|
||||
assert(testGetNumber(tree.last().?).value == 3);
|
||||
var lookupNode: testNumber = undefined;
|
||||
lookupNode.value = 3;
|
||||
assert(tree.lookup(&lookupNode.node) == &third.node);
|
||||
}
|
||||
|
||||
@ -77,16 +77,20 @@ const Allocator = std.mem.Allocator;
|
||||
pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
const prealloc_exp = blk: {
|
||||
// we don't use the prealloc_exp constant when prealloc_item_count is 0.
|
||||
assert(prealloc_item_count != 0);
|
||||
assert(std.math.isPowerOfTwo(prealloc_item_count));
|
||||
|
||||
const value = std.math.log2_int(usize, prealloc_item_count);
|
||||
break :blk @typeOf(1)(value);
|
||||
};
|
||||
const ShelfIndex = std.math.Log2Int(usize);
|
||||
|
||||
const prealloc_exp: ShelfIndex = blk: {
|
||||
// we don't use the prealloc_exp constant when prealloc_item_count is 0
|
||||
// but lazy-init may still be triggered by other code so supply a value
|
||||
if (prealloc_item_count == 0) {
|
||||
break :blk 0;
|
||||
} else {
|
||||
assert(std.math.isPowerOfTwo(prealloc_item_count));
|
||||
const value = std.math.log2_int(usize, prealloc_item_count);
|
||||
break :blk value;
|
||||
}
|
||||
};
|
||||
|
||||
prealloc_segment: [prealloc_item_count]T,
|
||||
dynamic_segments: [][*]T,
|
||||
allocator: *Allocator,
|
||||
@ -157,11 +161,12 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
|
||||
|
||||
/// Grows or shrinks capacity to match usage.
|
||||
pub fn setCapacity(self: *Self, new_capacity: usize) !void {
|
||||
if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
|
||||
return self.shrinkCapacity(new_capacity);
|
||||
} else {
|
||||
return self.growCapacity(new_capacity);
|
||||
if (prealloc_item_count != 0) {
|
||||
if (new_capacity <= usize(1) << (prealloc_exp + @intCast(ShelfIndex, self.dynamic_segments.len))) {
|
||||
return self.shrinkCapacity(new_capacity);
|
||||
}
|
||||
}
|
||||
return self.growCapacity(new_capacity);
|
||||
}
|
||||
|
||||
/// Only grows capacity, or retains current capacity
|
||||
@ -399,4 +404,6 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
|
||||
testing.expect(item == i);
|
||||
list.shrinkCapacity(list.len);
|
||||
}
|
||||
|
||||
try list.setCapacity(0);
|
||||
}
|
||||
|
||||
@ -24,16 +24,6 @@ comptime {
|
||||
}
|
||||
}
|
||||
|
||||
fn enableSegfaultHandler() void {
|
||||
const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
|
||||
root.enable_segfault_handler
|
||||
else
|
||||
std.debug.runtime_safety and std.debug.have_segfault_handling_support;
|
||||
if (enable_segfault_handler) {
|
||||
std.debug.attachSegfaultHandler();
|
||||
}
|
||||
}
|
||||
|
||||
extern fn wasm_freestanding_start() void {
|
||||
_ = callMain();
|
||||
}
|
||||
@ -45,13 +35,13 @@ nakedcc fn _start() noreturn {
|
||||
|
||||
switch (builtin.arch) {
|
||||
.x86_64 => {
|
||||
argc_ptr = asm ("lea (%%rsp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
argc_ptr = asm (""
|
||||
: [argc] "={rsp}" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
.i386 => {
|
||||
argc_ptr = asm ("lea (%%esp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
argc_ptr = asm (""
|
||||
: [argc] "={esp}" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
.aarch64, .aarch64_be => {
|
||||
@ -77,7 +67,7 @@ extern fn WinMainCRTStartup() noreturn {
|
||||
_ = @import("start_windows_tls.zig");
|
||||
}
|
||||
|
||||
enableSegfaultHandler();
|
||||
std.debug.maybeEnableSegfaultHandler();
|
||||
|
||||
std.os.windows.kernel32.ExitProcess(callMain());
|
||||
}
|
||||
@ -118,7 +108,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
|
||||
std.os.argv = argv[0..argc];
|
||||
std.os.environ = envp;
|
||||
|
||||
enableSegfaultHandler();
|
||||
std.debug.maybeEnableSegfaultHandler();
|
||||
|
||||
return callMain();
|
||||
}
|
||||
|
||||
@ -105,6 +105,7 @@ test "std" {
|
||||
_ = @import("packed_int_array.zig");
|
||||
_ = @import("priority_queue.zig");
|
||||
_ = @import("rand.zig");
|
||||
_ = @import("rb.zig");
|
||||
_ = @import("sort.zig");
|
||||
_ = @import("testing.zig");
|
||||
_ = @import("thread.zig");
|
||||
|
||||
209
std/zig/ast.zig
209
std/zig/ast.zig
@ -159,101 +159,99 @@ pub const Error = union(enum) {
|
||||
|
||||
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
|
||||
switch (self.*) {
|
||||
// TODO https://github.com/ziglang/zig/issues/683
|
||||
@TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedContainerMembers => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedStringLiteral => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPubItem => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedIdentifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedStatement => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedVarDecl => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedReturnType => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedSemiOrElse => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedLabelOrLBrace => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedLBrace => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedTypeExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedParamType => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedParamList => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPayload => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedLoopExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedSuffixOp => |*x| return x.render(tokens, stream),
|
||||
.InvalidToken => |*x| return x.render(tokens, stream),
|
||||
.ExpectedContainerMembers => |*x| return x.render(tokens, stream),
|
||||
.ExpectedStringLiteral => |*x| return x.render(tokens, stream),
|
||||
.ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
|
||||
.ExpectedPubItem => |*x| return x.render(tokens, stream),
|
||||
.ExpectedIdentifier => |*x| return x.render(tokens, stream),
|
||||
.ExpectedStatement => |*x| return x.render(tokens, stream),
|
||||
.ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
|
||||
.ExpectedVarDecl => |*x| return x.render(tokens, stream),
|
||||
.ExpectedReturnType => |*x| return x.render(tokens, stream),
|
||||
.ExpectedAggregateKw => |*x| return x.render(tokens, stream),
|
||||
.UnattachedDocComment => |*x| return x.render(tokens, stream),
|
||||
.ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSemiOrElse => |*x| return x.render(tokens, stream),
|
||||
.ExpectedLabelOrLBrace => |*x| return x.render(tokens, stream),
|
||||
.ExpectedLBrace => |*x| return x.render(tokens, stream),
|
||||
.ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
|
||||
.ExpectedLabelable => |*x| return x.render(tokens, stream),
|
||||
.ExpectedInlinable => |*x| return x.render(tokens, stream),
|
||||
.ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
|
||||
.ExpectedCall => |*x| return x.render(tokens, stream),
|
||||
.ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
|
||||
.ExtraAlignQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraConstQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExpectedTypeExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedParamType => |*x| return x.render(tokens, stream),
|
||||
.ExpectedExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedToken => |*x| return x.render(tokens, stream),
|
||||
.ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
|
||||
.ExpectedParamList => |*x| return x.render(tokens, stream),
|
||||
.ExpectedPayload => |*x| return x.render(tokens, stream),
|
||||
.ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
|
||||
.ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
|
||||
.ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
|
||||
.ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedLoopExpr => |*x| return x.render(tokens, stream),
|
||||
.ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSuffixOp => |*x| return x.render(tokens, stream),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loc(self: *const Error) TokenIndex {
|
||||
switch (self.*) {
|
||||
// TODO https://github.com/ziglang/zig/issues/683
|
||||
@TagType(Error).InvalidToken => |x| return x.token,
|
||||
@TagType(Error).ExpectedContainerMembers => |x| return x.token,
|
||||
@TagType(Error).ExpectedStringLiteral => |x| return x.token,
|
||||
@TagType(Error).ExpectedIntegerLiteral => |x| return x.token,
|
||||
@TagType(Error).ExpectedPubItem => |x| return x.token,
|
||||
@TagType(Error).ExpectedIdentifier => |x| return x.token,
|
||||
@TagType(Error).ExpectedStatement => |x| return x.token,
|
||||
@TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
|
||||
@TagType(Error).ExpectedVarDecl => |x| return x.token,
|
||||
@TagType(Error).ExpectedReturnType => |x| return x.token,
|
||||
@TagType(Error).ExpectedAggregateKw => |x| return x.token,
|
||||
@TagType(Error).UnattachedDocComment => |x| return x.token,
|
||||
@TagType(Error).ExpectedEqOrSemi => |x| return x.token,
|
||||
@TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
|
||||
@TagType(Error).ExpectedSemiOrElse => |x| return x.token,
|
||||
@TagType(Error).ExpectedLabelOrLBrace => |x| return x.token,
|
||||
@TagType(Error).ExpectedLBrace => |x| return x.token,
|
||||
@TagType(Error).ExpectedColonOrRParen => |x| return x.token,
|
||||
@TagType(Error).ExpectedLabelable => |x| return x.token,
|
||||
@TagType(Error).ExpectedInlinable => |x| return x.token,
|
||||
@TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
|
||||
@TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
|
||||
@TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
|
||||
@TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
|
||||
@TagType(Error).ExtraAlignQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraConstQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraVolatileQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraAllowZeroQualifier => |x| return x.token,
|
||||
@TagType(Error).ExpectedTypeExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedPrimaryTypeExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedParamType => |x| return x.token,
|
||||
@TagType(Error).ExpectedExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedToken => |x| return x.token,
|
||||
@TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
|
||||
@TagType(Error).ExpectedParamList => |x| return x.token,
|
||||
@TagType(Error).ExpectedPayload => |x| return x.token,
|
||||
@TagType(Error).ExpectedBlockOrAssignment => |x| return x.token,
|
||||
@TagType(Error).ExpectedBlockOrExpression => |x| return x.token,
|
||||
@TagType(Error).ExpectedExprOrAssignment => |x| return x.token,
|
||||
@TagType(Error).ExpectedPrefixExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedLoopExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedDerefOrUnwrap => |x| return x.token,
|
||||
@TagType(Error).ExpectedSuffixOp => |x| return x.token,
|
||||
.InvalidToken => |x| return x.token,
|
||||
.ExpectedContainerMembers => |x| return x.token,
|
||||
.ExpectedStringLiteral => |x| return x.token,
|
||||
.ExpectedIntegerLiteral => |x| return x.token,
|
||||
.ExpectedPubItem => |x| return x.token,
|
||||
.ExpectedIdentifier => |x| return x.token,
|
||||
.ExpectedStatement => |x| return x.token,
|
||||
.ExpectedVarDeclOrFn => |x| return x.token,
|
||||
.ExpectedVarDecl => |x| return x.token,
|
||||
.ExpectedReturnType => |x| return x.token,
|
||||
.ExpectedAggregateKw => |x| return x.token,
|
||||
.UnattachedDocComment => |x| return x.token,
|
||||
.ExpectedEqOrSemi => |x| return x.token,
|
||||
.ExpectedSemiOrLBrace => |x| return x.token,
|
||||
.ExpectedSemiOrElse => |x| return x.token,
|
||||
.ExpectedLabelOrLBrace => |x| return x.token,
|
||||
.ExpectedLBrace => |x| return x.token,
|
||||
.ExpectedColonOrRParen => |x| return x.token,
|
||||
.ExpectedLabelable => |x| return x.token,
|
||||
.ExpectedInlinable => |x| return x.token,
|
||||
.ExpectedAsmOutputReturnOrType => |x| return x.token,
|
||||
.ExpectedCall => |x| return x.node.firstToken(),
|
||||
.ExpectedCallOrFnProto => |x| return x.node.firstToken(),
|
||||
.ExpectedSliceOrRBracket => |x| return x.token,
|
||||
.ExtraAlignQualifier => |x| return x.token,
|
||||
.ExtraConstQualifier => |x| return x.token,
|
||||
.ExtraVolatileQualifier => |x| return x.token,
|
||||
.ExtraAllowZeroQualifier => |x| return x.token,
|
||||
.ExpectedTypeExpr => |x| return x.token,
|
||||
.ExpectedPrimaryTypeExpr => |x| return x.token,
|
||||
.ExpectedParamType => |x| return x.token,
|
||||
.ExpectedExpr => |x| return x.token,
|
||||
.ExpectedPrimaryExpr => |x| return x.token,
|
||||
.ExpectedToken => |x| return x.token,
|
||||
.ExpectedCommaOrEnd => |x| return x.token,
|
||||
.ExpectedParamList => |x| return x.token,
|
||||
.ExpectedPayload => |x| return x.token,
|
||||
.ExpectedBlockOrAssignment => |x| return x.token,
|
||||
.ExpectedBlockOrExpression => |x| return x.token,
|
||||
.ExpectedExprOrAssignment => |x| return x.token,
|
||||
.ExpectedPrefixExpr => |x| return x.token,
|
||||
.ExpectedLoopExpr => |x| return x.token,
|
||||
.ExpectedDerefOrUnwrap => |x| return x.token,
|
||||
.ExpectedSuffixOp => |x| return x.token,
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,8 +318,19 @@ pub const Error = union(enum) {
|
||||
expected_id: Token.Id,
|
||||
|
||||
pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
|
||||
const token_name = @tagName(tokens.at(self.token).id);
|
||||
return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
|
||||
const found_token = tokens.at(self.token);
|
||||
switch (found_token.id) {
|
||||
.Invalid_ampersands => {
|
||||
return stream.print("`&&` is invalid. Note that `and` is boolean AND.");
|
||||
},
|
||||
.Invalid => {
|
||||
return stream.print("expected {}, found invalid bytes", @tagName(self.expected_id));
|
||||
},
|
||||
else => {
|
||||
const token_name = @tagName(found_token.id);
|
||||
return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1708,15 +1717,15 @@ pub const Node = struct {
|
||||
i -= 1;
|
||||
|
||||
switch (self.op) {
|
||||
@TagType(Op).Call => |*call_info| {
|
||||
.Call => |*call_info| {
|
||||
if (i < call_info.params.len) return call_info.params.at(i).*;
|
||||
i -= call_info.params.len;
|
||||
},
|
||||
Op.ArrayAccess => |index_expr| {
|
||||
.ArrayAccess => |index_expr| {
|
||||
if (i < 1) return index_expr;
|
||||
i -= 1;
|
||||
},
|
||||
@TagType(Op).Slice => |range| {
|
||||
.Slice => |range| {
|
||||
if (i < 1) return range.start;
|
||||
i -= 1;
|
||||
|
||||
@ -1725,16 +1734,16 @@ pub const Node = struct {
|
||||
i -= 1;
|
||||
}
|
||||
},
|
||||
Op.ArrayInitializer => |*exprs| {
|
||||
.ArrayInitializer => |*exprs| {
|
||||
if (i < exprs.len) return exprs.at(i).*;
|
||||
i -= exprs.len;
|
||||
},
|
||||
Op.StructInitializer => |*fields| {
|
||||
.StructInitializer => |*fields| {
|
||||
if (i < fields.len) return fields.at(i).*;
|
||||
i -= fields.len;
|
||||
},
|
||||
Op.UnwrapOptional,
|
||||
Op.Deref,
|
||||
.UnwrapOptional,
|
||||
.Deref,
|
||||
=> {},
|
||||
}
|
||||
|
||||
@ -1743,7 +1752,7 @@ pub const Node = struct {
|
||||
|
||||
pub fn firstToken(self: *const SuffixOp) TokenIndex {
|
||||
switch (self.op) {
|
||||
@TagType(Op).Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
|
||||
.Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
|
||||
else => {},
|
||||
}
|
||||
return self.lhs.firstToken();
|
||||
|
||||
@ -774,7 +774,7 @@ fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
arena,
|
||||
it,
|
||||
tree,
|
||||
SimpleBinOpParseFn(.Keyword_and, Node.InfixOp.Op.BoolAnd),
|
||||
SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
|
||||
parseCompareExpr,
|
||||
.Infinitely,
|
||||
);
|
||||
|
||||
@ -2267,6 +2267,32 @@ test "zig fmt: file ends with struct field" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comments at several places in struct init" {
|
||||
try testTransform(
|
||||
\\var bar = Bar{
|
||||
\\ .x = 10, // test
|
||||
\\ .y = "test"
|
||||
\\ // test
|
||||
\\};
|
||||
\\
|
||||
,
|
||||
\\var bar = Bar{
|
||||
\\ .x = 10, // test
|
||||
\\ .y = "test", // test
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
|
||||
try testCanonical(
|
||||
\\var bar = Bar{ // test
|
||||
\\ .x = 10, // test
|
||||
\\ .y = "test",
|
||||
\\ // test
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const warn = std.debug.warn;
|
||||
|
||||
@ -2020,7 +2020,13 @@ fn renderTokenOffset(
|
||||
|
||||
const after_comment_token = tree.tokens.at(token_index + offset);
|
||||
const next_line_indent = switch (after_comment_token.id) {
|
||||
Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent - indent_delta,
|
||||
Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => blk: {
|
||||
if (indent > indent_delta) {
|
||||
break :blk indent - indent_delta;
|
||||
} else {
|
||||
break :blk 0;
|
||||
}
|
||||
},
|
||||
else => indent,
|
||||
};
|
||||
try stream.writeByteNTimes(' ', next_line_indent);
|
||||
|
||||
@ -77,6 +77,7 @@ pub const Token = struct {
|
||||
|
||||
pub const Id = enum {
|
||||
Invalid,
|
||||
Invalid_ampersands,
|
||||
Identifier,
|
||||
StringLiteral,
|
||||
MultilineStringLiteralLine,
|
||||
@ -484,6 +485,11 @@ pub const Tokenizer = struct {
|
||||
},
|
||||
|
||||
State.Ampersand => switch (c) {
|
||||
'&' => {
|
||||
result.id = Token.Id.Invalid_ampersands;
|
||||
self.index += 1;
|
||||
break;
|
||||
},
|
||||
'=' => {
|
||||
result.id = Token.Id.AmpersandEqual;
|
||||
self.index += 1;
|
||||
|
||||
@ -201,7 +201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ return error.OutOfMemory;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:7: error: error is discarded",
|
||||
"tmp.zig:2:12: error: error is discarded",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -234,7 +234,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
|
||||
cases.add(
|
||||
"usingnamespace with wrong type",
|
||||
\\use void;
|
||||
\\usingnamespace void;
|
||||
,
|
||||
"tmp.zig:1:1: error: expected struct, enum, or union; found 'void'",
|
||||
);
|
||||
@ -2740,7 +2740,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ 3 = 3;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:7: error: cannot assign to constant",
|
||||
"tmp.zig:2:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2750,7 +2750,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a = 4;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:7: error: cannot assign to constant",
|
||||
"tmp.zig:3:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2820,7 +2820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\}
|
||||
\\export fn entry() void { f(); }
|
||||
,
|
||||
"tmp.zig:3:7: error: cannot assign to constant",
|
||||
"tmp.zig:3:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3883,7 +3883,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
|
||||
,
|
||||
"tmp.zig:6:24: error: unable to evaluate constant expression",
|
||||
"tmp.zig:6:26: error: unable to evaluate constant expression",
|
||||
"tmp.zig:4:17: note: called from here",
|
||||
);
|
||||
|
||||
@ -4133,7 +4133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ cstr[0] = 'W';
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:11: error: cannot assign to constant",
|
||||
"tmp.zig:3:13: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -4143,7 +4143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ cstr[0] = 'W';
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:11: error: cannot assign to constant",
|
||||
"tmp.zig:3:13: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -4291,7 +4291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ f.field = 0;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:6:13: error: cannot assign to constant",
|
||||
"tmp.zig:6:15: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
||||
@ -93,6 +93,7 @@ comptime {
|
||||
_ = @import("behavior/undefined.zig");
|
||||
_ = @import("behavior/underscore.zig");
|
||||
_ = @import("behavior/union.zig");
|
||||
_ = @import("behavior/usingnamespace.zig");
|
||||
_ = @import("behavior/var_args.zig");
|
||||
_ = @import("behavior/vector.zig");
|
||||
_ = @import("behavior/void.zig");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
@ -69,3 +70,33 @@ test "cmpxchg with ptr" {
|
||||
expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
|
||||
expect(x == &data2);
|
||||
}
|
||||
|
||||
// TODO this test is disabled until this issue is resolved:
|
||||
// https://github.com/ziglang/zig/issues/2883
|
||||
// otherwise cross compiling will result in:
|
||||
// lld: error: undefined symbol: __sync_val_compare_and_swap_16
|
||||
//test "128-bit cmpxchg" {
|
||||
// var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987
|
||||
// if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
|
||||
// expect(x1 == 1234);
|
||||
// } else {
|
||||
// @panic("cmpxchg should have failed");
|
||||
// }
|
||||
//
|
||||
// while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
|
||||
// expect(x1 == 1234);
|
||||
// }
|
||||
// expect(x == 5678);
|
||||
//
|
||||
// expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
|
||||
// expect(x == 42);
|
||||
//}
|
||||
|
||||
test "cmpxchg with ignored result" {
|
||||
var x: i32 = 1234;
|
||||
var ptr = &x;
|
||||
|
||||
_ = @cmpxchgStrong(i32, &x, 1234, 5678, .Monotonic, .Monotonic);
|
||||
|
||||
expectEqual(i32(5678), x);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "compile time recursion" {
|
||||
@ -794,3 +795,12 @@ test "no undeclared identifier error in unanalyzed branches" {
|
||||
lol_this_doesnt_exist = nonsense;
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime assign int to optional int" {
|
||||
comptime {
|
||||
var x: ?i32 = null;
|
||||
x = 2;
|
||||
x.? *= 10;
|
||||
expectEqual(20, x.?);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,3 +228,22 @@ test "implicit cast fn call result to optional in field result" {
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
test "discard the result of a function that returns a struct" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
_ = func();
|
||||
}
|
||||
|
||||
fn func() Foo {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
14
test/stage1/behavior/usingnamespace.zig
Normal file
14
test/stage1/behavior/usingnamespace.zig
Normal file
@ -0,0 +1,14 @@
|
||||
const std = @import("std");
|
||||
|
||||
fn Foo(comptime T: type) type {
|
||||
return struct {
|
||||
usingnamespace T;
|
||||
};
|
||||
}
|
||||
|
||||
test "usingnamespace inside a generic struct" {
|
||||
const std2 = Foo(std);
|
||||
const testing2 = Foo(std.testing);
|
||||
std2.testing.expect(true);
|
||||
testing2.expect(true);
|
||||
}
|
||||
@ -74,3 +74,9 @@ test "implicit cast vector to array" {
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "array to vector" {
|
||||
var foo: f32 = 3.14;
|
||||
var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
|
||||
var vec: @Vector(4, f32) = arr;
|
||||
}
|
||||
|
||||
@ -1780,6 +1780,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("escape sequences",
|
||||
\\const char *escapes() {
|
||||
\\char a = '\'',
|
||||
\\ b = '\\',
|
||||
\\ c = '\a',
|
||||
\\ d = '\b',
|
||||
\\ e = '\f',
|
||||
\\ f = '\n',
|
||||
\\ g = '\r',
|
||||
\\ h = '\t',
|
||||
\\ i = '\v',
|
||||
\\ j = '\0',
|
||||
\\ k = '\"';
|
||||
\\ return "\'\\\a\b\f\n\r\t\v\0\"";
|
||||
\\}
|
||||
\\
|
||||
,
|
||||
\\pub export fn escapes() [*c]const u8 {
|
||||
\\ var a: u8 = u8('\'');
|
||||
\\ var b: u8 = u8('\\');
|
||||
\\ var c: u8 = u8('\x07');
|
||||
\\ var d: u8 = u8('\x08');
|
||||
\\ var e: u8 = u8('\x0c');
|
||||
\\ var f: u8 = u8('\n');
|
||||
\\ var g: u8 = u8('\r');
|
||||
\\ var h: u8 = u8('\t');
|
||||
\\ var i: u8 = u8('\x0b');
|
||||
\\ var j: u8 = u8('\x00');
|
||||
\\ var k: u8 = u8('\"');
|
||||
\\ return c"\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
|
||||
/////////////// Cases for only stage1 because stage2 behavior is better ////////////////
|
||||
cases.addC("Parameterless function prototypes",
|
||||
\\void foo() {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user