Skip to content

Format function arg defaults with the constants-as-written printer - #1069

Open
conrade-ctc wants to merge 2 commits into
compiler-research:mainfrom
conrade-ctc:argdefault-symbolic-floating-defaults
Open

Format function arg defaults with the constants-as-written printer#1069
conrade-ctc wants to merge 2 commits into
compiler-research:mainfrom
conrade-ctc:argdefault-symbolic-floating-defaults

Conversation

@conrade-ctc

@conrade-ctc conrade-ctc commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

GetFunctionArgDefault re-printed default arguments at maximum float precision, so 3.14 rendered as 3.1400000000000001. Print them with printPretty, the interpreter's ASTContext, and ConstantsAsWritten = true instead: literal leaves keep their source spelling (4.0 stays 4.0).

Two clang-side gaps remain: the maximum-precision expansion where ConstantsAsWritten cannot apply (fix under review in llvm/llvm-project#218471), and cooked UDL floats (90.0_deg prints as 90._deg). A canary test expects the old output before clang 24 and the fixed output from clang 24 on.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.70%. Comparing base (1795887) to head (5c372a8).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1069      +/-   ##
==========================================
+ Coverage   87.68%   87.70%   +0.01%     
==========================================
  Files          23       23              
  Lines        6382     6391       +9     
==========================================
+ Hits         5596     5605       +9     
  Misses        786      786              
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOp.cpp 90.51% <100.00%> (+0.02%) ⬆️
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOp.cpp 90.51% <100.00%> (+0.02%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread lib/CppInterOp/CppInterOp.cpp Outdated
// is not a plain literal.
errno = 0;
char* ParseEnd = nullptr;
double DefaultArgValue = std::strtod(Result.c_str(), &ParseEnd);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe we can take a step back here -- is that the way clang does this?

@conrade-ctc conrade-ctc Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good point... claude pointed out to me that there is a more standard, generic fix... two possibilities... let me try that them, and repost... might close one of the two PRs actually, since they are related. Give me a sec...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call — reworked. It now does what SemaCodeComplete's GetDefaultValueString does: read the parameter's getDefaultArgRange() source text via Lexer::getSourceText (including stripping the sometimes-present leading =, per the FIXME there), falling back to the AST pretty-print only when there's no usable range. That makes the output as-written by construction, so the float-precision FIXME and the std::stod normalization are gone entirely. Literal defaults now render exactly as written (4.0 where the old code produced 4.) — existing test expectations updated to match.

@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@conrade-ctc conrade-ctc changed the title Keep symbolic floating defaults in GetFunctionArgDefault Format function arg defaults from their source text Jul 16, 2026
@conrade-ctc
conrade-ctc force-pushed the argdefault-symbolic-floating-defaults branch from 189b6aa to 2d07020 Compare July 16, 2026 17:33
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Comment thread lib/CppInterOp/CppInterOp.cpp Outdated
// Render the default as written: read its source range, the way clang's
// own code completion formats default arguments (GetDefaultValueString
// in SemaCodeComplete). Pretty-printing the AST instead reproduces
// floating literals at representation precision ("3.1400000000000001"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe that's a bug in clang -- it should print the value as written. Can we follow up there, and land that as a temporary workaround?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

makes sense, i'll iterate on that and reproducing the bug upstream. i'll post a PR for that separately, and we can treat this as a work-around. I'll update this PR as well with the proper guards so that we can clean up later.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

also, in the process of iterating on the upstream, a lighter version of this diff that uses a different pathway was found, so i'm verifying it and probably will update this PR to swap in that change instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reworked: the patch now prints defaults with printPretty, the interpreter's ASTContext, and ConstantsAsWritten = true, instead of the hand-rolled source-text read. All existing tests pass unchanged. The clang-side precision bug is being fixed in llvm/llvm-project#218471; until then, defaults that ConstantsAsWritten cannot cover (cooked UDL floats, invalid-range literals) still print at maximum precision. A version-gated canary test expects the old output before clang 24 and the fixed output from clang 24 on, so a cherry-pick or a slipped landing shows up as a named failure.

}
ASTContext& Ctx = getASTContext();
PrintingPolicy Policy(Ctx.getLangOpts());
Policy.ConstantsAsWritten = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, that’s nice. And probably kills our upstream story probably for good.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@vgvassilev, do you think the UDL hole that is listed above is worth a PR to clang as well? it's a separate gap that might be valuable to clean up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, ok. Did not realize that’s a disk access. That’s pretty slow for the pch case and requires headers to be around..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hmmm, by UDL i mean user-defined-literal, not the disk one :) Just want to make sure we're on the same page... there is apparently a minor hole in the UDL float impl that mixes 90.0_deg and 90._deg for example... claude identified that as a follow up that is related and needs a separate treatment upstream.

@conrade-ctc conrade-ctc changed the title Format function arg defaults from their source text Format function arg defaults with the constants-as-written printer Aug 24, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

Comment thread unittests/CppInterOp/FunctionReflectionTest.cpp
Comment thread unittests/CppInterOp/FunctionReflectionTest.cpp
@conrade-ctc
conrade-ctc force-pushed the argdefault-symbolic-floating-defaults branch from 1c98a0f to e900344 Compare August 24, 2026 20:28
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Emery Conrad added 2 commits August 27, 2026 09:24
Print the default-argument expression with printPretty, the
interpreter's ASTContext, and ConstantsAsWritten = true. The policy
prints literal leaves from their source text, so defaults keep their
spelling (4.0 stays "4.0"). This replaces the AST re-print at maximum
float precision, which turned 3.14 into 3.1400000000000001.

Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
Fails on the first LLVM that prints shortest round-trip floats
(llvm/llvm-project#218471), which changes the output for defaults the
constants-as-written policy cannot cover.

Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
@conrade-ctc
conrade-ctc force-pushed the argdefault-symbolic-floating-defaults branch from e900344 to 5c372a8 Compare August 27, 2026 14:24
conrade-ctc pushed a commit to chicagotrading/CppInterOp that referenced this pull request Aug 27, 2026
Print the default-argument expression with printPretty, the
interpreter's ASTContext, and ConstantsAsWritten = true. The policy
prints literal leaves from their source text, so defaults keep their
spelling (4.0 stays "4.0"). This replaces the AST re-print at maximum
float precision, which turned 3.14 into 3.1400000000000001.

A canary test fails on the first LLVM that prints shortest round-trip
floats (llvm/llvm-project#218471), which changes the output for defaults
the policy cannot cover.

Content matches compiler-research#1069.

Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
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.

2 participants