From 968c2a3d51fec66640a383644d19a7eec05b8baf Mon Sep 17 00:00:00 2001 From: Carson Radtke Date: Sun, 23 Nov 2025 23:12:25 -0700 Subject: [PATCH] [clang] fix crash when template with constructor attribute is instantiated without a priority The current implementation expects the priority argument to be provided to `[[gnu::constructor()]]`, but the argument is really optional. This was causing a segfault when instantiating the function-template because we were trying to fold an `Expr*` that was a nullptr. This change skips the evaluation of the priority argument when it is missing; this will instantiate a function declaration with the default priority (65535). --- clang/docs/ReleaseNotes.rst | 2 ++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 20 ++++++++++--------- clang/test/SemaTemplate/attributes.cpp | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 439e47b209b2f..20e5a33ff7711 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -513,6 +513,8 @@ Bug Fixes to Attribute Support - Fix handling of parameter indexes when an attribute is applied to a C++23 explicit object member function. - Fixed several false positives and false negatives in function effect (`nonblocking`) analysis. (#GH166078) (#GH166101) (#GH166110) - Fix ``cleanup`` attribute by delaying type checks until after the type is deduced. (#GH129631) +- Fix a crash when instantiating a function template with ``constructor`` or ``destructor`` + attributes without a priority argument. (#GH169072) Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 26693514bb278..e74c41517ecbf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -245,15 +245,17 @@ static void sharedInstantiateConstructorDestructorAttr( ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs); if (Result.isInvalid()) return; - tempInstPriority = Result.get(); - if (std::optional CE = - tempInstPriority->getIntegerConstantExpr(C)) { - // Consistent with non-templated priority arguments, which must fit in a - // 32-bit unsigned integer. - if (!CE->isIntN(32)) { - S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large) - << toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1; - return; + if (Result.isUsable()) { + tempInstPriority = Result.get(); + if (std::optional CE = + tempInstPriority->getIntegerConstantExpr(C)) { + // Consistent with non-templated priority arguments, which must fit in a + // 32-bit unsigned integer. + if (!CE->isIntN(32)) { + S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large) + << toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1; + return; + } } } } diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp index 20fe983af28f7..d0ab0a68dec2a 100644 --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -640,3 +640,23 @@ namespace preferred_name { Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar'}} } ::preferred_name::Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar'}} + +// GH169072: templated attribute((constructor)) function crashes clang +// constructor/destructor attribute without priority argument should not crash. +namespace gh169072 { + template + [[gnu::constructor]] void foo() {} + + template void foo(); + + template + [[gnu::destructor]] void bar() {} + + template void bar(); + + // Also test with explicit priority argument + template + [[gnu::constructor(101)]] void baz() {} + + template void baz(); +}