Skip to content

Commit 1e7efca

Browse files
authored
[clang] fix crash when template with constructor attribute is instantiated without a priority (#169282)
fixes: #169072 The current implementation expects the priority argument to be provided to `[[gnu::constructor(<priority>)]]`, 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).
1 parent 1100917 commit 1e7efca

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,8 @@ Bug Fixes to Attribute Support
518518
- Fix handling of parameter indexes when an attribute is applied to a C++23 explicit object member function.
519519
- Fixed several false positives and false negatives in function effect (`nonblocking`) analysis. (#GH166078) (#GH166101) (#GH166110)
520520
- Fix ``cleanup`` attribute by delaying type checks until after the type is deduced. (#GH129631)
521+
- Fix a crash when instantiating a function template with ``constructor`` or ``destructor``
522+
attributes without a priority argument. (#GH169072)
521523

522524
Bug Fixes to C++ Support
523525
^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,17 @@ static void sharedInstantiateConstructorDestructorAttr(
245245
ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs);
246246
if (Result.isInvalid())
247247
return;
248-
tempInstPriority = Result.get();
249-
if (std::optional<llvm::APSInt> CE =
250-
tempInstPriority->getIntegerConstantExpr(C)) {
251-
// Consistent with non-templated priority arguments, which must fit in a
252-
// 32-bit unsigned integer.
253-
if (!CE->isIntN(32)) {
254-
S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
255-
<< toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1;
256-
return;
248+
if (Result.isUsable()) {
249+
tempInstPriority = Result.get();
250+
if (std::optional<llvm::APSInt> CE =
251+
tempInstPriority->getIntegerConstantExpr(C)) {
252+
// Consistent with non-templated priority arguments, which must fit in a
253+
// 32-bit unsigned integer.
254+
if (!CE->isIntN(32)) {
255+
S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
256+
<< toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1;
257+
return;
258+
}
257259
}
258260
}
259261
}

clang/test/SemaTemplate/attributes.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,23 @@ namespace preferred_name {
640640
Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar<int, float>'}}
641641
}
642642
::preferred_name::Foo<1, 2, int, float>::nosuch x; // expected-error {{no type named 'nosuch' in 'preferred_name::Bar<int, float>'}}
643+
644+
// GH169072: templated attribute((constructor)) function crashes clang
645+
// constructor/destructor attribute without priority argument should not crash.
646+
namespace gh169072 {
647+
template <typename T>
648+
[[gnu::constructor]] void foo() {}
649+
650+
template void foo<int>();
651+
652+
template <typename T>
653+
[[gnu::destructor]] void bar() {}
654+
655+
template void bar<int>();
656+
657+
// Also test with explicit priority argument
658+
template <typename T>
659+
[[gnu::constructor(101)]] void baz() {}
660+
661+
template void baz<int>();
662+
}

0 commit comments

Comments
 (0)