Skip to content

[Clang][P1061] Fix invalid pack binding crash #135129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 11, 2025

Conversation

ricejasonf
Copy link
Contributor

Fixes #134882

Consider

struct foo { char a; int b; };
constexpr foo t{'a', 1};
constexpr auto [...m] = t;

Without the constexpr qualifier, the decomposition declaration just happens to not crash in the call to DeclMustBeEmitted because it returns early because of its "discardable gval linkage". So, the fix is in flat_bindings where we cannot assume the pack binding is valid. There is also a fix along the same vein from a suggestion made by @shafik. The tests are still building on my machine, but I thought I would submit this to get eyes on it earlier since it is trivial.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 10, 2025

@llvm/pr-subscribers-clang

Author: Jason Rice (ricejasonf)

Changes

Fixes #134882

Consider

struct foo { char a; int b; };
constexpr foo t{'a', 1};
constexpr auto [...m] = t;

Without the constexpr qualifier, the decomposition declaration just happens to not crash in the call to DeclMustBeEmitted because it returns early because of its "discardable gval linkage". So, the fix is in flat_bindings where we cannot assume the pack binding is valid. There is also a fix along the same vein from a suggestion made by @shafik. The tests are still building on my machine, but I thought I would submit this to get eyes on it earlier since it is trivial.


Full diff: https://github.com/llvm/llvm-project/pull/135129.diff

3 Files Affected:

  • (modified) clang/include/clang/AST/DeclCXX.h (+1-1)
  • (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+2-3)
  • (modified) clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp (+6)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 56cec07ec0293..ba6d87f8158ab 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4281,7 +4281,7 @@ class DecompositionDecl final
         [](BindingDecl *BD) { return BD->isParameterPack(); });
 
     Bindings = Bindings.drop_front(BeforePackBindings.size());
-    if (!Bindings.empty()) {
+    if (!Bindings.empty() && Bindings.front()->getBinding()) {
       PackBindings = Bindings.front()->getBindingPackDecls();
       Bindings = Bindings.drop_front();
     }
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e0f7ccc4674d8..4f7410c9bf0d8 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1597,11 +1597,10 @@ Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
   auto *NewDD = cast_if_present<DecompositionDecl>(
       VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray));
 
-  if (!NewDD || NewDD->isInvalidDecl())
+  if (!NewDD || NewDD->isInvalidDecl()) {
     for (auto *NewBD : NewBindings)
       NewBD->setInvalidDecl();
-
-  if (OldBindingPack) {
+  } else if (OldBindingPack) {
     // Mark the bindings in the pack as instantiated.
     auto Bindings = NewDD->bindings();
     BindingDecl *NewBindingPack = *llvm::find_if(
diff --git a/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
index ea94757dc66b6..1818dc699c71c 100644
--- a/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
+++ b/clang/test/SemaCXX/cxx2c-binding-pack-nontemplate.cpp
@@ -8,4 +8,10 @@ void decompose_array() {
   // cxx23-warning@+2 {{structured binding packs are a C++2c extension}}
   // nontemplate-error@+1 {{pack declaration outside of template}}
   auto [x, ...rest, y] = arr;
+
+  // cxx26-warning@+4 {{structured binding packs are incompatible with C++ standards before C++2c}}
+  // cxx23-warning@+3 {{structured binding packs are a C++2c extension}}
+  // nontemplate-error@+2 {{decomposition declaration cannot be declared 'constexpr'}}
+  // nontemplate-error@+1 {{pack declaration outside of template}}
+  constexpr auto [x, ...rest, y] = arr;
 }

@ricejasonf ricejasonf force-pushed the ricejasonf/p1061-constexpr-fix branch from 27290e3 to 1597be8 Compare April 10, 2025 06:33
Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

@cor3ntin
Copy link
Contributor

thanks! do you need us to merge that for you?

@ricejasonf
Copy link
Contributor Author

Yes, please, merge it when you can.

@zyn0217 zyn0217 merged commit 2f29829 into llvm:main Apr 11, 2025
11 checks passed
Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the quick fix, I left a comment on the test which should be addressed in a follow up, unless I am missing something and the coverage is elsewhere already.

@@ -3,9 +3,15 @@
// RUN: %clang_cc1 -std=c++23 -verify=cxx23,nontemplate -fsyntax-only -Wc++26-extensions %s

void decompose_array() {
int arr[4] = {1, 2, 3, 6};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have both cases tested, we want as wide test coverage as possible.

Since we just saw w/ the bug this fixes the change in semantics uncovered a bug so covering both semantics is the right thing to do.

@ricejasonf
Copy link
Contributor Author

Sorry, I haven't had time to revisit this, but in that test we are only checking the validity of the decomposition declarations so I think the addition of constexpr to that variable should not affect the checks on the other declarations. There is plenty of coverage on decompositions in the other not "nontemplate" test file. Still, I probably did not need to step on the original test like that. I will consider adding more "invalid declaration" tests and address this when I get more time. Thank you.

var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

constexpr decomposition declaration make clang crash
5 participants