Beispiel #1
0
void
cxx_print_decl (FILE *file, tree node, int indent)
{
  if (TREE_CODE (node) == FIELD_DECL)
    {
      if (DECL_MUTABLE_P (node))
	{
	  indent_to (file, indent + 3);
	  fprintf (file, " mutable ");
	}
      return;
    }

  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
      || !DECL_LANG_SPECIFIC (node))
    return;
  indent_to (file, indent + 3);
  if (TREE_CODE (node) == FUNCTION_DECL
      && DECL_PENDING_INLINE_INFO (node))
    fprintf (file, " pending-inline-info %p",
	     (void *) DECL_PENDING_INLINE_INFO (node));
  if (TREE_CODE (node) == TYPE_DECL
      && DECL_SORTED_FIELDS (node))
    fprintf (file, " sorted-fields %p",
	     (void *) DECL_SORTED_FIELDS (node));
  if ((TREE_CODE (node) == FUNCTION_DECL || TREE_CODE (node) == VAR_DECL)
      && DECL_TEMPLATE_INFO (node))
    fprintf (file, " template-info %p",
	     (void *) DECL_TEMPLATE_INFO (node));
}
Beispiel #2
0
tree
make_alias_for (tree function, tree newid)
{
    tree alias = build_decl (FUNCTION_DECL, newid, TREE_TYPE (function));
    DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
    cxx_dup_lang_specific_decl (alias);
    DECL_CONTEXT (alias) = NULL;
    TREE_READONLY (alias) = TREE_READONLY (function);
    TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
    TREE_PUBLIC (alias) = 0;
    DECL_INTERFACE_KNOWN (alias) = 1;
    DECL_NOT_REALLY_EXTERN (alias) = 1;
    DECL_THIS_STATIC (alias) = 1;
    DECL_SAVED_FUNCTION_DATA (alias) = NULL;
    DECL_DESTRUCTOR_P (alias) = 0;
    DECL_CONSTRUCTOR_P (alias) = 0;
    DECL_CLONED_FUNCTION (alias) = NULL_TREE;
    DECL_EXTERNAL (alias) = 0;
    DECL_ARTIFICIAL (alias) = 1;
    DECL_NO_STATIC_CHAIN (alias) = 1;
    DECL_PENDING_INLINE_P (alias) = 0;
    DECL_INLINE (alias) = 0;
    DECL_DECLARED_INLINE_P (alias) = 0;
    DECL_DEFERRED_FN (alias) = 0;
    DECL_USE_TEMPLATE (alias) = 0;
    DECL_TEMPLATE_INSTANTIATED (alias) = 0;
    DECL_TEMPLATE_INFO (alias) = NULL;
    DECL_INITIAL (alias) = error_mark_node;
    TREE_ADDRESSABLE (alias) = 1;
    TREE_USED (alias) = 1;
    SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
    return alias;
}
Beispiel #3
0
bool
generic_lambda_fn_p (tree callop)
{
  return (LAMBDA_FUNCTION_P (callop)
	  && DECL_TEMPLATE_INFO (callop)
	  && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop)));
}
Beispiel #4
0
void
cxx_print_decl (FILE *file, tree node, int indent)
{
  if (TREE_CODE (node) == FIELD_DECL)
    {
      if (DECL_MUTABLE_P (node))
	{
	  indent_to (file, indent + 3);
	  fprintf (file, " mutable ");
	}
      return;
    }

  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
      || !DECL_LANG_SPECIFIC (node))
    return;
  if (TREE_CODE (node) == FUNCTION_DECL)
    {
      int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
	|TFF_FUNCTION_DEFAULT_ARGUMENTS|TFF_EXCEPTION_SPECIFICATION ;
      indent_to (file, indent + 3);
      fprintf (file, " full-name \"%s\"", decl_as_string (node, flags));
    }
  else if (TREE_CODE (node) == TEMPLATE_DECL)
    {
      indent_to (file, indent + 3);
      fprintf (file, " full-name \"%s\"",
	       decl_as_string (node, TFF_TEMPLATE_HEADER));
    }

  indent_to (file, indent + 3);
  if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
    fprintf (file, " not-really-extern");
  if (TREE_CODE (node) == FUNCTION_DECL
      && DECL_PENDING_INLINE_INFO (node))
    fprintf (file, " pending-inline-info %p",
	     (void *) DECL_PENDING_INLINE_INFO (node));
  if (VAR_OR_FUNCTION_DECL_P (node)
      && DECL_TEMPLATE_INFO (node))
    fprintf (file, " template-info %p",
	     (void *) DECL_TEMPLATE_INFO (node));
}
Beispiel #5
0
static tree
make_alias_for_thunk (tree function)
{
  tree alias;
  char buf[256];

#if defined (TARGET_IS_PE_COFF)
  if (DECL_ONE_ONLY (function))
    return function;
#endif

  ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
  thunk_labelno++;
  alias = build_decl (FUNCTION_DECL, get_identifier (buf),
		      TREE_TYPE (function));
  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
  cxx_dup_lang_specific_decl (alias);
  DECL_CONTEXT (alias) = NULL;
  TREE_READONLY (alias) = TREE_READONLY (function);
  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
  TREE_PUBLIC (alias) = 0;
  DECL_INTERFACE_KNOWN (alias) = 1;
  DECL_NOT_REALLY_EXTERN (alias) = 1;
  DECL_THIS_STATIC (alias) = 1;
  DECL_SAVED_FUNCTION_DATA (alias) = NULL;
  DECL_DESTRUCTOR_P (alias) = 0;
  DECL_CONSTRUCTOR_P (alias) = 0;
  DECL_CLONED_FUNCTION (alias) = NULL_TREE;
  DECL_EXTERNAL (alias) = 0;
  DECL_ARTIFICIAL (alias) = 1;
  DECL_NO_STATIC_CHAIN (alias) = 1;
  DECL_PENDING_INLINE_P (alias) = 0;
  DECL_INLINE (alias) = 0;
  DECL_DECLARED_INLINE_P (alias) = 0;
  DECL_DEFERRED_FN (alias) = 0;
  DECL_USE_TEMPLATE (alias) = 0;
  DECL_TEMPLATE_INSTANTIATED (alias) = 0;
  DECL_TEMPLATE_INFO (alias) = NULL;
  DECL_INITIAL (alias) = error_mark_node;
  TREE_ADDRESSABLE (alias) = 1;
  TREE_USED (alias) = 1;
  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
  if (!flag_syntax_only)
    assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
  return alias;
}
Beispiel #6
0
tree
make_alias_for (tree target, tree newid)
{
  tree alias = build_decl (DECL_SOURCE_LOCATION (target),
			   TREE_CODE (target), newid, TREE_TYPE (target));
  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (target);
  cxx_dup_lang_specific_decl (alias);
  DECL_CONTEXT (alias) = NULL;
  TREE_READONLY (alias) = TREE_READONLY (target);
  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (target);
  TREE_PUBLIC (alias) = 0;
  DECL_INTERFACE_KNOWN (alias) = 1;
  if (DECL_LANG_SPECIFIC (alias))
    {
      DECL_NOT_REALLY_EXTERN (alias) = 1;
      DECL_USE_TEMPLATE (alias) = 0;
      DECL_TEMPLATE_INFO (alias) = NULL;
    }
  DECL_EXTERNAL (alias) = 0;
  DECL_ARTIFICIAL (alias) = 1;
  DECL_TEMPLATE_INSTANTIATED (alias) = 0;
  if (TREE_CODE (alias) == FUNCTION_DECL)
    {
      DECL_SAVED_FUNCTION_DATA (alias) = NULL;
      DECL_DESTRUCTOR_P (alias) = 0;
      DECL_CONSTRUCTOR_P (alias) = 0;
      DECL_PENDING_INLINE_P (alias) = 0;
      DECL_DECLARED_INLINE_P (alias) = 0;
      DECL_INITIAL (alias) = error_mark_node;
      DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (target));
    }
  else
    TREE_STATIC (alias) = 1;
  TREE_ADDRESSABLE (alias) = 1;
  TREE_USED (alias) = 1;
  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
  return alias;
}
Beispiel #7
0
void
maybe_add_lambda_conv_op (tree type)
{
  bool nested = (cfun != NULL);
  bool nested_def = decl_function_context (TYPE_MAIN_DECL (type));
  tree callop = lambda_function (type);

  if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
    return;

  if (processing_template_decl)
    return;

  bool const generic_lambda_p
    = (DECL_TEMPLATE_INFO (callop)
    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);

  if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE)
    {
      /* If the op() wasn't instantiated due to errors, give up.  */
      gcc_assert (errorcount || sorrycount);
      return;
    }

  /* Non-template conversion operators are defined directly with build_call_a
     and using DIRECT_ARGVEC for arguments (including 'this').  Templates are
     deferred and the CALL is built in-place.  In the case of a deduced return
     call op, the decltype expression, DECLTYPE_CALL, used as a substitute for
     the return type is also built in-place.  The arguments of DECLTYPE_CALL in
     the return expression may differ in flags from those in the body CALL.  In
     particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in
     the body CALL, but not in DECLTYPE_CALL.  */

  vec<tree, va_gc> *direct_argvec = 0;
  tree decltype_call = 0, call = 0;
  tree fn_result = TREE_TYPE (TREE_TYPE (callop));

  if (generic_lambda_p)
    {
      /* Prepare the dependent member call for the static member function
	 '_FUN' and, potentially, prepare another call to be used in a decltype
	 return expression for a deduced return call op to allow for simple
	 implementation of the conversion operator.  */

      tree instance = build_nop (type, null_pointer_node);
      tree objfn = build_min (COMPONENT_REF, NULL_TREE,
			      instance, DECL_NAME (callop), NULL_TREE);
      int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;

      call = prepare_op_call (objfn, nargs);
      if (type_uses_auto (fn_result))
	decltype_call = prepare_op_call (objfn, nargs);
    }
  else
    {
      direct_argvec = make_tree_vector ();
      direct_argvec->quick_push (build1 (NOP_EXPR,
					 TREE_TYPE (DECL_ARGUMENTS (callop)),
					 null_pointer_node));
    }

  /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to
     declare the static member function "_FUN" below.  For each arg append to
     DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated
     call args (for the template case).  If a parameter pack is found, expand
     it, flagging it as PACK_EXPANSION_LOCAL_P for the body call.  */

  tree fn_args = NULL_TREE;
  {
    int ix = 0;
    tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
    tree tgt;

    while (src)
      {
	tree new_node = copy_node (src);

	if (!fn_args)
	  fn_args = tgt = new_node;
	else
	  {
	    TREE_CHAIN (tgt) = new_node;
	    tgt = new_node;
	  }

	mark_exp_read (tgt);

	if (generic_lambda_p)
	  {
	    if (DECL_PACK_P (tgt))
	      {
		tree a = make_pack_expansion (tgt);
		if (decltype_call)
		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
		PACK_EXPANSION_LOCAL_P (a) = true;
		CALL_EXPR_ARG (call, ix) = a;
	      }
	    else
	      {
		tree a = convert_from_reference (tgt);
		CALL_EXPR_ARG (call, ix) = a;
		if (decltype_call)
		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
	      }
	    ++ix;
	  }
	else
	  vec_safe_push (direct_argvec, tgt);

	src = TREE_CHAIN (src);
      }
  }


  if (generic_lambda_p)
    {
      if (decltype_call)
	{
	  ++processing_template_decl;
	  fn_result = finish_decltype_type
	    (decltype_call, /*id_expression_or_member_access_p=*/false,
	     tf_warning_or_error);
	  --processing_template_decl;
	}
    }
  else
    call = build_call_a (callop,
			 direct_argvec->length (),
			 direct_argvec->address ());

  CALL_FROM_THUNK_P (call) = 1;

  tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));

  /* First build up the conversion op.  */

  tree rettype = build_pointer_type (stattype);
  tree name = mangle_conv_op_name_for_type (rettype);
  tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
  tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
  tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
  tree fn = convfn;
  DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);

  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
      && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
    DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;

  SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR);
  grokclassfn (type, fn, NO_SPECIAL);
  set_linkage_according_to_type (type, fn);
  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
  DECL_IN_AGGR_P (fn) = 1;
  DECL_ARTIFICIAL (fn) = 1;
  DECL_NOT_REALLY_EXTERN (fn) = 1;
  DECL_DECLARED_INLINE_P (fn) = 1;
  DECL_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST);
  if (nested_def)
    DECL_INTERFACE_KNOWN (fn) = 1;

  if (generic_lambda_p)
    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));

  add_method (type, fn, NULL_TREE);

  /* Generic thunk code fails for varargs; we'll complain in mark_used if
     the conversion op is used.  */
  if (varargs_function_p (callop))
    {
      DECL_DELETED_FN (fn) = 1;
      return;
    }

  /* Now build up the thunk to be returned.  */

  name = get_identifier ("_FUN");
  tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
  fn = statfn;
  DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
      && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
    DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;
  grokclassfn (type, fn, NO_SPECIAL);
  set_linkage_according_to_type (type, fn);
  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
  DECL_IN_AGGR_P (fn) = 1;
  DECL_ARTIFICIAL (fn) = 1;
  DECL_NOT_REALLY_EXTERN (fn) = 1;
  DECL_DECLARED_INLINE_P (fn) = 1;
  DECL_STATIC_FUNCTION_P (fn) = 1;
  DECL_ARGUMENTS (fn) = fn_args;
  for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
    {
      /* Avoid duplicate -Wshadow warnings.  */
      DECL_NAME (arg) = NULL_TREE;
      DECL_CONTEXT (arg) = fn;
    }
  if (nested_def)
    DECL_INTERFACE_KNOWN (fn) = 1;

  if (generic_lambda_p)
    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));

  add_method (type, fn, NULL_TREE);

  if (nested)
    push_function_context ();
  else
    /* Still increment function_depth so that we don't GC in the
       middle of an expression.  */
    ++function_depth;

  /* Generate the body of the thunk.  */

  start_preparsed_function (statfn, NULL_TREE,
			    SF_PRE_PARSED | SF_INCLASS_INLINE);
  if (DECL_ONE_ONLY (statfn))
    {
      /* Put the thunk in the same comdat group as the call op.  */
      cgraph_node::get_create (statfn)->add_to_same_comdat_group
	(cgraph_node::get_create (callop));
    }
  tree body = begin_function_body ();
  tree compound_stmt = begin_compound_stmt (0);
  if (!generic_lambda_p)
    {
      set_flags_from_callee (call);
      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
	call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
    }
  call = convert_from_reference (call);
  finish_return_stmt (call);

  finish_compound_stmt (compound_stmt);
  finish_function_body (body);

  fn = finish_function (/*inline*/2);
  if (!generic_lambda_p)
    expand_or_defer_fn (fn);

  /* Generate the body of the conversion op.  */

  start_preparsed_function (convfn, NULL_TREE,
			    SF_PRE_PARSED | SF_INCLASS_INLINE);
  body = begin_function_body ();
  compound_stmt = begin_compound_stmt (0);

  /* decl_needed_p needs to see that it's used.  */
  TREE_USED (statfn) = 1;
  finish_return_stmt (decay_conversion (statfn, tf_warning_or_error));

  finish_compound_stmt (compound_stmt);
  finish_function_body (body);

  fn = finish_function (/*inline*/2);
  if (!generic_lambda_p)
    expand_or_defer_fn (fn);

  if (nested)
    pop_function_context ();
  else
    --function_depth;
}
Beispiel #8
0
void gcc_plugin_finish_decl(void *gcc_data, void *user_data)
{
    tree decl = (tree) gcc_data;
    tree type = TREE_TYPE(decl);

    // push this onto the pending parameters if necessary.
    if (TREE_CODE(decl) == PARM_DECL) {
        // we should only see parameter declarations for C.
        gcc_assert(!c_dialect_cxx());

        struct XIL_ParamDecl *last = xil_pending_param_decls;
        while (last && last->next) last = last->next;

        struct XIL_ParamDecl *param_decl = xcalloc(1, sizeof(struct XIL_ParamDecl));
        param_decl->decl = decl;
        if (last) last->next = param_decl;
        else xil_pending_param_decls = param_decl;

        return;
    }

    // check for typedefs on structures, and assign the structure a name
    // if one is found.
    if (TREE_CODE(decl) == TYPE_DECL &&
            (TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE)) {
        if (XIL_IsAnonymous(type)) {
            const char *name = IDENTIFIER_POINTER(DECL_NAME(decl));
            XIL_CSUName(type, name);
        }
    }

    // check for a global variable.
    bool is_global = false;

    if (TREE_CODE(decl) == VAR_DECL) {
        if (DECL_CONTEXT(decl) == NULL)
            is_global = true;
        if (TREE_STATIC(decl))
            is_global = true;
    }

    bool is_function = (TREE_CODE(decl) == FUNCTION_DECL);

    if (!is_global && !is_function)
        return;

    // only processing the output function for annotations.
    if (xil_has_annotation)
        return;

    XIL_Var var = XIL_TranslateVar(decl);
    const char *name = XIL_GetVarName(var);

    // future parameter declarations will be for a different function.
    xil_pending_param_decls = NULL;

    if (!is_global)
        return;

    // check if this is a global variable we want to skip. these are introduced
    // for type information globals.
    static const char *bad_prefix_list[] = {
        "const __class_type_info_pseudo",
        "const __si_class_type_info_pseudo",
        "const __vmi_class_type_info_pseudo",
        "const char _ZTS",
        NULL
    };
    int ind;
    for (ind = 0; bad_prefix_list[ind]; ind++) {
        const char *bad_prefix = bad_prefix_list[ind];
        if (!strncmp(name, bad_prefix, strlen(bad_prefix)))
            return;
    }

    // if the decl is contained in a template class then skip it. we can only
    // handle instantiated declarations, and will only see the uninstantiated
    // declarations here. TODO: is there a way to get these?
    if (DECL_LANG_SPECIFIC(decl) != NULL &&
            DECL_TEMPLATE_INFO(decl) != NULL)
        return;
    tree context = DECL_CONTEXT(decl);
    while (context && TREE_CODE(context) == FUNCTION_DECL) {
        if (DECL_LANG_SPECIFIC(context) != NULL &&
                DECL_TEMPLATE_INFO(context) != NULL)
            return;
        context = DECL_CONTEXT(context);
    }

    // this is a function or global, process any annotation attributes.
    tree attr = DECL_ATTRIBUTES(decl);
    while (attr) {
        XIL_ProcessAnnotationAttr(decl, attr, NULL, NULL);
        attr = TREE_CHAIN(attr);
    }

    // also look for annotations read in from file.
    for (ind = 0; ind < XIL_GetAnnotationCount(name, !is_function, false); ind++) {
        const char *where;
        const char *point_text, *annot_text;
        int trusted;
        XIL_GetAnnotation(name, !is_function, false, ind, &where,
                          &point_text, &annot_text, &trusted);

        // we'll handle loop invariants and point assertions after seeing the
        // function's definition.
        if (!strncmp(where, "loop", 4) || point_text)
            continue;

        XIL_ProcessAnnotationRead(decl, where, point_text, annot_text, trusted);
    }

    XIL_GenerateBlock(decl);
}
Beispiel #9
0
tree
do_friend (tree ctype, tree declarator, tree decl,
           tree attrlist, enum overload_flags flags,
           bool funcdef_flag)
{
    gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
    gcc_assert (!ctype || MAYBE_CLASS_TYPE_P (ctype));

    /* Every decl that gets here is a friend of something.  */
    DECL_FRIEND_P (decl) = 1;

    /* Unfortunately, we have to handle attributes here.  Normally we would
       handle them in start_decl_1, but since this is a friend decl start_decl_1
       never gets to see it.  */

    /* Set attributes here so if duplicate decl, will have proper attributes.  */
    cplus_decl_attributes (&decl, attrlist, 0);

    if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
    {
        declarator = TREE_OPERAND (declarator, 0);
        if (is_overloaded_fn (declarator))
            declarator = DECL_NAME (get_first_fn (declarator));
    }

    if (ctype)
    {
        /* CLASS_TEMPLATE_DEPTH counts the number of template headers for
        the enclosing class.  FRIEND_DEPTH counts the number of template
         headers used for this friend declaration.  TEMPLATE_MEMBER_P is
         true if a template header in FRIEND_DEPTH is intended for
         DECLARATOR.  For example, the code

           template <class T> struct A {
             template <class U> struct B {
               template <class V> template <class W>
        	 friend void C<V>::f(W);
             };
           };

         will eventually give the following results

         1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U').
         2. FRIEND_DEPTH equals 2 (for `V' and `W').
         3. TEMPLATE_MEMBER_P is true (for `W').  */

        int class_template_depth = template_class_depth (current_class_type);
        int friend_depth = processing_template_decl - class_template_depth;
        /* We will figure this out later.  */
        bool template_member_p = false;

        tree cname = TYPE_NAME (ctype);
        if (TREE_CODE (cname) == TYPE_DECL)
            cname = DECL_NAME (cname);

        /* A method friend.  */
        if (flags == NO_SPECIAL && declarator == cname)
            DECL_CONSTRUCTOR_P (decl) = 1;

        grokclassfn (ctype, decl, flags);

        if (friend_depth)
        {
            if (!uses_template_parms_level (ctype, class_template_depth
                                            + friend_depth))
                template_member_p = true;
        }

        /* A nested class may declare a member of an enclosing class
        to be a friend, so we do lookup here even if CTYPE is in
         the process of being defined.  */
        if (class_template_depth
                || COMPLETE_TYPE_P (ctype)
                || (CLASS_TYPE_P (ctype) && TYPE_BEING_DEFINED (ctype)))
        {
            if (DECL_TEMPLATE_INFO (decl))
                /* DECL is a template specialization.  No need to
                   build a new TEMPLATE_DECL.  */
                ;
            else if (class_template_depth)
                /* We rely on tsubst_friend_function to check the
                   validity of the declaration later.  */
                decl = push_template_decl_real (decl, /*is_friend=*/true);
            else
                decl = check_classfn (ctype, decl,
                                      template_member_p
                                      ? current_template_parms
                                      : NULL_TREE);

            if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
                decl = DECL_TI_TEMPLATE (decl);

            if (decl)
                add_friend (current_class_type, decl, /*complain=*/true);
        }
        else
            error ("member %qD declared as friend before type %qT defined",
                   decl, ctype);
    }
    /* A global friend.
       @@ or possibly a friend from a base class ?!?  */
    else if (TREE_CODE (decl) == FUNCTION_DECL)
    {
        int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();

        /* Friends must all go through the overload machinery,
        even though they may not technically be overloaded.

         Note that because classes all wind up being top-level
         in their scope, their friend wind up in top-level scope as well.  */
        if (funcdef_flag)
            SET_DECL_FRIEND_CONTEXT (decl, current_class_type);

        if (! DECL_USE_TEMPLATE (decl))
        {
            /* We must check whether the decl refers to template
               arguments before push_template_decl_real adds a
               reference to the containing template class.  */
            int warn = (warn_nontemplate_friend
                        && ! funcdef_flag && ! is_friend_template
                        && current_template_parms
                        && uses_template_parms (decl));

            if (is_friend_template
                    || template_class_depth (current_class_type) != 0)
                /* We can't call pushdecl for a template class, since in
                   general, such a declaration depends on template
                   parameters.  Instead, we call pushdecl when the class
                   is instantiated.  */
                decl = push_template_decl_real (decl, /*is_friend=*/true);
            else if (current_function_decl)
            {
                /* This must be a local class.  11.5p11:

                If a friend declaration appears in a local class (9.8) and
                 the name specified is an unqualified name, a prior
                 declaration is looked up without considering scopes that
                 are outside the innermost enclosing non-class scope. For a
                 friend function declaration, if there is no prior
                 declaration, the program is ill-formed.  */
                tree t = lookup_name_innermost_nonclass_level (DECL_NAME (decl));
                if (t)
                    decl = pushdecl_maybe_friend (decl, /*is_friend=*/true);
                else
                {
                    error ("friend declaration %qD in local class without "
                           "prior declaration", decl);
                    return error_mark_node;
                }
            }
            else
            {
                /* We can't use pushdecl, as we might be in a template
                class specialization, and pushdecl will insert an
                 unqualified friend decl into the template parameter
                 scope, rather than the namespace containing it.  */
                tree ns = decl_namespace_context (decl);

                push_nested_namespace (ns);
                decl = pushdecl_namespace_level (decl, /*is_friend=*/true);
                pop_nested_namespace (ns);
            }

            if (warn)
            {
                static int explained;
                bool warned;

                warned = warning (OPT_Wnon_template_friend, "friend declaration "
                                  "%q#D declares a non-template function", decl);
                if (! explained && warned)
                {
                    inform (input_location, "(if this is not what you intended, make sure "
                            "the function template has already been declared "
                            "and add <> after the function name here) ");
                    explained = 1;
                }
            }
        }

        if (decl == error_mark_node)
            return error_mark_node;

        add_friend (current_class_type,
                    is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
                    /*complain=*/true);
        DECL_FRIEND_P (decl) = 1;
    }

    return decl;
}
Beispiel #10
0
tree
make_thunk (tree function, bool this_adjusting,
            tree fixed_offset, tree virtual_offset)
{
    HOST_WIDE_INT d;
    tree thunk;

    gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
    /* We can have this thunks to covariant thunks, but not vice versa.  */
    gcc_assert (!DECL_THIS_THUNK_P (function));
    gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting);

    /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */
    if (this_adjusting && virtual_offset)
        virtual_offset
            = size_binop (MULT_EXPR,
                          virtual_offset,
                          convert (ssizetype,
                                   TYPE_SIZE_UNIT (vtable_entry_type)));

    d = tree_low_cst (fixed_offset, 0);

    /* See if we already have the thunk in question.  For this_adjusting
       thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
       will be a BINFO.  */
    for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
        if (DECL_THIS_THUNK_P (thunk) == this_adjusting
                && THUNK_FIXED_OFFSET (thunk) == d
                && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
                && (!virtual_offset
                    || (this_adjusting
                        ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
                                              virtual_offset)
                        : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
            return thunk;

    /* All thunks must be created before FUNCTION is actually emitted;
       the ABI requires that all thunks be emitted together with the
       function to which they transfer control.  */
    gcc_assert (!TREE_ASM_WRITTEN (function));
    /* Likewise, we can only be adding thunks to a function declared in
       the class currently being laid out.  */
    gcc_assert (TYPE_SIZE (DECL_CONTEXT (function))
                && TYPE_BEING_DEFINED (DECL_CONTEXT (function)));

    thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
    DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
    cxx_dup_lang_specific_decl (thunk);
    DECL_THUNKS (thunk) = NULL_TREE;

    DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
    TREE_READONLY (thunk) = TREE_READONLY (function);
    TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
    TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
    SET_DECL_THUNK_P (thunk, this_adjusting);
    THUNK_TARGET (thunk) = function;
    THUNK_FIXED_OFFSET (thunk) = d;
    THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
    THUNK_ALIAS (thunk) = NULL_TREE;

    /* The thunk itself is not a constructor or destructor, even if
       the thing it is thunking to is.  */
    DECL_INTERFACE_KNOWN (thunk) = 1;
    DECL_NOT_REALLY_EXTERN (thunk) = 1;
    DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
    DECL_DESTRUCTOR_P (thunk) = 0;
    DECL_CONSTRUCTOR_P (thunk) = 0;
    DECL_EXTERNAL (thunk) = 1;
    DECL_ARTIFICIAL (thunk) = 1;
    /* Even if this thunk is a member of a local class, we don't
       need a static chain.  */
    DECL_NO_STATIC_CHAIN (thunk) = 1;
    /* The THUNK is not a pending inline, even if the FUNCTION is.  */
    DECL_PENDING_INLINE_P (thunk) = 0;
    DECL_INLINE (thunk) = 0;
    DECL_DECLARED_INLINE_P (thunk) = 0;
    /* Nor has it been deferred.  */
    DECL_DEFERRED_FN (thunk) = 0;
    /* Nor is it a template instantiation.  */
    DECL_USE_TEMPLATE (thunk) = 0;
    DECL_TEMPLATE_INFO (thunk) = NULL;

    /* Add it to the list of thunks associated with FUNCTION.  */
    TREE_CHAIN (thunk) = DECL_THUNKS (function);
    DECL_THUNKS (function) = thunk;

    return thunk;
}