From 609cbe53b758afaf344f6798be776cce0d00a3fa Mon Sep 17 00:00:00 2001
From: Barrett Adair <barrettellisadair@gmail.com>
Date: Fri, 17 Sep 2021 10:46:46 -0500
Subject: [PATCH] Allow parm use outside function body for constexpr members
---
gcc/cp/pt.c | 11 +++++++----
gcc/cp/semantics.c | 13 ++-----------
gcc/testsuite/g++.dg/cpp0x/noexcept34.C | 2 +-
.../g++.dg/parse/parameter-declaration-2.C | 2 +-
gcc/testsuite/g++.dg/template/dependent-expr11.C | 6 ++++++
gcc/testsuite/g++.dg/template/dependent-expr12.C | 10 ++++++++++
gcc/testsuite/g++.dg/template/memfriend19.C | 12 ++++++++++++
gcc/testsuite/g++.dg/template/memfriend20.C | 11 +++++++++++
8 files changed, 50 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/dependent-expr11.C
create mode 100644 gcc/testsuite/g++.dg/template/dependent-expr12.C
create mode 100644 gcc/testsuite/g++.dg/template/memfriend19.C
create mode 100644 gcc/testsuite/g++.dg/template/memfriend20.C
@@ -15133,9 +15133,13 @@ tsubst_function_type (tree t,
inject_this_parameter (this_type, cp_type_quals (this_type));
}
+ begin_scope (sk_function_parms, in_decl);
+
/* Substitute the return type. */
return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ finish_scope ();
+
if (do_inject)
{
current_class_ptr = save_ccp;
@@ -16594,10 +16598,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (DECL_NAME (t) == this_identifier && current_class_ptr)
return current_class_ptr;
- /* This can happen for a parameter name used later in a function
- declaration (such as in a late-specified return type). Just
- make a dummy decl, since it's only used for its type. */
- gcc_assert (cp_unevaluated_operand != 0);
+ gcc_assert (cp_unevaluated_operand != 0
+ || current_binding_level->kind == sk_function_parms);
+
r = tsubst_decl (t, args, complain);
/* Give it the template pattern as its context; its true context
hasn't been instantiated yet and this is good enough for
@@ -3742,7 +3742,8 @@ outer_var_p (tree decl)
&& DECL_FUNCTION_SCOPE_P (decl)
/* Don't get confused by temporaries. */
&& DECL_NAME (decl)
- && (DECL_CONTEXT (decl) != current_function_decl
+ && ((current_function_decl != NULL
+ && DECL_CONTEXT (decl) != current_function_decl)
|| parsing_nsdmi ()));
}
@@ -4002,16 +4003,6 @@ finish_id_expression_1 (tree id_expression,
if (decl == error_mark_node)
return error_mark_node;
}
-
- /* Also disallow uses of function parameters outside the function
- body, except inside an unevaluated context (i.e. decltype). */
- if (TREE_CODE (decl) == PARM_DECL
- && DECL_CONTEXT (decl) == NULL_TREE
- && !cp_unevaluated_operand)
- {
- *error_msg = G_("use of parameter outside function body");
- return error_mark_node;
- }
}
/* If we didn't find anything, or what we found was a type,
@@ -10,7 +10,7 @@ template<typename> struct A
void g () noexcept (f()) { } // { dg-error "use of parameter" }
void g2 () noexcept (this->f()) { } // { dg-error "use of parameter" }
void g3 () noexcept (b) { } // { dg-error "use of .this. in a constant expression|use of parameter" }
- void g4 (int i) noexcept (i) { } // { dg-error "use of parameter" }
+ void g4 (int i) noexcept (i) { } // { dg-error "use of parameter|not a constant expression" }
void g5 () noexcept (A::f()) { } // { dg-error "use of parameter" }
void g6 () noexcept (foo(b)) { } // { dg-error "use of .this. in a constant expression|use of parameter" }
void g7 () noexcept (int{f()}) { } // { dg-error "use of parameter" }
@@ -1,2 +1,2 @@
-void f (int i, int p[i]); // { dg-error "use of parameter.*outside function body" }
+void f (int i, int p[i]); // { dg-error "use of parameter.*outside function body|integral constant" }
// { dg-prune-output "array bound" }
new file mode 100644
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++11 } }
+template<bool u> struct bool_c{ static constexpr bool value = u; };
+struct foo { constexpr bool operator()() const { return true; } };
+template<class T> auto bar(T t) -> bool_c<t()>;
+template<class T> auto bar(T t) -> bool_c<t()>;
+static_assert(decltype(bar(foo{}))::value, "");
new file mode 100644
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++14 } }
+template<int i>
+struct foo {
+ constexpr operator int() { return i; }
+};
+void bar() {
+ [](auto i) -> foo<i> {
+ return {};
+ };
+}
new file mode 100644
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+template <typename T>
+struct foo {
+ auto operator()(T t) -> decltype(t->v);
+};
+
+class bar {
+ friend struct foo<bar*>;
+ int v;
+};
+
+decltype(foo<bar*>{}(nullptr)) x;
new file mode 100644
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+template <typename T>
+struct foo {
+ auto operator()(T t) -> decltype(t->v); // { dg-error "private" }
+};
+
+class bar {
+ int v;
+};
+
+decltype(foo<bar*>{}(nullptr)) x;
--
2.30.2