Skip to content

Commit

Permalink
Merge pull request #655 from ehaas/callable-tok
Browse files Browse the repository at this point in the history
Improve unused result diagnostics
  • Loading branch information
Vexu authored Mar 27, 2024
2 parents dcde67e + 3a1479e commit e379e04
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/aro/Attribute.zig
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ pub fn applyFieldAttributes(p: *Parser, field_ty: *Type, attr_buf_start: usize)
p.attr_application_buf.items.len = 0;
for (attrs, toks) |attr, tok| switch (attr.tag) {
// zig fmt: off
.@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode,
.@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode, .warn_unused_result, .nodiscard,
=> try p.attr_application_buf.append(p.gpa, attr),
// zig fmt: on
.vector_size => try attr.applyVectorSize(p, tok, field_ty),
Expand Down
16 changes: 6 additions & 10 deletions src/aro/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5168,20 +5168,16 @@ pub const Result = struct {
=> return,
.call_expr_one => {
const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;
const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
const call_info = p.tmpTree().callableResultUsage(fn_ptr) orelse return;
if (call_info.nodiscard) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(call_info.tok));
if (call_info.warn_unused_result) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(call_info.tok));
return;
},
.call_expr => {
const fn_ptr = p.data.items[p.nodes.items(.data)[@intFromEnum(cur_node)].range.start];
const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
const call_info = p.tmpTree().callableResultUsage(fn_ptr) orelse return;
if (call_info.nodiscard) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(call_info.tok));
if (call_info.warn_unused_result) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(call_info.tok));
return;
},
.stmt_expr => {
Expand Down
51 changes: 51 additions & 0 deletions src/aro/Tree.zig
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,57 @@ pub fn bitfieldWidth(tree: *const Tree, node: NodeIndex, inspect_lval: bool) ?u3
}
}

const CallableResultUsage = struct {
/// name token of the thing being called, for diagnostics
tok: TokenIndex,
/// true if `nodiscard` attribute present
nodiscard: bool,
/// true if `warn_unused_result` attribute present
warn_unused_result: bool,
};

pub fn callableResultUsage(tree: *const Tree, node: NodeIndex) ?CallableResultUsage {
const data = tree.nodes.items(.data);

var cur_node = node;
while (true) switch (tree.nodes.items(.tag)[@intFromEnum(cur_node)]) {
.decl_ref_expr => {
const tok = data[@intFromEnum(cur_node)].decl_ref;
const fn_ty = tree.nodes.items(.ty)[@intFromEnum(node)].elemType();
return .{
.tok = tok,
.nodiscard = fn_ty.hasAttribute(.nodiscard),
.warn_unused_result = fn_ty.hasAttribute(.warn_unused_result),
};
},
.paren_expr => cur_node = data[@intFromEnum(cur_node)].un,
.comma_expr => cur_node = data[@intFromEnum(cur_node)].bin.rhs,

.explicit_cast, .implicit_cast => cur_node = data[@intFromEnum(cur_node)].cast.operand,
.addr_of_expr, .deref_expr => cur_node = data[@intFromEnum(cur_node)].un,
.call_expr_one => cur_node = data[@intFromEnum(cur_node)].bin.lhs,
.call_expr => cur_node = tree.data[data[@intFromEnum(cur_node)].range.start],
.member_access_expr, .member_access_ptr_expr => {
const member = data[@intFromEnum(cur_node)].member;
var ty = tree.nodes.items(.ty)[@intFromEnum(member.lhs)];
if (ty.isPtr()) ty = ty.elemType();
const record = ty.getRecord().?;
const field = record.fields[member.index];
const attributes = if (record.field_attributes) |attrs| attrs[member.index] else &.{};
return .{
.tok = field.name_tok,
.nodiscard = for (attributes) |attr| {
if (attr.tag == .nodiscard) break true;
} else false,
.warn_unused_result = for (attributes) |attr| {
if (attr.tag == .warn_unused_result) break true;
} else false,
};
},
else => return null,
};
}

pub fn isLval(tree: *const Tree, node: NodeIndex) bool {
var is_const: bool = undefined;
return tree.isLvalExtra(node, &is_const);
Expand Down
28 changes: 26 additions & 2 deletions test/cases/warn unused result.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
typedef int (*fnptr)(int, int);


int foo() __attribute__((warn_unused_result)) {
return 0;
}

void bar() {
fnptr make_fn(int a, int b) {
return 0;
}

void bar(fnptr ptr) {
foo();
(foo)();
(foo - 16)();
(foo + 16)();
(*****foo)();
make_fn(1, 2)(2, 2);
}

struct S {
int __attribute__((warn_unused_result))(*close)(void);
};

void baz(struct S *s){
(bar(0), s->close)();
}


#define EXPECTED_ERRORS "warn unused result.c:13:4: warning: ignoring return value of 'foo', declared with 'warn_unused_result' attribute [-Wunused-result]" \
"warn unused result.c:14:4: warning: ignoring return value of 'foo', declared with 'warn_unused_result' attribute [-Wunused-result]" \
"warn unused result.c:17:4: warning: ignoring return value of 'foo', declared with 'warn_unused_result' attribute [-Wunused-result]" \
"warn unused result.c:26:5: warning: ignoring return value of 'close', declared with 'warn_unused_result' attribute [-Wunused-result]" \

#define EXPECTED_ERRORS "warn unused result.c:6:4: warning: ignoring return value of 'foo', declared with 'warn_unused_result' attribute [-Wunused-result]"

0 comments on commit e379e04

Please sign in to comment.