error_mark_node is returned. Otherwise, OLDDECL is returned.
If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is
- returned. */
+ returned.
+
+ NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */
tree
-duplicate_decls (tree newdecl, tree olddecl)
+duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
{
unsigned olddecl_uid = DECL_UID (olddecl);
- int olddecl_friend = 0, types_match = 0;
+ int olddecl_friend = 0, types_match = 0, hidden_friend = 0;
int new_defines_function = 0;
if (newdecl == olddecl)
if (TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_ARTIFICIAL (olddecl))
{
+ gcc_assert (!DECL_HIDDEN_FRIEND_P (olddecl));
if (TREE_CODE (newdecl) != FUNCTION_DECL)
{
- /* Avoid warnings redeclaring anticipated built-ins. */
+ /* Avoid warnings redeclaring built-ins which have not been
+ explicitly declared. */
if (DECL_ANTICIPATED (olddecl))
return NULL_TREE;
}
else if (!types_match)
{
- /* Avoid warnings redeclaring anticipated built-ins. */
+ /* Avoid warnings redeclaring built-ins which have not been
+ explicitly declared. */
if (DECL_ANTICIPATED (olddecl))
{
/* Deal with fileptr_type_node. FILE type is not known
= TYPE_ARG_TYPES (TREE_TYPE (newdecl));
types_match = decls_match (newdecl, olddecl);
if (types_match)
- return duplicate_decls (newdecl, olddecl);
+ return duplicate_decls (newdecl, olddecl,
+ newdecl_is_friend);
TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
}
}
/* Replace the old RTL to avoid problems with inlining. */
COPY_DECL_RTL (newdecl, olddecl);
}
- /* Even if the types match, prefer the new declarations type
- for anticipated built-ins, for exception lists, etc... */
+ /* Even if the types match, prefer the new declarations type for
+ built-ins which have not been explicitly declared, for
+ exception lists, etc... */
else if (DECL_ANTICIPATED (olddecl))
{
tree type = TREE_TYPE (newdecl);
/* Don't warn about extern decl followed by definition. */
&& !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))
/* Don't warn about friends, let add_friend take care of it. */
- && ! (DECL_FRIEND_P (newdecl) || DECL_FRIEND_P (olddecl)))
+ && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl)))
{
warning (0, "redundant redeclaration of %qD in same scope", newdecl);
warning (0, "previous declaration of %q+D", olddecl);
DECL_INITIALIZED_IN_CLASS_P (newdecl)
|= DECL_INITIALIZED_IN_CLASS_P (olddecl);
olddecl_friend = DECL_FRIEND_P (olddecl);
+ hidden_friend = (DECL_ANTICIPATED (olddecl)
+ && DECL_HIDDEN_FRIEND_P (olddecl)
+ && newdecl_is_friend);
/* Only functions have DECL_BEFRIENDING_CLASSES. */
if (TREE_CODE (newdecl) == FUNCTION_DECL
DECL_UID (olddecl) = olddecl_uid;
if (olddecl_friend)
DECL_FRIEND_P (olddecl) = 1;
+ if (hidden_friend)
+ {
+ DECL_ANTICIPATED (olddecl) = 1;
+ DECL_HIDDEN_FRIEND_P (olddecl) = 1;
+ }
/* NEWDECL contains the merged attribute lists.
Update OLDDECL to be the same. */
struct cp_binding_level *b = current_binding_level;
while (b->level_chain->kind != sk_function_parms)
b = b->level_chain;
- pushdecl_with_scope (decl, b);
+ pushdecl_with_scope (decl, b, /*is_friend=*/false);
cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
}
else
if (libname)
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
- /* Warn if a function in the namespace for users
- is used without an occasion to consider it declared. */
+ /* A function in the user's namespace should have an explicit
+ declaration before it is used. Mark the built-in function as
+ anticipated but not actually declared. */
if (name[0] != '_' || name[1] != '_')
DECL_ANTICIPATED (decl) = 1;
if (DECL_INITIAL (decl)
&& DECL_INITIALIZED_IN_CLASS_P (field))
error ("duplicate initialization of %qD", decl);
- if (duplicate_decls (decl, field))
+ if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
decl = field;
}
}
> template_class_depth (context))
? current_template_parms
: NULL_TREE);
- if (field && duplicate_decls (decl, field))
+ if (field && duplicate_decls (decl, field,
+ /*newdecl_is_friend=*/false))
decl = field;
}
error ("%q+D declared with an exception specification", object);
}
+/* DECL is a member function or static data member and is presently
+ being defined. Check that the definition is taking place in a
+ valid namespace. */
+
+static void
+check_class_member_definition_namespace (tree decl)
+{
+ /* These checks only apply to member functions and static data
+ members. */
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL);
+ /* We check for problems with specializations in pt.c in
+ check_specialization_namespace, where we can issue better
+ diagnostics. */
+ if (processing_specialization)
+ return;
+ /* There are no restrictions on the placement of
+ explicit instantiations. */
+ if (processing_explicit_instantiation)
+ return;
+ /* [class.mfct]
+
+ A member function definition that appears outside of the
+ class definition shall appear in a namespace scope enclosing
+ the class definition.
+
+ [class.static.data]
+
+ The definition for a static data member shall appear in a
+ namespace scope enclosing the member's class definition. */
+ if (!is_ancestor (current_namespace, DECL_CONTEXT (decl)))
+ pedwarn ("definition of %qD is not in namespace enclosing %qT",
+ decl, DECL_CONTEXT (decl));
+}
+
/* CTYPE is class type, or null if non-class.
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
}
if (ctype)
- DECL_CONTEXT (decl) = ctype;
+ {
+ DECL_CONTEXT (decl) = ctype;
+ if (funcdef_flag)
+ check_class_member_definition_namespace (decl);
+ }
if (ctype == NULL_TREE && DECL_MAIN_P (decl))
{
/* Attempt to merge the declarations. This can fail, in
the case of some invalid specialization declarations. */
pushed_scope = push_scope (ctype);
- ok = duplicate_decls (decl, old_decl);
+ ok = duplicate_decls (decl, old_decl, friendp);
if (pushed_scope)
pop_scope (pushed_scope);
if (!ok)
set_linkage_for_static_data_member (decl);
/* This function is only called with out-of-class definitions. */
DECL_EXTERNAL (decl) = 0;
+ check_class_member_definition_namespace (decl);
}
/* At top level, either `static' or no s.c. makes a definition
(perhaps tentative), and absence of `static' makes it public. */
unqualified_id = dname;
}
- /* If DECLARATOR is non-NULL, we know it is a cdk_id declarator;
- otherwise, we would not have exited the loop above. */
+ /* If TYPE is a FUNCTION_TYPE, but the function name was explicitly
+ qualified with a class-name, turn it into a METHOD_TYPE, unless
+ we know that the function is static. We take advantage of this
+ opportunity to do other processing that pertains to entities
+ explicitly declared to be class members. Note that if DECLARATOR
+ is non-NULL, we know it is a cdk_id declarator; otherwise, we
+ would not have exited the loop above. */
if (declarator
&& declarator->u.id.qualifying_scope
&& TYPE_P (declarator->u.id.qualifying_scope))
}
}
+ /* Now TYPE has the actual type. */
+
if (returned_attrs)
{
if (attrlist)
attrlist = &returned_attrs;
}
- /* Now TYPE has the actual type. */
-
/* Did array size calculations overflow? */
if (TREE_CODE (type) == ARRAY_TYPE
/* Do the necessary processing for the beginning of a function body, which
in this case includes member-initializers, but not the catch clauses of
a function-try-block. Currently, this means opening a binding level
- for the member-initializers (in a ctor) and member cleanups (in a dtor).
- In other functions, this isn't necessary, but it doesn't hurt. */
+ for the member-initializers (in a ctor) and member cleanups (in a dtor). */
tree
begin_function_body (void)
{
tree stmt;
+ if (! FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
+ return NULL_TREE;
+
if (processing_template_decl)
/* Do nothing now. */;
else
void
finish_function_body (tree compstmt)
{
+ if (compstmt == NULL_TREE)
+ return;
+
/* Close the block. */
finish_compound_stmt (compstmt);
finish_destructor_body ();
}
+/* Given a function, returns the BLOCK corresponding to the outermost level
+ of curly braces, skipping the artificial block created for constructor
+ initializers. */
+
+static tree
+outer_curly_brace_block (tree fndecl)
+{
+ tree block = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl));
+ if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
+ /* Skip the artificial function body block. */
+ block = BLOCK_SUBBLOCKS (block);
+ return block;
+}
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
the function so we know that their lifetime always ends with a
return; see g++.dg/opt/nrv6.C. We could be more flexible if
we were to do this optimization in tree-ssa. */
- && (outer = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl)))
- /* Skip the artificial function body block. */
- && (outer = BLOCK_SUBBLOCKS (outer))
+ && (outer = outer_curly_brace_block (fndecl))
&& chain_member (r, BLOCK_VARS (outer)))
finalize_nrv (&DECL_SAVED_TREE (fndecl), r, DECL_RESULT (fndecl));