Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?
-- >8 --
The r16-5425 workaround to delay current-instantiation name lookup
within a friend's noexcept-spec is unsound because it considers the
flag cp_noexcept_operand but that indicates a noexcept-expr, not a
noexcept-spec. We don't currently have a usable flag for indicating
a noexcept-spec context, and I don't think we want one.
This patch reverts that workaround and instead makes us properly
delay noexcept-spec parsing of templated friends, which should fully
address the regression since it's only applicable to ahead of time
name lookup at class template scope. Delaying noexcept-spec parsing
of non-templated friends is trickier since it means we need to defer
declaration matching of such friends until after delayed parsing rather
than immediately matching. In contrast, for templated friends we
naturally delay declaration matching until instantiation time.
PR c++/122668
PR c++/114764
gcc/cp/ChangeLog:
* parser.cc (cp_parser_class_specifier): Adjust after
changing the element type of unparsed_noexcepts. Pass
the class type to noexcept_override_late_checks.
(cp_parser_member_declaration): Set
CP_PARSER_FLAGS_DELAY_NOEXCEPT also for templated friends.
(noexcept_override_late_checks): Add class_type parameter.
(cp_parser_single_declaration): Set
CP_PARSER_FLAGS_DELAY_NOEXCEPT also for template friends
at class template scope.
(cp_parser_save_default_args): Push current_class_type
to unparsed_noexcepts.
* parser.h (cp_unparsed_functions_entry::noexcepts):
Change element type to cp_default_arg_entry.
* pt.cc (dependentish_scope_p): Revert r16-5425 changes.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/noexcept91a.C: New test.
---
gcc/cp/parser.cc | 34 ++++++++++++++----------
gcc/cp/parser.h | 2 +-
gcc/cp/pt.cc | 11 +-------
gcc/testsuite/g++.dg/cpp0x/noexcept91a.C | 25 +++++++++++++++++
4 files changed, 47 insertions(+), 25 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index cdfa8f0122d3..6b12efb56a77 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -260,7 +260,7 @@ static cp_token_cache *cp_token_cache_new
static tree cp_parser_late_noexcept_specifier
(cp_parser *, tree);
static void noexcept_override_late_checks
- (tree);
+ (tree, tree);
static void cp_parser_initial_pragma
(cp_token *);
@@ -28982,9 +28982,10 @@ cp_parser_class_specifier (cp_parser* parser)
/* If there are noexcept-specifiers that have not yet been processed,
take care of them now. Do this before processing NSDMIs as they
may depend on noexcept-specifiers already having been processed. */
- FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl)
+ FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, e)
{
- tree ctx = DECL_CONTEXT (decl);
+ decl = e->decl;
+ tree ctx = e->class_type;
switch_to_class (ctx);
tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
@@ -29027,7 +29028,7 @@ cp_parser_class_specifier (cp_parser* parser)
/* The finish_struct call above performed various override checking,
but it skipped unparsed noexcept-specifier operands. Now that we
have resolved them, check again. */
- noexcept_override_late_checks (decl);
+ noexcept_override_late_checks (decl, ctx);
/* Remove any member-function parameters from the symbol table. */
pop_injected_parms ();
@@ -30305,10 +30306,11 @@ cp_parser_member_declaration (cp_parser* parser)
int ctor_dtor_or_conv_p;
bool static_p = (decl_specifiers.storage_class == sc_static);
cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
- /* We can't delay parsing for friends,
- alias-declarations, and typedefs, even though the
- standard seems to require it. */
- if (!friend_p
+ /* We can't delay parsing for alias-declarations and typedefs,
+ even though the standard seems to require it. */
+ /* FIXME: Delay parsing for all friends, not just templated
+ ones (PR114764). */
+ if ((!friend_p || current_template_depth > 0)
&& !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
@@ -31046,9 +31048,9 @@ cp_parser_late_noexcept_specifier (cp_parser *parser,
tree default_arg)
overrides some virtual function with the same signature. */
static void
-noexcept_override_late_checks (tree fndecl)
+noexcept_override_late_checks (tree fndecl, tree class_type)
{
- tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl));
+ tree binfo = TYPE_BINFO (class_type);
tree base_binfo;
if (DECL_STATIC_FUNCTION_P (fndecl))
@@ -35349,9 +35351,10 @@ cp_parser_single_declaration (cp_parser* parser,
|| decl_specifiers.type != error_mark_node))
{
int flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
- /* We don't delay parsing for friends, though CWG 2510 may change
- that. */
- if (member_p && !(friend_p && *friend_p))
+ /* FIXME: Delay parsing for all template friends, not just those
+ at class template scope (PR114764). */
+ if (member_p && (!(friend_p && *friend_p)
+ || current_template_depth > 1))
flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
decl = cp_parser_init_declarator (parser,
flags,
@@ -35854,7 +35857,10 @@ cp_parser_save_default_args (cp_parser* parser, tree
decl)
/* Remember if there is a noexcept-specifier to post process. */
tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
if (UNPARSED_NOEXCEPT_SPEC_P (spec))
- vec_safe_push (unparsed_noexcepts, decl);
+ {
+ cp_default_arg_entry entry = {current_class_type, decl};
+ vec_safe_push (unparsed_noexcepts, entry);
+ }
/* Contracts are deferred. */
for (tree attr = DECL_ATTRIBUTES (decl); attr; attr = TREE_CHAIN (attr))
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 3e7251c38a95..387e4a58e5f4 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -181,7 +181,7 @@ struct GTY(()) cp_unparsed_functions_entry {
vec<tree, va_gc> *nsdmis;
/* Functions with noexcept-specifiers that require post-processing. */
- vec<tree, va_gc> *noexcepts;
+ vec<cp_default_arg_entry, va_gc> *noexcepts;
/* Functions with contract attributes that require post-processing. */
vec<tree, va_gc> *contracts;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ce30b5276638..9fade00ac808 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29064,16 +29064,7 @@ dependent_scope_p (tree scope)
bool
dependentish_scope_p (tree scope)
{
- return dependent_scope_p (scope) || any_dependent_bases_p (scope)
- /* A noexcept-spec is a complete-class context, so this should never hold.
- But since we don't implement deferred noexcept-spec parsing of a friend
- declaration (PR114764) we compensate by treating the current
- instantiation as dependent to avoid bogus name lookup failures in this
- case (PR122668). */
- || (cp_noexcept_operand
- && CLASS_TYPE_P (scope)
- && TYPE_BEING_DEFINED (scope)
- && dependent_type_p (scope));
+ return dependent_scope_p (scope) || any_dependent_bases_p (scope);
}
/* T is a SCOPE_REF. Return whether it represents a non-static member of
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
b/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
new file mode 100644
index 000000000000..d3e44bb677bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
@@ -0,0 +1,25 @@
+// PR c++/122668
+// A version of noexcept91.C that doesn't use a noexcept-expr.
+// { dg-do compile { target c++11 } }
+
+template<class T>
+struct A {
+ friend void f(A& a) noexcept(g(0)) { }
+ static constexpr bool g(int) { return true; }
+};
+
+template<class T>
+struct B {
+ struct C {
+ friend void f(C& a) noexcept(g(0)) { }
+ static constexpr bool g(int) { return true; }
+ };
+};
+
+int main() {
+ A<int> a;
+ static_assert(noexcept(f(a)), "");
+
+ B<int>::C c;
+ static_assert(noexcept(f(c)), "");
+}
--
2.52.0.209.ge85ae279b0