Skip to content

fix(cgen): fix address-of and as_cast pointer codegen - #27481

Open
guweigang wants to merge 8 commits into
vlang:masterfrom
guweigang:fix-toml-cc
Open

fix(cgen): fix address-of and as_cast pointer codegen#27481
guweigang wants to merge 8 commits into
vlang:masterfrom
guweigang:fix-toml-cc

Conversation

@guweigang

Copy link
Copy Markdown
Contributor

Summary

This PR fixes a C code generation issue where combining the address-of (&) operator and as_cast expressions (specifically during smartcasts) results in incorrect pointer casting and dereferencing syntax in the generated C output.

Details of Changes

In vlib/v/gen/c/cgen.v:

  1. Gen.expr:
    • Enhanced the address-of (&) operator codegen path. When the right-hand side is an AsCast expression, we check if it evaluates to a pointer casting using the new as_cast_will_use_ptr() helper. If so, we avoid writing incorrect prefix operators (like double address-of or invalid dereference syntax).
  2. Gen.write_as_cast_call_start:
    • Added a check for g.is_amp (address-of context) to ensure the compiler generates (Type*) pointer casts rather than standard value casts when smartcasting is performed in an address-of context.
  3. Gen.as_cast_will_use_ptr:
    • Introduced this helper method to accurately determine if an AsCast node will result in a pointer-based representation under the hood (e.g. casting interfaces or sum types with differing base types).

Checklist

  • I have formatted my V files with v fmt -w.
  • All existing tests pass.

Tests Run

Rebuilt the V compiler and verified that all compiler and cgen tests pass:

./v -g -keepc -o ./vnew cmd/v
./vnew -silent test vlib/v/gen/c/

All tests passed successfully on local machine.

@guweigang
guweigang marked this pull request as ready for review June 17, 2026 14:12
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6045f791fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
Comment thread vlib/v/gen/c/cgen.v Outdated
@guweigang

Copy link
Copy Markdown
Contributor Author

Addressed the latest review feedback in 528f9ed:

  • keep address-of semantics for temporary-backed &(call() as Foo) casts
  • scope pointer-mode codegen to the direct as cast so selectors such as &((sum as Foo).field) remain valid
  • add regression coverage for interface casts, sumtype selectors, and call-backed casts

Validation:

  • macOS: casts tests, 36/36 passed
  • Ubuntu ARM64 VM with VFLAGS="-gc none -cc gcc": 35 passed, 1 JS-only test skipped
  • macOS compiler error and C output suites passed

@medvednikov

Copy link
Copy Markdown
Member

@codex review

1 similar comment
@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 528f9edd0b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v
@GGRei

GGRei commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 8605c07c38

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@GGRei

GGRei commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

@medvednikov / @JalonSolov From my perspective, this PR is ready to merge. Thanks!

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-08T20:40:39.697703Z 523125a Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8605c07c38

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v
@medvednikov

Copy link
Copy Markdown
Member

Fixed the current-head function-variant address-cast finding in 4bd7cfe:

  • hoist addressed function-type as casts into statement-lifetime storage before taking &
  • add regression coverage that dereferences and invokes the resulting function pointer

Validation:

  • focused cast regression passed
  • formatter check passed
  • compiler errors: 1,589 passed, 1 skipped
  • C output: 96 passed/8 skipped; C patterns: 125 passed/9 skipped
  • full vlib/v/ run was stopped at 37/2,311 because shared-machine slowdown projected over an hour and unrelated tests were retrying

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4bd7cfee5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
Comment on lines +13841 to +13843
if expr_type_sym.info is ast.SumType
|| (expr_type_sym.info is ast.Interface && node.expr_type != node.typ) {
return true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve address-of for interface-to-interface casts

When a checked interface conversion is addressed, for example if w is ResizableWidget { p := &(w as ResizableWidget) }, this helper returns true because the source and target are different interfaces, causing PrefixExpr to omit &. However, the interface-to-interface branch of as_cast emits I_Widget_as_I_ResizableWidget(w), whose generated signature returns ResizableWidget by value and which does not use is_direct_amp; assigning that value to the inferred &ResizableWidget therefore produces incompatible C. Keep the outer address operation or materialize an address for this branch.

Useful? React with 👍 / 👎.

@medvednikov

Copy link
Copy Markdown
Member

Fixed the interface-to-interface address-cast finding in 1234935:

  • materialize addressed interface conversion results in statement-lifetime storage
  • only use direct payload-pointer mode for interface-to-concrete casts
  • add regression coverage that invokes a method through the resulting interface pointer

Validation on this head:

  • focused cast regression passed
  • formatter check passed
  • compiler errors: 1,589 passed, 1 skipped

The complete C-output suite passed in the immediately preceding fix cycle; it was not overlapped again because another session was using that runner's shared temporary directory.

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 12349354f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12349354f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
Comment on lines 7244 to 7245
tmp_var = g.new_tmp_var()
g.writeln('${typ} ${tmp_var};')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep escaping addressed-cast temporaries alive

When the newly covered function-type or interface-to-interface cast is returned, such as return &(handler_sum as IntHandler), this branch declares an ordinary C automatic temporary, assigns the cast to it, and then returns &tmp_var. The pointer consequently dangles as soon as the function exits, potentially causing a use-after-return; the same occurs when the pointer is stored beyond the current block. Fresh evidence beyond the prior type-mismatch reports is that the new hoisting branch fixes those mismatches by introducing stack storage without applying V's normal escape-to-heap handling.

Useful? React with 👍 / 👎.

Comment thread vlib/v/gen/c/cgen.v Outdated
if node.op == .amp {
if node.right is ast.ParExpr && node.right.expr is ast.AsCast
&& (node.right.expr as ast.AsCast).expr is ast.CallExpr {
if node.op == .amp && node.right is ast.ParExpr && node.right.expr is ast.AsCast {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Unwrap all parentheses before matching addressed casts

When a valid cast has redundant parentheses, for example &((handler_sum as IntHandler)) or &((widget as ResizableWidget)), the parser preserves nested ParExpr nodes but this condition recognizes only one wrapper; the later direct-cast check likewise removes only one. The special temporary path is therefore skipped and C generation takes the address of the function/interface conversion rvalue, which is not an lvalue and fails to compile. Fresh evidence beyond the prior direct-cast reports is the still-unhandled nested-ParExpr form; recursively unwrapping parentheses would make it follow the corrected path.

Useful? React with 👍 / 👎.

@medvednikov

Copy link
Copy Markdown
Member

Fixed the escaping-temporary and nested-parenthesis findings in 2389599:

  • heap-materialize addressed casts whose C result is an rvalue, including call-backed, function-type, and interface conversion casts
  • recursively unwrap redundant parentheses when identifying the direct addressed cast
  • add regressions for returned function/interface pointers and nested-parenthesis forms

Validation on this head:

  • focused cast regression passed with default GC and -gc none
  • generated C confirms escaping values use HEAP(...)
  • formatter check passed
  • compiler errors: 1,589 passed, 1 skipped

The immediately preceding complete C-output run passed (96/8 output fixtures, 125/9 C-pattern fixtures); a duplicate isolated rerun was stopped due shared-machine slowdown.

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2389599410

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
g.write('*')
}
if is_as_cast_heap {
g.write_heap_alloc(g.styp(as_cast_heap_type), as_cast_heap_type)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid HEAP for fixed-array cast results

When the called sum/interface value is cast to a fixed-array variant, for example p := &(get_prefix() as [2]string), this path emits HEAP(<fixed-array typedef>, <array expression>). The HEAP macro initializes an element of (type[]){expr}, but C arrays are not assignable initializers, so GCC/Clang reject the generated C. The previous temporary path handled fixed arrays via declaration and memcpy; this heap materialization needs an equivalent fixed-array-specific allocation/copy path.

Useful? React with 👍 / 👎.

@medvednikov

Copy link
Copy Markdown
Member

Fixed the addressed fixed-array cast finding in 8198a2d:

  • heap-copy fixed-array cast lvalues with builtin__memdup instead of using the non-assignable-array HEAP initializer
  • add a call-backed [2]string sum-cast regression that validates both elements through the resulting pointer

Validation:

  • focused regression passed with default GC and -gc none
  • casts suite: 38/38 passed
  • formatter check passed
  • compiler errors: 1,589 passed, 1 skipped
  • generated C inspected to confirm the fixed-array memdup path

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8198a2db35

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
}

fn (mut g Gen) as_cast_address_needs_heap(node ast.AsCast) bool {
if node.expr is ast.CallExpr {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Unwrap cast operands before deciding heap lifetime

When an escaping addressed cast parenthesizes its call operand, such as return &(((get_sum()) as Foo)), node.expr is an ast.ParExpr, so this check does not select heap storage. as_cast_operand_needs_tmp_eval still recognizes the enclosed call and stores its returned sum in a C automatic temporary, after which the direct-address path returns a pointer into that temporary's payload; the pointer dangles when the function returns. Fresh evidence beyond the previously reported selector/if/match forms is that this new heap helper still does not unwrap a ParExpr around a direct call.

Useful? React with 👍 / 👎.

@medvednikov

Copy link
Copy Markdown
Member

Fixed the current-head lifetime finding by recursively unwrapping parenthesized cast operands before deciding heap allocation. Added the exact escaping return &(((get_foo_bar()) as Foo)) regression; generated C now returns HEAP(main__Foo, ...) instead of the address of an automatic cast temporary.

Validation:

  • focused regression with default GC and -gc none
  • ./vnew -silent test vlib/v/tests/casts/ (38/38)
  • ./vnew -silent vlib/v/compiler_errors_test.v (1589 passed, 1 skipped)
  • generated C inspected for the exact escaping return
  • C-output suite was started but stopped after three minutes of severe shared-load slowdown; the prior-head full C-output suite passed, and this delta is covered by the focused generated-C check.

@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 523125ab5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants