feat: parser-level support for block literals and __block variables#971
feat: parser-level support for block literals and __block variables#971dotcarmen wants to merge 5 commits into
Conversation
f0b3a01 to
4a15846
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as outdated.
This comment was marked as outdated.
a82f534 to
51c20b7
Compare
|
i just realized aro doesn't support lowering to |
22a3bdb to
201fca6
Compare
201fca6 to
a66ae0c
Compare
a295122 to
4f224ce
Compare
73b3cad to
c9e93a3
Compare
2e2bc28 to
fad7906
Compare
| .weakref, | ||
| .zero_call_used_regs, | ||
| => |t| try p.err(tok, .attribute_todo, .{ @tagName(t), "functions" }), | ||
| // TODO: clang doesn't emit a dx here, but behavior for `__block <function>` is unspecified |
There was a problem hiding this comment.
i wonder if this might apply __block to the variable when initialized with this
eg for auto or id it could be eg id b = ^__block {}; instantiates b as a __block variable
There was a problem hiding this comment.
looked into this by checking -dump-ast (no useful info besides "my hypothesis above is incorrect") and by glancing at the LLVM discourse a bit, couldn't find anything.
this is probably only a detail when lowering, the question is - should i remove this TODO? if clang truly doesn't do anything here, then i think an attribute ignored warning would be nice when not --emulate=clang. but if it does somehow affect compilation, then such a warning would be frivolous
| }, | ||
|
|
||
| .sentinel, | ||
| .blocks, // TODO: clang doesn't emit any diagnostic, but it's not clear what this does |
There was a problem hiding this comment.
fad7906 to
5cbbdea
Compare
| return .{ | ||
| .node = node, | ||
| .qt = block_type, | ||
| .val = try .block(@intFromEnum(node), p.comp), |
There was a problem hiding this comment.
Does a block value need to exist? The only place where you handle it you explicitly ignore it.
There was a problem hiding this comment.
technically it doesn't need to exist. i just created it
- to satisfy the return type of
fn primaryExpr - because it'd be needed when lowering
i can remove it and leave the value as undefined?
There was a problem hiding this comment.
I don't see why you would need it when lowering since the same information is available from the node. You can just leave the value empty for non compile time known values.
| } | ||
| } else { | ||
| try some.coerce(p, ret_qt, e_tok, .ret); | ||
| block.return_type = if (ret_expr) |*some| some.qt else .void; |
There was a problem hiding this comment.
Missing lvalue conversion:
__auto_type a = ^(int a) {
int arr[2];
return arr;
};| block.return_type = if (ret_expr) |*some| some.qt else .void; | |
| } else if (ret_expr) |*some| { | |
| try some.lvalConversion(p, e_tok); | |
| block.return_type = some.qt; | |
| } else { | |
| block.return_type = .void |
There was a problem hiding this comment.
clang warns about returning a pointer to a value on the stack. i couldn't find a similar diagnostic, so i'm assuming such detection is unimplemented.
5cbbdea to
7cf3ccd
Compare
7cf3ccd to
f05a42a
Compare
f05a42a to
d985071
Compare
There was a problem hiding this comment.
still have to finish handling the attributes that i handled before the attributes rework, and finish addressing previous review comments. attributes rework was nice - only had to fix 1 bug in an unused codepath.
the biggest change from the merge: i updated p.block to use a Node with a QualType, both of which get updated as more block literal information is parsed. this allows p.tree.attr_map.hasAttribute to work as expected.
| return node.decl_ref_expr; | ||
| } | ||
| if (@typeInfo(@TypeOf(Wanted)) == .@"enum" and Wanted.opts.enum_kind == .identifier and node == .identifier_arg) { | ||
| if (@typeInfo(Wanted) == .@"enum" and Wanted.opts.enum_kind == .identifier and node == .identifier_arg) { |
There was a problem hiding this comment.
bug fix for this previously-unused code path
d985071 to
e2cfd6d
Compare
| block literals.c:23:17: error: __block attribute not allowed, only allowed on local variables | ||
| block literals.c:23:17: warning: 'blocks' attribute only applies to local variables |
There was a problem hiding this comment.
some of the attribute diagnostics emitted by clang are errors, not warnings - but currently only warnings are emitted. i'm assuming this is fine?
There was a problem hiding this comment.
You don't have to use checkTarget if you want to add a more specific diagnostic.
e2cfd6d to
7e599a7
Compare
|
|
||
| const attr_state = p.wip_attrs.state(true); | ||
| defer p.wip_attrs.restore(attr_state); | ||
| try p.attributeSpecifier(); |
There was a problem hiding this comment.
should keyword attributes be handled as part of attributeSpecifier?
There was a problem hiding this comment.
As in __cdecl? Those are available via msTypeAttribute.
There was a problem hiding this comment.
as in bare noinline, _Noreturn, etc - the keywords handled directly in fn declSpec
|
btw i'm working on splitting out my merge commit to better show the updated blocks-related handling. i'll try to push it tonight |
7e599a7 to
c8af2f8
Compare
Vexu
left a comment
There was a problem hiding this comment.
Here's a diff to prevent a crash when using -fblocks without -fsyntax-only:
diff --git a/src/aro/CodeGen.zig b/src/aro/CodeGen.zig
index 082f41cf..4b322540 100644
--- a/src/aro/CodeGen.zig
+++ b/src/aro/CodeGen.zig
@@ -876,6 +876,7 @@ fn genExpr(c: *CodeGen, node_index: Node.Index) Error!Ir.Ref {
.sizeof_expr,
.builtin_va_arg_pack,
.builtin_va_arg_pack_len,
+ .block_literal,
=> return c.fail("TODO CodeGen.genExpr {t}\n", .{node}),
.codegen_diagnostic => |diagnostic| {
try c.comp.diagnostics.addWithLocation(c.comp, .{| wip.current.attr = attr; | ||
| wip.current.arg_i = 0; | ||
|
|
||
| if (is_block_literal and attr.syntax != .gnu) { |
There was a problem hiding this comment.
I preferred when you added this error in the parser.
| block literals.c:23:17: error: __block attribute not allowed, only allowed on local variables | ||
| block literals.c:23:17: warning: 'blocks' attribute only applies to local variables |
There was a problem hiding this comment.
You don't have to use checkTarget if you want to add a more specific diagnostic.
| return .{ | ||
| .node = node, | ||
| .qt = block_type, | ||
| .val = try .block(@intFromEnum(node), p.comp), |
There was a problem hiding this comment.
I don't see why you would need it when lowering since the same information is available from the node. You can just leave the value empty for non compile time known values.
| if (ret_qt.isBlockLiteralAutoReturn()) { | ||
| func_ty.return_type = .void; | ||
| try block.qt.set(p.comp, .{ .func = func_ty }); | ||
| } else if (last_noreturn != .yes) { |
| if (try p.typeName()) |typename| { | ||
| if (typename.is(p.comp, .func)) { | ||
| qt = typename; | ||
| } else { |
There was a problem hiding this comment.
Needs a check for array types:
^int [2] {};|
|
||
| var compound_stmt_state: StmtExprState = .{}; | ||
| const body = try p.compoundStmt(true, &compound_stmt_state) orelse { | ||
| try p.err(p.tok_i, .missing_block_literal_body, .{}); |
There was a problem hiding this comment.
This should not be fatal, the note is never added because of it.
blocked on/part 2 of #969, wip towards closing #825This PR implements parsing of block literals according to the language extension specification by Clang. Caveat: while the spec document specifies that the parameter list may only be omitted when the return type is omitted, Clang actually compiles programs that omit the return type but not the parameter list (excuse the linker error). The behavior here matches that behavior
Additionally, this change makes no attempt to track
__blockvariable references within block bodies, since that's not necessary for the parse to complete, and that extra information would not be used anywhere yet. in the future, when implementing lowering support for blocks, this information tracking can be added