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>
* 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)
IF_STMT_CONSTEXPR_P (IF_STMT)
TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@ -2916,6 +2917,10 @@ struct GTY(()) lang_decl {
#define LOCAL_CLASS_P(NODE) \
(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
The PURPOSE is the used namespace, the value is the namespace
that is the common ancestor. */

View File

@ -6441,107 +6441,112 @@ pop_from_top_level (void)
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
}
/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
select a name that is unique to this compilation unit. Returns FALSE if
pushdecl fails, TRUE otherwise. */
/* Push into the scope of the NAME namespace. If NAME is NULL_TREE,
then we enter an anonymous namespace. If MAKE_INLINE is true, then
we create an inline namespace (it is up to the caller to check upon
redefinition). Return the number of namespaces entered. */
bool
push_namespace (tree name)
int
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);
int count = 0;
/* We should not get here if the global_namespace is not yet constructed
nor if NAME designates the global namespace: The global scope is
constructed elsewhere. */
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;
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)
if (tree dna = DECL_NAMESPACE_ALIAS (ns))
{
tree dna = DECL_NAMESPACE_ALIAS (d);
if (dna)
{
/* We do some error recovery for, eg, the redeclaration
of M here:
/* We do some error recovery for, eg, the redeclaration of M
here:
namespace N {}
namespace M = N;
namespace M {}
namespace N {}
namespace M = N;
namespace M {}
However, in nasty cases like:
However, in nasty cases like:
namespace N
{
namespace M = N;
namespace M {}
}
namespace N
{
namespace M = N;
namespace M {}
}
we just error out below, in duplicate_decls. */
if (NAMESPACE_LEVEL (dna)->level_chain
== current_binding_level)
{
error ("namespace alias %qD not allowed here, "
"assuming %qD", d, dna);
d = dna;
need_new = false;
}
we just error out below, in duplicate_decls. */
if (NAMESPACE_LEVEL (dna)->level_chain == current_binding_level)
{
error ("namespace alias %qD not allowed here, "
"assuming %qD", ns, dna);
ns = dna;
}
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
resume_scope (NAMESPACE_LEVEL (d));
ns = NULL_TREE;
if (implicit_use)
do_using_directive (d);
/* Enter the name space. */
current_namespace = d;
bool new_ns = false;
if (!ns)
{
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);
return true;
return count;
}
/* 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_and_finish (tree, tree);
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 push_nested_namespace (tree);
extern void pop_nested_namespace (tree);

View File

@ -18172,114 +18172,88 @@ cp_parser_namespace_name (cp_parser* parser)
static void
cp_parser_namespace_definition (cp_parser* parser)
{
tree identifier, attribs;
bool has_visibility;
bool is_inline;
cp_token* token;
tree identifier;
int nested_definition_count = 0;
cp_ensure_no_omp_declare_simd (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);
is_inline = true;
cp_lexer_consume_token (parser->lexer);
}
else
is_inline = false;
/* 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. */
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
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)
for (;;)
{
if (attribs)
attribs = chainon (attribs, post_ident_attribs);
else
attribs = post_ident_attribs;
}
identifier = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
identifier = cp_parser_identifier (parser);
/* Start the namespace. */
bool ok = push_namespace (identifier);
/* Parse any attributes specified after the identifier. */
attribs = chainon (attribs, cp_parser_attributes_opt (parser));
}
/* Parse any nested namespace definition. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
{
if (attribs)
error_at (token->location, "a nested namespace definition cannot have attributes");
if (cxx_dialect < cxx1z)
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE))
break;
if (!nested_definition_count && cxx_dialect < cxx1z)
pedwarn (input_location, OPT_Wpedantic,
"nested namespace definitions only available with "
"-std=c++1z or -std=gnu++1z");
if (is_inline)
error_at (token->location, "a nested namespace definition cannot be inline");
while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
{
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
{
cp_parser_error (parser, "nested identifier required");
break;
}
if (push_namespace (identifier))
++nested_definition_count;
}
/* Nested namespace names can create new namespaces (unlike
other qualified-ids). */
if (int count = identifier ? push_namespace (identifier) : 0)
nested_definition_count += count;
else
cp_parser_error (parser, "nested namespace name required");
cp_lexer_consume_token (parser->lexer);
}
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. */
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. */
cp_parser_namespace_body (parser);
/* Look for the final `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
if (has_visibility)
pop_visibility (1);
/* Finish the nested namespace definitions. */
/* Pop the nested namespace definitions. */
while (nested_definition_count--)
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.

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>
PR fortran/80752
gfortran.dg/pr80752.f90: New test.
* gfortran.dg/pr80752.f90: New test.
2017-05-15 Uros Bizjak <ubizjak@gmail.com>

View File

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