[clang] Implement declcall (P2825) as a SYCL-gated extension - #22924
Draft
koparasy wants to merge 30 commits into
Draft
[clang] Implement declcall (P2825) as a SYCL-gated extension#22924koparasy wants to merge 30 commits into
koparasy wants to merge 30 commits into
Conversation
declcall (P2825R5) prototype ported from hanickadot/llvm-project onto intel/llvm sycl. (cherry picked from commit 4c54efc218e2b81e2c014b5f328e30f6151ab191)
Contributor
There was a problem hiding this comment.
Pull request overview
Implements declcall(call-expression) (P2825R5) in Clang as a SYCL-gated keyword/extension, introducing a new AST node (CXXDeclcallExpr) that resolves a call-expression’s overload and yields the selected function (or member function) pointer, including support for “devirtualized” qualified virtual member calls.
Changes:
- Adds parsing, Sema, AST, serialization, ASTMatchers, and tooling support for
CXXDeclcallExpr, including extension diagnostics and keyword gating. - Extends constant evaluation / interpreter and CodeGen to carry and lower a “devirtualized member pointer” flag.
- Adds broad test coverage across Sema/SFINAE, AST dump, mangling, CodeGen, PCH, and C++20 modules.
Reviewed changes
Copilot reviewed 65 out of 65 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| clang/tools/libclang/CXCursor.cpp | Map CXXDeclcallExpr to libclang cursor kind. |
| clang/test/SemaCXX/declcall.cpp | Core semantic tests for declcall. |
| clang/test/SemaCXX/declcall-sfinae.cpp | SFINAE behavior tests. |
| clang/test/SemaCXX/declcall-extension.cpp | Extension vs SYCL keyword gating tests. |
| clang/test/PCH/declcall.cpp | PCH serialization test for devirtualize bit. |
| clang/test/CodeGenCXX/mangle-declcall.cpp | Itanium mangling coverage for dependent declcall. |
| clang/test/CodeGenCXX/declcall.cpp | CodeGen + constant-interpreter coverage. |
| clang/test/CodeGenCXX/declcall-modules.cpp | C++20 modules serialization coverage. |
| clang/test/AST/ast-dump-declcall.cpp | AST dump coverage for declcall + devirtualized marker. |
| clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | Static analyzer visitor handling for declcall. |
| clang/lib/Serialization/ASTWriterStmt.cpp | Serialize CXXDeclcallExpr (+ devirtualize flag). |
| clang/lib/Serialization/ASTReaderStmt.cpp | Deserialize CXXDeclcallExpr (+ devirtualize flag). |
| clang/lib/Sema/TreeTransform.h | Template transformation support for CXXDeclcallExpr. |
| clang/lib/Sema/SemaFixItUtils.cpp | Parentheses heuristics updated for CXXDeclcallExpr. |
| clang/lib/Sema/SemaExprCXX.cpp | Sema build/diagnose logic for declcall. |
| clang/lib/Sema/SemaExpr.cpp | Address-of member-function operand checking touched. |
| clang/lib/Sema/SemaExceptionSpec.cpp | canThrow classification includes declcall. |
| clang/lib/Parse/ParseExpr.cpp | Parser support for declcall(...). |
| clang/lib/Edit/RewriteObjCFoundationAPI.cpp | Parentheses heuristics updated for CXXDeclcallExpr. |
| clang/lib/CodeGen/MicrosoftCXXABI.cpp | ABI interface extended with AllowVirtual knobs. |
| clang/lib/CodeGen/ItaniumCXXABI.cpp | Itanium member-pointer emission honors AllowVirtual. |
| clang/lib/CodeGen/CGExprScalar.cpp | Scalar emission support for CXXDeclcallExpr. |
| clang/lib/CodeGen/CGExprConstant.cpp | Member-pointer constant emission passes AllowVirtual. |
| clang/lib/CodeGen/CGCXXABI.h | ABI interface extended for devirtualization control. |
| clang/lib/CodeGen/CGCXXABI.cpp | Base ABI stubs updated for new parameters. |
| clang/lib/Basic/IdentifierTable.cpp | Add KEYCXX26 status + compat diagnostics. |
| clang/lib/ASTMatchers/Dynamic/Registry.cpp | Register cxxDeclcallExpr matcher. |
| clang/lib/ASTMatchers/ASTMatchersInternal.cpp | Define internal matcher object. |
| clang/lib/AST/TextNodeDumper.cpp | Dump member-pointer APValue “(devirtualized)” marker. |
| clang/lib/AST/StmtProfile.cpp | Stmt profiling visitor for CXXDeclcallExpr. |
| clang/lib/AST/StmtPrinter.cpp | Pretty-printer support for declcall(...). |
| clang/lib/AST/ItaniumMangle.cpp | Vendor-extended mangling for declcall expressions. |
| clang/lib/AST/ExprConstant.cpp | Constant-eval propagation for devirtualized member pointers. |
| clang/lib/AST/ExprClassification.cpp | Expression classification includes declcall. |
| clang/lib/AST/Expr.cpp | Side-effect classification includes declcall. |
| clang/lib/AST/ComputeDependence.cpp | Dependence computation for CXXDeclcallExpr. |
| clang/lib/AST/ByteCode/Opcodes.td | New opcode for member-pointer devirtualization. |
| clang/lib/AST/ByteCode/MemberPointer.h | Interpreter member-pointer tracks devirtualized bit. |
| clang/lib/AST/ByteCode/MemberPointer.cpp | APValue conversion preserves devirtualized bit. |
| clang/lib/AST/ByteCode/Interp.h | Declare interpreter opcode handler. |
| clang/lib/AST/ByteCode/Interp.cpp | Implement devirtualize-member-pointer opcode. |
| clang/lib/AST/ByteCode/Compiler.h | Add bytecode compiler visitor for declcall. |
| clang/lib/AST/ByteCode/Compiler.cpp | Emit bytecode for declcall + devirtualization. |
| clang/lib/AST/ASTImporter.cpp | Import CXXDeclcallExpr and APValue member-pointer flag. |
| clang/lib/AST/APValue.cpp | Extend member-pointer APValue representation with flag. |
| clang/lib/Analysis/UnsafeBufferUsage.cpp | Treat declcall as unevaluated context in traversal. |
| clang/include/clang/Serialization/ASTBitCodes.h | Add bitcode tag for CXXDeclcallExpr. |
| clang/include/clang/Sema/Sema.h | Add Sema entry points for declcall. |
| clang/include/clang/Basic/TokenKinds.h | Add KEYCXX26 and update keyword masks. |
| clang/include/clang/Basic/TokenKinds.def | Define declcall as a C++26 keyword (SYCL-gated). |
| clang/include/clang/Basic/StmtNodes.td | Register CXXDeclcallExpr AST node. |
| clang/include/clang/Basic/DiagnosticSemaKinds.td | Add declcall extension/error diagnostics. |
| clang/include/clang/Basic/DiagnosticLexKinds.td | Add C++26 keyword compatibility warning. |
| clang/include/clang/Basic/DiagnosticGroups.td | Add -Wdeclcall-extension group. |
| clang/include/clang/ASTMatchers/ASTMatchers.h | Expose cxxDeclcallExpr matcher in public API. |
| clang/include/clang/AST/TextNodeDumper.h | Update dumper visitor declarations. |
| clang/include/clang/AST/RecursiveASTVisitor.h | Add traversal macro for CXXDeclcallExpr. |
| clang/include/clang/AST/PropertiesBase.td | Add APValue member-pointer flag to properties layer. |
| clang/include/clang/AST/ExprCXX.h | Define CXXDeclcallExpr node. |
| clang/include/clang/AST/EvaluatedExprVisitor.h | Mark declcall as unevaluated for evaluated-expr visitor. |
| clang/include/clang/AST/ComputeDependence.h | Declare dependence computation for declcall. |
| clang/include/clang/AST/APValue.h | Public API for member-pointer devirtualized flag. |
| clang/docs/ReleaseNotes.md | Document declcall support as an extension. |
| clang/docs/LanguageExtensions.md | Add language extension documentation for declcall. |
| clang-tools-extra/clang-tidy/utils/Matchers.h | Treat declcall as an unevaluated context matcher. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…call declcall now forms its pointer to member from a qualified reference to the selected member function, so the global CheckUseOfCXXMethodAsAddressOfOperand short-circuit is no longer needed. Restoring it re-enables the diagnostics for improperly taking a member function's address (unqualified name, destructor, parenthesized), which the prototype had disabled for all code.
The argument subexpressions of the call are no longer odr-used or evaluated, matching the paper's unevaluated-operand rule (previously they were treated as potentially-evaluated, causing spurious odr-use and diagnostics). The selected function is odr-used separately in the declcall's own evaluation context, so it is still instantiated when the declcall is potentially-evaluated.
EmitMemberFunctionPointer took an AllowVirtual parameter but ignored it, so a devirtualized declcall of a qualified virtual member still emitted a vftable thunk. Emit a direct function pointer when devirtualization is requested.
The devirtualized flag is the only state distinguishing declcall of a qualified virtual call from an unqualified one (both rebuild the same &Class::method operand). Without profiling it, two inline definitions differing only in devirtualization hash identically, so a cross-module ODR mismatch is silently merged (import-order-dependent: direct pointer vs vtable index) instead of diagnosed.
… in the bytecode interpreter Calling through a devirtualized declcall member pointer under -fexperimental-new-constant-interpreter dispatched virtually, disagreeing with the classic evaluator and runtime codegen. The devirtualized flag is now: preserved across MemberPointer instance-binding/path copies, restored when a member pointer is materialized from an APValue, and honored by a new CallMemberPtr opcode that calls directly instead of dispatching.
CXXDeclcallExpr rewrote its operand to the resolved callee, so -ast-print emitted declcall(f) / declcall(&B::g), which does not re-parse. Store the original call expression separately and print it, restoring round-tripping; evaluation and codegen continue to use the resolved operand.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds declcall, an overload-resolution hook from P2825R5.
declcall(call-expression)yields a pointer, or pointer to member, to the function that overload resolution would select for the call-expression, which is an unevaluated operand.The initial implementation is based on a prototype by Hana Dusíková (
hanickadot/llvm-project); this PR ports it, fixes correctness issues, and adds test coverage.Devirtualization.
declcallof a qualified call to a virtual member produces a devirtualized pointer-to-member (dispatch skipped). This is represented by a Devirtualize bit onCXXDeclcallExpr, carried into the member-pointerAPValue, and lowered via anAllowVirtualparameter in both the Itanium and Microsoft ABIs to a direct pointer rather than a vtable index. The flag is serialized (PCH/modules) and honored by both constant evaluators. Note this yields a pointer-to-member that bypasses virtual dispatch, which has no standard-C++ equivalent.Feature gating. P2825 is not standardized.
declcallis enabled as a native keyword under-fsycl; otherwise it is a Clang extension diagnosed by-Wdeclcall-extension(a warning by default, an error under -pedantic-errors). Outside those modes it remains an ordinary identifier.Known limitations (design-level, from the paper). When the selected function relies on default arguments, or is an explicit-object-parameter ("deducing this") member function, the resulting pointer's parameter list does not match the argument list written at the call, so it cannot be invoked with those same arguments (e.g.
declcall(f(1)) for void f(int, int = 1)yieldsvoid(*)(int,int)). These are limitations of the proposal itself and are documented rather than worked around.Tests. Coverage spans Sema, SFINAE, AST dump, CodeGen (classic and -fexperimental-new-constant-interpreter), Itanium and Microsoft mangling, PCH, and C++20 modules.