re PR c++/79369 (namespace definition with qualified id)

gcc/cp/
	PR c++/79369
	* cp-tree.h (DECL_NAMESPACE_INLINE_P): New.
	* name-lookup.h (push_namespace): Return int, add make_inline arg.
	* name-lookup.c (push_namespace): Deal with inline directly.
	Return pushed count.
	* parser.c (cp_parser_namespace_definition): Adjust for
	push_namespace change.

	gcc/testsuite/
	* g++.dg/cpp0x/pr65558.C: Adjust diagnostic location.
	* g++.dg/cpp0x/pr79369.C: New.

From-SVN: r248073
This commit is contained in:
Nathan Sidwell 2017-05-15 19:35:52 +00:00
parent 0735a1c8cf
commit 3a77e7ccc4
8 changed files with 168 additions and 158 deletions

View file

@ -1,3 +1,13 @@
2017-05-15 Nathan Sidwell <nathan@acm.org>
PR c++/79369
* cp-tree.h (DECL_NAMESPACE_INLINE_P): New.
* name-lookup.h (push_namespace): Return int, add make_inline arg.
* name-lookup.c (push_namespace): Deal with inline directly.
Return pushed count.
* parser.c (cp_parser_namespace_definition): Adjust for
push_namespace change.
2017-05-11 Nathan Sidwell <nathan@acm.org> 2017-05-11 Nathan Sidwell <nathan@acm.org>
* cp-lang.c (get_global_decls, cxx_pushdecl, LANG_HOOK_GETDECLS, * cp-lang.c (get_global_decls, cxx_pushdecl, LANG_HOOK_GETDECLS,

View file

@ -333,6 +333,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
FOLD_EXPR_MODOP_P (*_FOLD_EXPR) FOLD_EXPR_MODOP_P (*_FOLD_EXPR)
IF_STMT_CONSTEXPR_P (IF_STMT) IF_STMT_CONSTEXPR_P (IF_STMT)
TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM) TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG. TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE. TEMPLATE_PARMS_FOR_INLINE.
@ -2916,6 +2917,10 @@ struct GTY(()) lang_decl {
#define LOCAL_CLASS_P(NODE) \ #define LOCAL_CLASS_P(NODE) \
(decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE) (decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE)
/* Whether the namepace is an inline namespace. */
#define DECL_NAMESPACE_INLINE_P(NODE) \
TREE_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE))
/* For a NAMESPACE_DECL: the list of using namespace directives /* For a NAMESPACE_DECL: the list of using namespace directives
The PURPOSE is the used namespace, the value is the namespace The PURPOSE is the used namespace, the value is the namespace
that is the common ancestor. */ that is the common ancestor. */

View file

@ -6441,107 +6441,112 @@ pop_from_top_level (void)
timevar_cond_stop (TV_NAME_LOOKUP, subtime); timevar_cond_stop (TV_NAME_LOOKUP, subtime);
} }
/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we /* Push into the scope of the NAME namespace. If NAME is NULL_TREE,
select a name that is unique to this compilation unit. Returns FALSE if then we enter an anonymous namespace. If MAKE_INLINE is true, then
pushdecl fails, TRUE otherwise. */ we create an inline namespace (it is up to the caller to check upon
redefinition). Return the number of namespaces entered. */
bool int
push_namespace (tree name) push_namespace (tree name, bool make_inline)
{ {
tree d = NULL_TREE;
bool need_new = true;
bool implicit_use = false;
bool anon = !name;
bool subtime = timevar_cond_start (TV_NAME_LOOKUP); bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
int count = 0;
/* We should not get here if the global_namespace is not yet constructed /* We should not get here if the global_namespace is not yet constructed
nor if NAME designates the global namespace: The global scope is nor if NAME designates the global namespace: The global scope is
constructed elsewhere. */ constructed elsewhere. */
gcc_assert (global_namespace != NULL && name != global_identifier); gcc_assert (global_namespace != NULL && name != global_identifier);
if (anon) if (!name)
name = anon_identifier;
/* Check whether this is an extended namespace definition. */
tree ns = get_namespace_binding (current_namespace, name);
if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
{ {
name = anon_identifier; if (tree dna = DECL_NAMESPACE_ALIAS (ns))
d = get_namespace_binding (current_namespace, name);
if (d)
/* Reopening anonymous namespace. */
need_new = false;
implicit_use = true;
}
else
{
/* Check whether this is an extended namespace definition. */
d = get_namespace_binding (current_namespace, name);
if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
{ {
tree dna = DECL_NAMESPACE_ALIAS (d); /* We do some error recovery for, eg, the redeclaration of M
if (dna) here:
{
/* We do some error recovery for, eg, the redeclaration
of M here:
namespace N {} namespace N {}
namespace M = N; namespace M = N;
namespace M {} namespace M {}
However, in nasty cases like: However, in nasty cases like:
namespace N namespace N
{ {
namespace M = N; namespace M = N;
namespace M {} namespace M {}
} }
we just error out below, in duplicate_decls. */ we just error out below, in duplicate_decls. */
if (NAMESPACE_LEVEL (dna)->level_chain if (NAMESPACE_LEVEL (dna)->level_chain == current_binding_level)
== current_binding_level) {
{ error ("namespace alias %qD not allowed here, "
error ("namespace alias %qD not allowed here, " "assuming %qD", ns, dna);
"assuming %qD", d, dna); ns = dna;
d = dna;
need_new = false;
}
} }
else else
need_new = false; ns = NULL_TREE;
} }
} }
if (need_new)
{
/* Make a new namespace, binding the name to it. */
d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace);
/* The name of this namespace is not visible to other translation
units if it is an anonymous namespace or member thereof. */
if (anon || decl_anon_ns_mem_p (current_namespace))
TREE_PUBLIC (d) = 0;
else
TREE_PUBLIC (d) = 1;
if (pushdecl (d) == error_mark_node)
{
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return false;
}
if (anon)
{
/* Clear DECL_NAME for the benefit of debugging back ends. */
SET_DECL_ASSEMBLER_NAME (d, name);
DECL_NAME (d) = NULL_TREE;
}
begin_scope (sk_namespace, d);
}
else else
resume_scope (NAMESPACE_LEVEL (d)); ns = NULL_TREE;
if (implicit_use) bool new_ns = false;
do_using_directive (d); if (!ns)
/* Enter the name space. */ {
current_namespace = d; ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace);
new_ns = true;
if (pushdecl (ns) == error_mark_node)
ns = NULL_TREE;
else
{
if (name == anon_identifier)
{
/* Clear DECL_NAME for the benefit of debugging back ends. */
SET_DECL_ASSEMBLER_NAME (ns, name);
DECL_NAME (ns) = NULL_TREE;
if (!make_inline)
do_using_directive (ns);
}
else if (TREE_PUBLIC (current_namespace))
TREE_PUBLIC (ns) = 1;
if (make_inline)
{
DECL_NAMESPACE_INLINE_P (ns) = true;
/* Set up namespace association. */
DECL_NAMESPACE_ASSOCIATIONS (ns)
= tree_cons (current_namespace, NULL_TREE, NULL_TREE);
/* Import the contents of the inline namespace. */
do_using_directive (ns);
}
}
}
if (ns)
{
if (make_inline && !DECL_NAMESPACE_INLINE_P (ns))
{
error ("inline namespace must be specified at initial definition");
inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns);
}
if (new_ns)
begin_scope (sk_namespace, ns);
else
resume_scope (NAMESPACE_LEVEL (ns));
current_namespace = ns;
count++;
}
timevar_cond_stop (TV_NAME_LOOKUP, subtime); timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return true; return count;
} }
/* Pop from the scope of the current namespace. */ /* Pop from the scope of the current namespace. */

View file

@ -340,7 +340,7 @@ extern tree pushdecl (tree, bool is_friend = false);
extern tree pushdecl_top_level (tree, bool is_friend = false); extern tree pushdecl_top_level (tree, bool is_friend = false);
extern tree pushdecl_top_level_and_finish (tree, tree); extern tree pushdecl_top_level_and_finish (tree, tree);
extern tree pushtag (tree, tree, tag_scope); extern tree pushtag (tree, tree, tag_scope);
extern bool push_namespace (tree); extern int push_namespace (tree, bool make_inline = false);
extern void pop_namespace (void); extern void pop_namespace (void);
extern void push_nested_namespace (tree); extern void push_nested_namespace (tree);
extern void pop_nested_namespace (tree); extern void pop_nested_namespace (tree);

View file

@ -18172,114 +18172,88 @@ cp_parser_namespace_name (cp_parser* parser)
static void static void
cp_parser_namespace_definition (cp_parser* parser) cp_parser_namespace_definition (cp_parser* parser)
{ {
tree identifier, attribs; tree identifier;
bool has_visibility;
bool is_inline;
cp_token* token;
int nested_definition_count = 0; int nested_definition_count = 0;
cp_ensure_no_omp_declare_simd (parser); cp_ensure_no_omp_declare_simd (parser);
cp_ensure_no_oacc_routine (parser); cp_ensure_no_oacc_routine (parser);
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
bool is_inline = cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE);
if (is_inline)
{ {
maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES);
is_inline = true;
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
else
is_inline = false;
/* Look for the `namespace' keyword. */ /* Look for the `namespace' keyword. */
token = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); cp_token* token
= cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
/* Parse any specified attributes before the identifier. */ /* Parse any specified attributes before the identifier. */
attribs = cp_parser_attributes_opt (parser); tree attribs = cp_parser_attributes_opt (parser);
/* Get the name of the namespace. We do not attempt to distinguish for (;;)
between an original-namespace-definition and an
extension-namespace-definition at this point. The semantic
analysis routines are responsible for that. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
/* Parse any specified attributes after the identifier. */
tree post_ident_attribs = cp_parser_attributes_opt (parser);
if (post_ident_attribs)
{ {
if (attribs) identifier = NULL_TREE;
attribs = chainon (attribs, post_ident_attribs);
else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
attribs = post_ident_attribs; {
} identifier = cp_parser_identifier (parser);
/* Start the namespace. */ /* Parse any attributes specified after the identifier. */
bool ok = push_namespace (identifier); attribs = chainon (attribs, cp_parser_attributes_opt (parser));
}
/* Parse any nested namespace definition. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) break;
{
if (attribs) if (!nested_definition_count && cxx_dialect < cxx1z)
error_at (token->location, "a nested namespace definition cannot have attributes");
if (cxx_dialect < cxx1z)
pedwarn (input_location, OPT_Wpedantic, pedwarn (input_location, OPT_Wpedantic,
"nested namespace definitions only available with " "nested namespace definitions only available with "
"-std=c++1z or -std=gnu++1z"); "-std=c++1z or -std=gnu++1z");
if (is_inline)
error_at (token->location, "a nested namespace definition cannot be inline"); /* Nested namespace names can create new namespaces (unlike
while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) other qualified-ids). */
{ if (int count = identifier ? push_namespace (identifier) : 0)
cp_lexer_consume_token (parser->lexer); nested_definition_count += count;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) else
identifier = cp_parser_identifier (parser); cp_parser_error (parser, "nested namespace name required");
else cp_lexer_consume_token (parser->lexer);
{
cp_parser_error (parser, "nested identifier required");
break;
}
if (push_namespace (identifier))
++nested_definition_count;
}
} }
if (nested_definition_count && !identifier)
cp_parser_error (parser, "namespace name required");
if (nested_definition_count && attribs)
error_at (token->location,
"a nested namespace definition cannot have attributes");
if (nested_definition_count && is_inline)
error_at (token->location,
"a nested namespace definition cannot be inline");
/* Start the namespace. */
nested_definition_count += push_namespace (identifier, is_inline);
bool has_visibility = handle_namespace_attrs (current_namespace, attribs);
warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
/* Look for the `{' to validate starting the namespace. */ /* Look for the `{' to validate starting the namespace. */
cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
/* "inline namespace" is equivalent to a stub namespace definition
followed by a strong using directive. */
if (is_inline && ok)
{
tree name_space = current_namespace;
/* Set up namespace association. */
DECL_NAMESPACE_ASSOCIATIONS (name_space)
= tree_cons (CP_DECL_CONTEXT (name_space), NULL_TREE,
DECL_NAMESPACE_ASSOCIATIONS (name_space));
/* Import the contents of the inline namespace. */
pop_namespace ();
do_using_directive (name_space);
push_namespace (identifier);
}
has_visibility = handle_namespace_attrs (current_namespace, attribs);
warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
/* Parse the body of the namespace. */ /* Parse the body of the namespace. */
cp_parser_namespace_body (parser); cp_parser_namespace_body (parser);
/* Look for the final `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
if (has_visibility) if (has_visibility)
pop_visibility (1); pop_visibility (1);
/* Finish the nested namespace definitions. */ /* Pop the nested namespace definitions. */
while (nested_definition_count--) while (nested_definition_count--)
pop_namespace (); pop_namespace ();
/* Finish the namespace. */
if (ok)
pop_namespace ();
/* Look for the final `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
} }
/* Parse a namespace-body. /* Parse a namespace-body.

View file

@ -1,7 +1,13 @@
2017-05-15 Nathan Sidwell <nathan@acm.org>
PR c++/79369
* g++.dg/cpp0x/pr65558.C: Adjust diagnostic location.
* g++.dg/cpp0x/pr79369.C: New.
2017-05-15 Steven G. Kargl <kargl@gcc.gnu.org> 2017-05-15 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/80752 PR fortran/80752
gfortran.dg/pr80752.f90: New test. * gfortran.dg/pr80752.f90: New test.
2017-05-15 Uros Bizjak <ubizjak@gmail.com> 2017-05-15 Uros Bizjak <ubizjak@gmail.com>

View file

@ -1,6 +1,7 @@
// PR c++/65558 // PR c++/65558
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
inline namespace __attribute__((__abi_tag__)) inline namespace
{ // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" } __attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
{
} }

View file

@ -0,0 +1,9 @@
// { dg-do compile { target c++11 } }
// PR c++/79369 accept late inline of namespace
namespace X {}
inline namespace X {} // { dg-error "must be specified" }
inline namespace Y {}
namespace Y {} // OK
inline namespace Y {} // also Ok