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:
parent
0735a1c8cf
commit
3a77e7ccc4
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
126
gcc/cp/parser.c
126
gcc/cp/parser.c
@ -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.
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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" }
|
||||
{
|
||||
}
|
||||
|
9
gcc/testsuite/g++.dg/cpp0x/pr79369.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/pr79369.C
Normal 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
|
Loading…
x
Reference in New Issue
Block a user