aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/constraint.cc1
-rw-r--r--gcc/cp/pt.cc31
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C16
3 files changed, 47 insertions, 1 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 83df57d..67fe2ae 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2370,6 +2370,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
matching or dguide constraint rewriting), in which case we need
to partially substitute. */
t = copy_node (t);
+ REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
return t;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fa660fc..3af705c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3861,6 +3861,24 @@ has_extra_args_mechanism_p (const_tree t)
&& IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS */
}
+/* Return *_EXTRA_ARGS of the given supported tree T. */
+
+static tree&
+tree_extra_args (tree t)
+{
+ gcc_checking_assert (has_extra_args_mechanism_p (t));
+
+ if (PACK_EXPANSION_P (t))
+ return PACK_EXPANSION_EXTRA_ARGS (t);
+ else if (TREE_CODE (t) == REQUIRES_EXPR)
+ return REQUIRES_EXPR_EXTRA_ARGS (t);
+ else if (TREE_CODE (t) == IF_STMT
+ && IF_STMT_CONSTEXPR_P (t))
+ return IF_STMT_EXTRA_ARGS (t);
+
+ gcc_unreachable ();
+}
+
/* Structure used to track the progress of find_parameter_packs_r. */
struct find_parameter_pack_data
{
@@ -13185,6 +13203,16 @@ extract_locals_r (tree *tp, int *walk_subtrees, void *data_)
/* Remember local typedefs (85214). */
tp = &TYPE_NAME (*tp);
+ if (has_extra_args_mechanism_p (*tp))
+ /* Assert *_EXTRA_ARGS is empty, because we don't want to walk it and
+ potentially see a previously captured local in an evaluated context
+ that's really only used in an unevaluated context (PR114303). This
+ means callers of build_extra_args need to clear *_EXTRA_ARGS of the
+ outermost tree. Nested *_EXTRA_ARGS should naturally be empty since
+ the outermost (extra-args) tree will intercept any substitution before
+ a nested tree can. */
+ gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE);
+
if (TREE_CODE (*tp) == DECL_EXPR)
{
tree decl = DECL_EXPR_DECL (*tp);
@@ -19189,10 +19217,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
of the constexpr if is still dependent. Don't substitute into the
branches now, just remember the template arguments. */
do_poplevel (IF_SCOPE (stmt));
+ IF_SCOPE (stmt) = NULL_TREE;
IF_COND (stmt) = IF_COND (t);
THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+ IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
add_stmt (stmt);
break;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index 0000000..038c2a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0,0 +1,16 @@
+// PR c++/114303
+// { dg-do compile { target c++17 } }
+
+struct A { static constexpr bool value = true; };
+
+int main() {
+ [](auto x1) {
+ return [&](auto) {
+ return [&](auto x3) {
+ if constexpr (decltype(x3)::value) {
+ static_assert(decltype(x1)::value);
+ }
+ }(A{});
+ }(0);
+ }(A{});
+}