diff options
-rw-r--r-- | gcc/cp/constraint.cc | 1 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 31 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C | 16 |
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{}); +} |