+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,
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.
#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. */
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)
- {
- name = anon_identifier;
- d = get_namespace_binding (current_namespace, name);
- if (d)
- /* Reopening anonymous namespace. */
- need_new = false;
- implicit_use = true;
- }
- else
+ 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)
{
- /* 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:
-
- namespace N {}
- namespace M = N;
- namespace M {}
-
- However, in nasty cases like:
-
- 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 do some error recovery for, eg, the redeclaration of M
+ here:
+
+ namespace N {}
+ namespace M = N;
+ namespace M {}
+
+ However, in nasty cases like:
+
+ 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", ns, dna);
+ ns = dna;
}
else
- need_new = false;
+ ns = NULL_TREE;
}
}
+ else
+ ns = NULL_TREE;
- if (need_new)
+ bool new_ns = false;
+ if (!ns)
{
- /* 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;
+ 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
- TREE_PUBLIC (d) = 1;
- if (pushdecl (d) == error_mark_node)
{
- timevar_cond_stop (TV_NAME_LOOKUP, subtime);
- return false;
+ 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 (anon)
+ }
+
+ if (ns)
+ {
+ if (make_inline && !DECL_NAMESPACE_INLINE_P (ns))
{
- /* Clear DECL_NAME for the benefit of debugging back ends. */
- SET_DECL_ASSEMBLER_NAME (d, name);
- DECL_NAME (d) = NULL_TREE;
+ error ("inline namespace must be specified at initial definition");
+ inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns);
}
- begin_scope (sk_namespace, d);
+ if (new_ns)
+ begin_scope (sk_namespace, ns);
+ else
+ resume_scope (NAMESPACE_LEVEL (ns));
+ current_namespace = ns;
+ count++;
}
- else
- resume_scope (NAMESPACE_LEVEL (d));
-
- if (implicit_use)
- do_using_directive (d);
- /* Enter the name space. */
- current_namespace = d;
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
- return true;
+ return count;
}
/* Pop from the scope of the current namespace. */
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);
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);
}
- /* Look for the `{' to validate starting the namespace. */
- cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+ 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");
- /* "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);
- }
+ /* Start the namespace. */
+ nested_definition_count += push_namespace (identifier, is_inline);
- has_visibility = handle_namespace_attrs (current_namespace, attribs);
+ 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);
+
/* 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.
+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>
// 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" }
+{
}
--- /dev/null
+// { 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