https://github.com/kumarak updated https://github.com/llvm/llvm-project/pull/210524
>From 8a893a6fd8083dea7ea57b8eabb3696477efd227 Mon Sep 17 00:00:00 2001 From: AkshayK <[email protected]> Date: Sat, 18 Jul 2026 10:14:42 -0400 Subject: [PATCH 1/2] [Clang] Fix crash when classifying a dependent call to a builtin A call to a builtin with dependent arguments takes the dependent path in Sema::BuildCallExpr, so its callee is not rewritten with CK_BuiltinFnToFnPtr until instantiation and keeps the BuiltinFn placeholder type. CallExpr::getCallReturnType had no case for this placeholder and fell through to castAs<FunctionType>, asserting on valid code such as: template <auto> struct S {}; template <typename T> using Alias = S<__builtin_constant_p(T::x)>; where the call is classified via Expr::ClassifyImpl while deducing the auto non-type template parameter. Return DependentTy for BuiltinFn callees, mirroring the existing overload, bound-member, and record-callee cases. --- clang/docs/ReleaseNotes.md | 3 ++ clang/lib/AST/Expr.cpp | 4 +- clang/test/SemaCXX/builtin-dependent-call.cpp | 18 ++++++++ clang/unittests/Tooling/SourceCodeTest.cpp | 42 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaCXX/builtin-dependent-call.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index a39bc2dfc5b6d..8e910a697845c 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -302,6 +302,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the #### Bug Fixes to Compiler Builtins +- Fixed a crash when classifying a call to a builtin with dependent arguments, + such as when the call is used as an `auto` non-type template argument. + #### Bug Fixes to Attribute Support - The `counted_by`/`counted_by_or_null` diagnostic that rejects a pointer whose diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 0bb9c6aa01c39..9a9a76e265f6a 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1628,7 +1628,9 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { // dependent call to the call operator of that type. return Ctx.DependentTy; } else if (CalleeType->isDependentType() || - CalleeType->isSpecificPlaceholderType(BuiltinType::Overload)) { + CalleeType->isSpecificPlaceholderType(BuiltinType::Overload) || + CalleeType->isSpecificPlaceholderType(BuiltinType::BuiltinFn)) { + // Dependent builtin calls keep their placeholder until instantiation. return Ctx.DependentTy; } diff --git a/clang/test/SemaCXX/builtin-dependent-call.cpp b/clang/test/SemaCXX/builtin-dependent-call.cpp new file mode 100644 index 0000000000000..e84bb78cfea29 --- /dev/null +++ b/clang/test/SemaCXX/builtin-dependent-call.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// expected-no-diagnostics + +// Dependent builtin calls used to assert during auto NTTP deduction. + +template <auto> struct S {}; + +template <typename T> using Alias = S<__builtin_constant_p(T::x)>; +template <typename T> using Alias2 = S<__builtin_ffs(T::x)>; + +struct HasX { + static constexpr int x = 42; +}; + +using Inst = Alias<HasX>; +using Inst2 = Alias2<HasX>; + +using Control = S<__builtin_constant_p(3)>; diff --git a/clang/unittests/Tooling/SourceCodeTest.cpp b/clang/unittests/Tooling/SourceCodeTest.cpp index d0eba43b0bb1c..db454945286ad 100644 --- a/clang/unittests/Tooling/SourceCodeTest.cpp +++ b/clang/unittests/Tooling/SourceCodeTest.cpp @@ -824,4 +824,46 @@ void f2() { Visitor.runOver(Code.code(), CallsVisitor::Lang_CXX14); } +TEST(SourceCodeTest, GetCallReturnType_DependentBuiltinCall) { + // Dependent builtin calls keep their BuiltinFn placeholder until + // instantiation. The alias also covers the parse-time regression. + llvm::Annotations Code{R"cpp( +template <auto> struct S {}; + +template <typename T> +using Alias = S<__builtin_constant_p(T::x)>; + +template <typename T> +void templ(const T &t) { + $test1[[__builtin_constant_p(t.x)]]; + $test2[[__builtin_ffs(t.x)]]; +} +)cpp"}; + + llvm::Annotations::Range R1 = Code.range("test1"); + llvm::Annotations::Range R2 = Code.range("test2"); + + bool SawBuiltinFnCallee = false; + CallsVisitor Visitor; + Visitor.OnCall = [&R1, &R2, &SawBuiltinFnCallee](CallExpr *Expr, + ASTContext *Context) { + unsigned Begin = Context->getSourceManager().getFileOffset( + Expr->getSourceRange().getBegin()); + unsigned End = Context->getSourceManager().getFileOffset( + Expr->getSourceRange().getEnd()); + llvm::Annotations::Range R{Begin, End + 1}; + + QualType CalleeType = Expr->getCallee()->getType(); + if (R == R1 || R == R2) { + SawBuiltinFnCallee = true; + ASSERT_FALSE(CalleeType->isDependentType()); + ASSERT_TRUE( + CalleeType->isSpecificPlaceholderType(BuiltinType::BuiltinFn)); + EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy); + } + }; + Visitor.runOver(Code.code(), CallsVisitor::Lang_CXX17); + EXPECT_TRUE(SawBuiltinFnCallee); +} + } // end anonymous namespace >From 7d0ace21be5d9c471d9c2c9fb74f42a73153b2dc Mon Sep 17 00:00:00 2001 From: AkshayK <[email protected]> Date: Sat, 18 Jul 2026 15:45:05 -0400 Subject: [PATCH 2/2] [Clang] Pass -fno-delayed-template-parsing in dependent-builtin-call unittest On MSVC-compatible triples delayed template parsing is on by default, so the uninstantiated body of the function template in GetCallReturnType_DependentBuiltinCall is never parsed and the dependent builtin calls never enter the AST, tripping the SawBuiltinFnCallee check on Windows CI. Bypass TestVisitor::runOver and pass -fno-delayed-template-parsing explicitly, following the existing pattern in this file and in RecursiveASTVisitorTests/OffsetOfExpr.cpp. --- clang/unittests/Tooling/SourceCodeTest.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clang/unittests/Tooling/SourceCodeTest.cpp b/clang/unittests/Tooling/SourceCodeTest.cpp index db454945286ad..33aeb7a132d55 100644 --- a/clang/unittests/Tooling/SourceCodeTest.cpp +++ b/clang/unittests/Tooling/SourceCodeTest.cpp @@ -45,6 +45,9 @@ struct IntLitVisitor : TestVisitor { }; struct CallsVisitor : TestVisitor { + // Expose the protected helper so a test can supply extra compiler args. + using TestVisitor::CreateTestAction; + bool VisitCallExpr(CallExpr *Expr) override { OnCall(Expr, Context); return true; @@ -862,7 +865,12 @@ void templ(const T &t) { EXPECT_EQ(Expr->getCallReturnType(*Context), Context->DependentTy); } }; - Visitor.runOver(Code.code(), CallsVisitor::Lang_CXX17); + // Bypass TestVisitor::runOver so we can pass -fno-delayed-template-parsing. + // Otherwise on MSVC-compatible triples the uninstantiated body of templ is + // not parsed and the dependent builtin calls never enter the AST. + EXPECT_TRUE(tooling::runToolOnCodeWithArgs( + Visitor.CreateTestAction(), Code.code(), + {"-std=c++17", "-fno-delayed-template-parsing"})); EXPECT_TRUE(SawBuiltinFnCallee); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
