Author: Akshay K Date: 2026-07-21T13:47:38+02:00 New Revision: 3fc3ef399d9972361209917bf26ae9cc7317d3a9
URL: https://github.com/llvm/llvm-project/commit/3fc3ef399d9972361209917bf26ae9cc7317d3a9 DIFF: https://github.com/llvm/llvm-project/commit/3fc3ef399d9972361209917bf26ae9cc7317d3a9.diff LOG: [Clang] Fix assertion failure when classifying a dependent call to a builtin (#210524) ## Summary Fix an assertion failure when Clang classifies a built-in call with type-dependent arguments before template instantiation, e.g., while deducing an `auto` non-type template parameter: For example: ```cpp template <auto> struct S {}; template <typename T> using Alias = S<__builtin_constant_p(T::x)>; ``` ``` Assertion failed: (isa<T>(CanonicalType)), function castAs, file TypeBase.h, line 9349. #9 clang::Type::castAs<clang::FunctionType>() const #10 clang::CallExpr::getCallReturnType(clang::ASTContext const&) const #11 ClassifyInternal(clang::ASTContext&, clang::Expr const*) #12 clang::Expr::ClassifyImpl(clang::ASTContext&, clang::SourceLocation*) const #13 clang::Sema::DeduceAutoType(...) #14 clang::Sema::CheckTemplateArgument(...) ``` ## Cause Built-in references initially have the BuiltinFn placeholder type. For a non-dependent call, `BuildResolvedCallExpr()` applies `CK_BuiltinFnToFnPtr`, converting the callee to its function-pointer type. When a call has type-dependent arguments, `BuildCallExpr()` postpones semantic analysis until instantiation. The callee, therefore, retains its BuiltinFn placeholder type. Deducing the auto non-type template parameter classifies the dependent call through `Expr::ClassifyImpl()`. This calls `CallExpr::getCallReturnType()`, which previously did not handle BuiltinFn and attempted to cast the placeholder to FunctionType, triggering an assertion. The issue also affects ordinary builtins such as `__builtin_ffs` and is not specific to` __builtin_constant_p`. ## Fix Handle `BuiltinFn` alongside the dependent and `Overload` callee cases in `CallExpr::getCallReturnType()` and return `DependentTy`. This matches the type `BuildCallExpr()` gives the `CallExpr` itself, so `getCallReturnType()` and `getType()` now agree on such calls. Built-in resolution and built-in-specific type checking still occur as usual during template instantiation. Added coverage for dependent calls and successful instantiation of `__builtin_constant_p` and `__builtin_ffs`, a non-dependent control case, and getCallReturnType() for a BuiltinFn callee. Added: clang/test/SemaCXX/builtin-dependent-call.cpp Modified: clang/docs/ReleaseNotes.md clang/lib/AST/Expr.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 28e4c98f63bdf..28fea9a99b609 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -310,6 +310,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..ecc95cc048f9b --- /dev/null +++ b/clang/test/SemaCXX/builtin-dependent-call.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fdelayed-template-parsing -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)>; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
