/* Default language-specific hooks.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2001-2020 Free Software Foundation, Inc.
Contributed by Alexandre Oliva <aoliva@redhat.com>
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "timevar.h"
+#include "stringpool.h"
+#include "diagnostic.h"
#include "intl.h"
-#include "tm.h"
#include "toplev.h"
-#include "tree.h"
-#include "tree-inline.h"
-#include "gimple.h"
-#include "rtl.h"
-#include "insn-config.h"
-#include "integrate.h"
-#include "flags.h"
+#include "attribs.h"
+#include "gimplify.h"
#include "langhooks.h"
-#include "target.h"
-#include "langhooks-def.h"
-#include "ggc.h"
-#include "diagnostic.h"
-#include "cgraph.h"
+#include "tree-diagnostic.h"
#include "output.h"
+#include "timevar.h"
+#include "stor-layout.h"
/* Do nothing; in many cases the default hook. */
return t;
}
-/* Do nothing (int). */
-
-void
-lhd_do_nothing_i (int ARG_UNUSED (i))
-{
-}
-
/* Do nothing (int, int, int). Return NULL_TREE. */
tree
/* Do nothing (return NULL_TREE). */
-tree
-lhd_return_null_tree_v (void)
-{
- return NULL_TREE;
-}
-
-/* Do nothing (return NULL_TREE). */
-
tree
lhd_return_null_tree (tree ARG_UNUSED (t))
{
{
/* Excess precision other than "fast" requires front-end
support. */
- flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+ flag_excess_precision = EXCESS_PRECISION_FAST;
return false;
}
{
}
-/* Called from check_global_declarations. */
+/* Called from check_global_declaration. */
bool
lhd_warn_unused_global_decl (const_tree decl)
{
- /* This is what used to exist in check_global_declarations. Probably
+ /* This is what used to exist in check_global_declaration. Probably
not many of these actually apply to non-C languages. */
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl))
return false;
- if (TREE_CODE (decl) == VAR_DECL && TREE_READONLY (decl))
+ if (VAR_P (decl) && TREE_READONLY (decl))
return false;
if (DECL_IN_SYSTEM_HEADER (decl))
return false;
{
tree id;
+ /* set_decl_assembler_name may be called on TYPE_DECL to record ODR
+ name for C++ types. By default types have no ODR names. */
+ if (TREE_CODE (decl) == TYPE_DECL)
+ return;
+
/* The language-independent code should never use the
DECL_ASSEMBLER_NAME for lots of DECLs. Only FUNCTION_DECLs and
VAR_DECLs for variables with static storage duration need a real
DECL_ASSEMBLER_NAME. */
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
- || (TREE_CODE (decl) == VAR_DECL
+ || (VAR_P (decl)
&& (TREE_STATIC (decl)
|| DECL_EXTERNAL (decl)
|| TREE_PUBLIC (decl))));
-
+
/* By default, assume the name to use in assembly code is the same
as that used in the source language. (That's correct for C, and
GCC used to set DECL_ASSEMBLER_NAME to the same value as
compatibility with existing front-ends. This assumption is wrapped
in a target hook, to allow for target-specific modification of the
identifier.
-
+
Can't use just the variable's own name for a variable whose scope
is less than the whole compilation. Concatenate a distinguishing
- number - we use the DECL_UID. */
+ number. */
- if (TREE_PUBLIC (decl) || DECL_CONTEXT (decl) == NULL_TREE)
+ if (TREE_PUBLIC (decl) || DECL_FILE_SCOPE_P (decl))
id = targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl));
else
{
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ static unsigned long num;
char *label;
-
- ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
+
+ ASM_FORMAT_PRIVATE_NAME (label, name, num++);
id = get_identifier (label);
}
+
SET_DECL_ASSEMBLER_NAME (decl, id);
+}
+/* Forcibly overwrite the DECL_ASSEMBLER_NAME for DECL to NAME. */
+void
+lhd_overwrite_decl_assembler_name (tree decl, tree name)
+{
+ DECL_ASSEMBLER_NAME_RAW (decl) = name;
}
/* Type promotion for variable arguments. */
/* Invalid use of an incomplete type. */
void
-lhd_incomplete_type_error (const_tree ARG_UNUSED (value), const_tree type)
+lhd_incomplete_type_error (location_t ARG_UNUSED (loc),
+ const_tree ARG_UNUSED (value), const_tree type)
{
gcc_assert (TREE_CODE (type) == ERROR_MARK);
return;
}
/* lang_hooks.tree_size: Determine the size of a tree with code C,
- which is a language-specific tree code in category tcc_constant or
- tcc_exceptional. The default expects never to be called. */
+ which is a language-specific tree code in category tcc_constant,
+ tcc_exceptional or tcc_type. The default expects never to be called. */
size_t
lhd_tree_size (enum tree_code c ATTRIBUTE_UNUSED)
{
return true;
}
-/* lang_hooks.decls.final_write_globals: perform final processing on
- global variables. */
+/* Generic global declaration processing. This is meant to be called
+ by the front-ends at the end of parsing. C/C++ do their own thing,
+ but other front-ends may call this. */
+
void
-write_global_declarations (void)
+global_decl_processing (void)
{
tree globals, decl, *vec;
int len, i;
- /* This lang hook is dual-purposed, and also finalizes the
- compilation unit. */
- cgraph_finalize_compilation_unit ();
-
+ timevar_stop (TV_PHASE_PARSING);
+ timevar_start (TV_PHASE_DEFERRED);
/* Really define vars that have had only a tentative definition.
Really output inline functions that must actually be callable
and have not been output so far. */
/* Process the decls in reverse order--earliest first.
Put them into VEC from back to front, then take out from front. */
- for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
+ for (i = 0, decl = globals; i < len; i++, decl = DECL_CHAIN (decl))
vec[len - i - 1] = decl;
wrapup_global_declarations (vec, len);
- check_global_declarations (vec, len);
- emit_debug_global_declarations (vec, len);
+ timevar_stop (TV_PHASE_DEFERRED);
- /* Clean up. */
+ timevar_start (TV_PHASE_PARSING);
free (vec);
}
/* Called to perform language-specific initialization of CTX. */
void
-lhd_initialize_diagnostics (struct diagnostic_context *ctx ATTRIBUTE_UNUSED)
+lhd_initialize_diagnostics (diagnostic_context *ctx ATTRIBUTE_UNUSED)
+{
+}
+
+/* Called to register dumps. */
+void
+lhd_register_dumps (gcc::dump_manager *)
+{
+}
+
+/* Called to perform language-specific options initialization. */
+void
+lhd_init_options (unsigned int decoded_options_count ATTRIBUTE_UNUSED,
+ struct cl_decoded_option *decoded_options ATTRIBUTE_UNUSED)
{
}
+/* By default, always complain about options for the wrong language. */
+bool
+lhd_complain_wrong_lang_p (const struct cl_option *option ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+/* By default, no language-specific options are valid. */
+bool
+lhd_handle_option (size_t code ATTRIBUTE_UNUSED,
+ const char *arg ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT value ATTRIBUTE_UNUSED,
+ int kind ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED,
+ const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
/* The default function to print out name of current function that caused
an error. */
void
{
if (diagnostic_last_function_changed (context, diagnostic))
{
- const char *old_prefix = context->printer->prefix;
- tree abstract_origin = diagnostic->abstract_origin;
+ char *old_prefix = pp_take_prefix (context->printer);
+ tree abstract_origin = diagnostic_abstract_origin (diagnostic);
char *new_prefix = (file && abstract_origin == NULL)
- ? file_name_as_prefix (file) : NULL;
+ ? file_name_as_prefix (context, file) : NULL;
pp_set_prefix (context->printer, new_prefix);
if (abstract_origin)
{
ao = BLOCK_ABSTRACT_ORIGIN (abstract_origin);
- while (TREE_CODE (ao) == BLOCK
- && BLOCK_ABSTRACT_ORIGIN (ao)
- && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
- ao = BLOCK_ABSTRACT_ORIGIN (ao);
gcc_assert (TREE_CODE (ao) == FUNCTION_DECL);
fndecl = ao;
}
&& BLOCK_ABSTRACT_ORIGIN (block))
{
ao = BLOCK_ABSTRACT_ORIGIN (block);
-
- while (TREE_CODE (ao) == BLOCK
- && BLOCK_ABSTRACT_ORIGIN (ao)
- && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
- ao = BLOCK_ABSTRACT_ORIGIN (ao);
-
if (TREE_CODE (ao) == FUNCTION_DECL)
{
fndecl = ao;
if (fndecl)
{
expanded_location s = expand_location (*locus);
- pp_character (context->printer, ',');
+ pp_comma (context->printer);
pp_newline (context->printer);
if (s.file != NULL)
{
- if (flag_show_column)
+ if (context->show_column)
pp_printf (context->printer,
- _(" inlined from %qs at %s:%d:%d"),
+ _(" inlined from %qs at %r%s:%d:%d%R"),
identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)),
- s.file, s.line, s.column);
+ "locus", s.file, s.line, s.column);
else
pp_printf (context->printer,
- _(" inlined from %qs at %s:%d"),
+ _(" inlined from %qs at %r%s:%d%R"),
identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)),
- s.file, s.line);
+ "locus", s.file, s.line);
}
else
identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2)));
}
}
- pp_character (context->printer, ':');
+ pp_colon (context->printer);
}
diagnostic_set_last_function (context, diagnostic);
- pp_flush (context->printer);
+ pp_newline_and_flush (context->printer);
context->printer->prefix = old_prefix;
free ((char*) new_prefix);
}
}
tree
-lhd_callgraph_analyze_expr (tree *tp ATTRIBUTE_UNUSED,
- int *walk_subtrees ATTRIBUTE_UNUSED)
+lhd_make_node (enum tree_code code)
{
- return NULL;
+ return make_node (code);
}
+/* Default implementation of LANG_HOOKS_SIMULATE_ENUM_DECL. Assume a
+ simple int-based enumerator (which is all the hook can be used for
+ at present) and push each decl individually without any decoration.
+
+ This definition is suitable for LTO and is generic enough that it
+ might be reusable elsewhere. */
tree
-lhd_make_node (enum tree_code code)
+lhd_simulate_enum_decl (location_t loc, const char *name,
+ vec<string_int_pair> values)
{
- return make_node (code);
+ tree enumtype = lang_hooks.types.make_type (ENUMERAL_TYPE);
+ tree enumdecl = build_decl (loc, TYPE_DECL, get_identifier (name), enumtype);
+ TYPE_STUB_DECL (enumtype) = enumdecl;
+
+ tree value_chain = NULL_TREE;
+ string_int_pair *value;
+ unsigned int i;
+ FOR_EACH_VEC_ELT (values, i, value)
+ {
+ tree value_decl = build_decl (loc, CONST_DECL,
+ get_identifier (value->first), enumtype);
+ DECL_INITIAL (value_decl) = build_int_cst (integer_type_node,
+ value->second);
+ lang_hooks.decls.pushdecl (value_decl);
+ value_chain = tree_cons (value_decl, DECL_INITIAL (value_decl),
+ value_chain);
+ }
+
+ TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (integer_type_node);
+ TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (integer_type_node);
+ SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (integer_type_node));
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
+ layout_type (enumtype);
+ lang_hooks.decls.pushdecl (enumdecl);
+
+ return enumtype;
+}
+
+/* Default implementation of LANG_HOOKS_TYPE_FOR_SIZE.
+ Return an integer type with PRECISION bits of precision,
+ that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
+
+tree
+lhd_type_for_size (unsigned precision, int unsignedp)
+{
+ int i;
+
+ if (precision == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (precision == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (precision == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (precision == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (precision == TYPE_PRECISION (long_long_integer_type_node))
+ return unsignedp
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node;
+
+ for (i = 0; i < NUM_INT_N_ENTS; i ++)
+ if (int_n_enabled_p[i]
+ && precision == int_n_data[i].bitsize)
+ return (unsignedp ? int_n_trees[i].unsigned_type
+ : int_n_trees[i].signed_type);
+
+ if (precision <= TYPE_PRECISION (intQI_type_node))
+ return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
+ if (precision <= TYPE_PRECISION (intHI_type_node))
+ return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+
+ if (precision <= TYPE_PRECISION (intSI_type_node))
+ return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+
+ if (precision <= TYPE_PRECISION (intDI_type_node))
+ return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+
+ if (precision <= TYPE_PRECISION (intTI_type_node))
+ return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+
+ return NULL_TREE;
}
HOST_WIDE_INT
return build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
}
+/* Finalize clause C. */
+
+void
+lhd_omp_finish_clause (tree, gimple_seq *)
+{
+}
+
+/* Return true if DECL is a scalar variable (for the purpose of
+ implicit firstprivatization). */
+
+bool
+lhd_omp_scalar_p (tree decl)
+{
+ tree type = TREE_TYPE (decl);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ type = TREE_TYPE (type);
+ if (INTEGRAL_TYPE_P (type)
+ || SCALAR_FLOAT_TYPE_P (type)
+ || TREE_CODE (type) == POINTER_TYPE)
+ return true;
+ return false;
+}
+
/* Register language specific type size variables as potentially OpenMP
firstprivate variables. */
{
}
-/* Common function for add_builtin_function and
- add_builtin_function_ext_scope. */
+/* Return true if TYPE is an OpenMP mappable type. */
+
+bool
+lhd_omp_mappable_type (tree type)
+{
+ /* Mappable type has to be complete. */
+ if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+ return false;
+ return true;
+}
+
+/* Common function for add_builtin_function, add_builtin_function_ext_scope
+ and simulate_builtin_function_decl. */
+
static tree
-add_builtin_function_common (const char *name,
- tree type,
- int function_code,
- enum built_in_class cl,
- const char *library_name,
- tree attrs,
- tree (*hook) (tree))
+build_builtin_function (location_t location, const char *name, tree type,
+ int function_code, enum built_in_class cl,
+ const char *library_name, tree attrs)
{
tree id = get_identifier (name);
- tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, id, type);
+ tree decl = build_decl (location, FUNCTION_DECL, id, type);
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
- DECL_BUILT_IN_CLASS (decl) = cl;
-
- DECL_FUNCTION_CODE (decl) = (enum built_in_function) function_code;
- /* DECL_FUNCTION_CODE is a bitfield; verify that the value fits. */
- gcc_assert (DECL_FUNCTION_CODE (decl) == function_code);
+ set_decl_built_in_function (decl, cl, function_code);
if (library_name)
{
tree libname = get_identifier (library_name);
+
+ libname = targetm.mangle_decl_assembler_name (decl, libname);
SET_DECL_ASSEMBLER_NAME (decl, libname);
}
else
decl_attributes (&decl, NULL_TREE, 0);
- return hook (decl);
-
+ return decl;
}
/* Create a builtin function. */
const char *library_name,
tree attrs)
{
- return add_builtin_function_common (name, type, function_code, cl,
- library_name, attrs,
- lang_hooks.builtin_function);
+ tree decl = build_builtin_function (BUILTINS_LOCATION, name, type,
+ function_code, cl, library_name, attrs);
+ return lang_hooks.builtin_function (decl);
}
/* Like add_builtin_function, but make sure the scope is the external scope.
const char *library_name,
tree attrs)
{
- return add_builtin_function_common (name, type, function_code, cl,
- library_name, attrs,
- lang_hooks.builtin_function_ext_scope);
+ tree decl = build_builtin_function (BUILTINS_LOCATION, name, type,
+ function_code, cl, library_name, attrs);
+ return lang_hooks.builtin_function_ext_scope (decl);
+}
+
+/* Simulate a declaration of a target-specific built-in function at
+ location LOCATION, as though it had been declared directly in the
+ source language. NAME is the name of the function, TYPE is its function
+ type, FUNCTION_CODE is the target-specific function code, LIBRARY_NAME
+ is the name of the underlying library function (NULL if none) and
+ ATTRS is a list of function attributes.
+
+ Return the decl of the declared function. */
+
+tree
+simulate_builtin_function_decl (location_t location, const char *name,
+ tree type, int function_code,
+ const char *library_name, tree attrs)
+{
+ tree decl = build_builtin_function (location, name, type,
+ function_code, BUILT_IN_MD,
+ library_name, attrs);
+ tree new_decl = lang_hooks.simulate_builtin_function_decl (decl);
+
+ /* Give the front end a chance to create a new decl if necessary,
+ but if the front end discards the decl in favour of a conflicting
+ (erroneous) previous definition, return the decl that we tried but
+ failed to add. This allows the caller to process the returned decl
+ normally, even though the source code won't be able to use it. */
+ if (TREE_CODE (new_decl) == FUNCTION_DECL
+ && fndecl_built_in_p (new_decl, function_code, BUILT_IN_MD))
+ return new_decl;
+
+ return decl;
}
tree
return decl;
}
+/* Create a builtin type. */
+
+tree
+add_builtin_type (const char *name, tree type)
+{
+ tree id = get_identifier (name);
+ tree decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, id, type);
+ return lang_hooks.decls.pushdecl (decl);
+}
+
/* LTO hooks. */
/* Used to save and restore any previously active section. */
/* Save the old section so we can restore it in lto_end_asm_section. */
gcc_assert (!saved_section);
saved_section = in_section;
+ if (!saved_section)
+ saved_section = text_section;
/* Create a new section and switch to it. */
- section = get_section (name, SECTION_DEBUG, NULL);
+ section = get_section (name, SECTION_DEBUG | SECTION_EXCLUDE, NULL);
switch_to_section (section);
}
/* Write DATA of length LEN to the current LTO output section. This default
- implementation just calls assemble_string and frees BLOCK. */
+ implementation just calls assemble_string. */
void
-lhd_append_data (const void *data, size_t len, void *block)
+lhd_append_data (const void *data, size_t len, void *)
{
if (data)
- assemble_string ((const char *)data, len);
- free (block);
+ {
+ timevar_push (TV_IPA_LTO_OUTPUT);
+ assemble_string ((const char *)data, len);
+ timevar_pop (TV_IPA_LTO_OUTPUT);
+ }
}
saved_section = NULL;
}
}
+
+/* Default implementation of enum_underlying_base_type using type_for_size. */
+
+tree
+lhd_enum_underlying_base_type (const_tree enum_type)
+{
+ return lang_hooks.types.type_for_size (TYPE_PRECISION (enum_type),
+ TYPE_UNSIGNED (enum_type));
+}
+
+/* Default implementation of LANG_HOOKS_GET_SUBSTRING_LOCATION. */
+
+const char *
+lhd_get_substring_location (const substring_loc &, location_t *)
+{
+ return "unimplemented";
+}
+
+/* Default implementation of LANG_HOOKS_DECL_DWARF_ATTRIBUTE. Don't add
+ any attributes. */
+
+int
+lhd_decl_dwarf_attribute (const_tree, int)
+{
+ return -1;
+}
+
+/* Default implementation of LANG_HOOKS_TYPE_DWARF_ATTRIBUTE. Don't add
+ any attributes. */
+
+int
+lhd_type_dwarf_attribute (const_tree, int)
+{
+ return -1;
+}
+
+/* Default implementation of LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING.
+ Just return TYPE_SIZE_UNIT unadjusted. */
+
+tree
+lhd_unit_size_without_reusable_padding (tree t)
+{
+ return TYPE_SIZE_UNIT (t);
+}
+
+/* Returns true if the current lang_hooks represents the GNU C frontend. */
+
+bool
+lang_GNU_C (void)
+{
+ return (strncmp (lang_hooks.name, "GNU C", 5) == 0
+ && (lang_hooks.name[5] == '\0' || ISDIGIT (lang_hooks.name[5])));
+}
+
+/* Returns true if the current lang_hooks represents the GNU C++ frontend. */
+
+bool
+lang_GNU_CXX (void)
+{
+ return strncmp (lang_hooks.name, "GNU C++", 7) == 0;
+}
+
+/* Returns true if the current lang_hooks represents the GNU Fortran frontend. */
+
+bool
+lang_GNU_Fortran (void)
+{
+ return strncmp (lang_hooks.name, "GNU Fortran", 11) == 0;
+}
+
+/* Returns true if the current lang_hooks represents the GNU Objective-C
+ frontend. */
+
+bool
+lang_GNU_OBJC (void)
+{
+ return strncmp (lang_hooks.name, "GNU Objective-C", 15) == 0;
+}