llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Eli Friedman (efriedma-quic) <details> <summary>Changes</summary> In some cases, a reference to a structured binding is value-dependent. I think this has been possible since they were originally defined in C++17. C++26 makes it easier to trigger issues, though. The standard doesn't provide any explicit rules for what to do here, so I invented a rule. My invented rule seems to be consistent for the cases I can come up with. Fixes #<!-- -->211930 --- Full diff: https://github.com/llvm/llvm-project/pull/212368.diff 4 Files Affected: - (modified) clang/include/clang/AST/DeclCXX.h (+3-3) - (modified) clang/lib/AST/ASTImporter.cpp (+2-1) - (modified) clang/lib/AST/ComputeDependence.cpp (+25) - (added) clang/test/SemaCXX/binding-value-dependence.cpp (+36) ``````````diff diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 45fb99e27b137..93c5d982e1d98 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -4205,7 +4205,7 @@ class StaticAssertDecl : public Decl { /// DecompositionDecl of type 'int (&)[3]'. class BindingDecl : public ValueDecl { /// The declaration that this binding binds to part of. - ValueDecl *Decomp = nullptr; + DecompositionDecl *Decomp = nullptr; /// The binding represented by this declaration. References to this /// declaration are effectively equivalent to this expression (except /// that it is only evaluated once at the point of declaration of the @@ -4236,7 +4236,7 @@ class BindingDecl : public ValueDecl { /// Get the decomposition declaration that this binding represents a /// decomposition of. - ValueDecl *getDecomposedDecl() const { return Decomp; } + DecompositionDecl *getDecomposedDecl() const { return Decomp; } /// Set the binding for this BindingDecl, along with its declared type (which /// should be a possibly-cv-qualified form of the type of the binding, or a @@ -4247,7 +4247,7 @@ class BindingDecl : public ValueDecl { } /// Set the decomposed variable for this BindingDecl. - void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; } + void setDecomposedDecl(DecompositionDecl *Decomposed) { Decomp = Decomposed; } /// Get the variable (if any) that holds the value of evaluating the binding. /// Only present for user-defined bindings for tuple-like types. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index db7d223d56af3..21dd219af6ca9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2835,7 +2835,8 @@ ExpectedDecl ASTNodeImporter::VisitBindingDecl(BindingDecl *D) { Error Err = Error::success(); QualType ToType = importChecked(Err, D->getType()); Expr *ToBinding = importChecked(Err, D->getBinding()); - ValueDecl *ToDecomposedDecl = importChecked(Err, D->getDecomposedDecl()); + DecompositionDecl *ToDecomposedDecl = + importChecked(Err, D->getDecomposedDecl()); if (Err) return std::move(Err); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index a819bb6dec599..0874dc6da381d 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -616,6 +616,31 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { Deps |= ExprDependence::ValueInstantiation; } + // The standard doesn't explicitly specify rules for when individial bindings + // a structured binding declaration are value-dependent. Handle them using a + // similar rule to the rule for variables: + // + // - An id-expression referring to a tuple binding is value-dependent if + // an id-expression referring to the synthetic variable used to store the + // result of get() would be value-dependent. + // - An id-expression referring to a non-tuple binding is value-dependent if + // an id-expression referring to the synthetic variable used to store the + // initializer would be value-dependent. + // + // Internally, this is equivalent to just checking whether the expression + // representing the binding is value-dependent. + if (const auto *BD = dyn_cast<BindingDecl>(Decl)) { + if (const Expr *Init = BD->getBinding()) { + if (Init->containsErrors()) + Deps |= ExprDependence::Error; + + if (Init->isValueDependent()) + Deps |= ExprDependence::ValueInstantiation; + } + + return Deps; + } + return Deps; } diff --git a/clang/test/SemaCXX/binding-value-dependence.cpp b/clang/test/SemaCXX/binding-value-dependence.cpp new file mode 100644 index 0000000000000..124e7eb3782a5 --- /dev/null +++ b/clang/test/SemaCXX/binding-value-dependence.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++26 -verify %s + +// expected-no-diagnostics + +template<int (*a)[3]> void pr211930() { + auto&& [x, y, z] = *a; + // This shouldn't crash; x is value-dependent. + constexpr int q = x; +} + +struct S {int a = 4;}; +namespace std { + template <typename T> struct tuple_size; + template <> struct tuple_size<S> { static const int value = 3; }; + template <> struct tuple_size<const S> { static const int value = 3; }; + template <int I, typename T> struct tuple_element; + template <int I> struct tuple_element<I, S> { + using type = const int; + }; + template <int I> struct tuple_element<I, const S> { + using type = const int; + }; +} +static const int Z = 4; +template<int x> constexpr const int &get(S&&s) { return s.a; } +template<int x> constexpr const int &get(const S&s) { return s.a; } +template<S *s> void value_dependent_get() { + auto &[a,b,c] = *s; + // This shouldn't warn: a is value-dependent. + int rr[-11/(a)]; +} +template<const S *s> void constexpr_value_dependent_get() { + static constexpr auto [a,b,c] = *s; + // This shouldn't warn: a is value-dependent. + int rr[-11/(a)]; +} `````````` </details> https://github.com/llvm/llvm-project/pull/212368 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
