diff --git a/src/gcc-final/overloadable.patch b/src/gcc-final/overloadable.patch new file mode 100644 index 0000000..d18f06f --- /dev/null +++ b/src/gcc-final/overloadable.patch @@ -0,0 +1,1441 @@ +Overload C functions on argument type with gnu::overloadable + +Clang has an "overloadable" attribute that lets several C functions +share a name, chosen between by argument type, with C++ name mangling +applied so that the symbols stay distinct. GCC rejected the idea +upstream. This adds the same feature to the C front end, spelled +__attribute__((overloadable)) or [[gnu::overloadable]]. + +Overload sets need no new data structure. bind already keeps a name's +bindings in a chain sorted by scope depth, and pop_scope unwinds several +bindings of one name in one scope correctly, so pushdecl only has to +decide whether a new declaration redeclares an existing binding or joins +it. Two declarations name the same function when their parameter lists +name the same types; lists that are merely compatible, such as an enum +and the integer type representing it, mangle differently and so +overload. A call is resolved in c_build_function_call_vec, beside the +type-directed overloading GCC already does for the __atomic builtins, +and before convert_arguments, which rewrites the arguments that the +ranking needs. + +Mangling is a new C-subset Itanium writer. cp/mangle.cc cannot be +reused: it is a cc1plus object that needs cp-tree.h and the C++ garbage +collection roots, and TYPE_LANG_SLOT_1 is TYPE_RAISES_EXCEPTIONS there +but TYPE_ACTUAL_ARG_TYPES in the C front end, so it would silently +mangle C function types wrong. The output here was checked against g++ +for every type C can express, substitution compression included. + +Two deliberate differences from Clang, whose documentation does not +describe its own behavior accurately anyway. An overloaded name is +resolved only by a call written directly on it, so taking its address, +or parenthesizing it as in (f) (x), is an error unless the set has a +single member; build_external_ref learns whether a name is being called +from the parser peeking for an open paren, and nothing later in the +front end can tell an unresolved overload from a chosen one. And +_Atomic is mangled as an extended qualifier written outside the +cv-qualifiers, following the ABI grammar and GCC's own C++ front end, +where Clang writes it inside them. + +--- a/gcc/c-family/c-attribs.cc ++++ b/gcc/c-family/c-attribs.cc +@@ -85,6 +85,7 @@ + static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *); + static tree handle_artificial_attribute (tree *, tree, tree, int, bool *); + static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); ++static tree handle_overloadable_attribute (tree *, tree, tree, int, bool *); + static tree handle_error_attribute (tree *, tree, tree, int, bool *); + static tree handle_used_attribute (tree *, tree, tree, int, bool *); + static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *); +@@ -404,6 +405,8 @@ + handle_artificial_attribute, NULL }, + { "flatten", 0, 0, true, false, false, false, + handle_flatten_attribute, NULL }, ++ { "overloadable", 0, 0, true, false, false, false, ++ handle_overloadable_attribute, NULL }, + { "used", 0, 0, true, false, false, false, + handle_used_attribute, NULL }, + { "unused", 0, 0, false, false, false, false, +@@ -1918,6 +1921,33 @@ + return NULL_TREE; + } + ++/* Handle an "overloadable" attribute; arguments as in ++ struct attribute_spec.handler. The C front end lets several ++ functions with this attribute share a name and picks between them by ++ argument type; see c_resolve_overload. In C++ the attribute is ++ accepted but means nothing, since functions already overload and ++ already get the mangling this attribute asks for. */ ++ ++static tree ++handle_overloadable_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, ++ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_DECL) ++ { ++ warning (OPT_Wattributes, "%qE attribute ignored", name); ++ *no_add_attrs = true; ++ } ++ else if (!prototype_p (TREE_TYPE (*node)) ++ && !TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (*node))) ++ { ++ error ("%qE attribute requires a function prototype", name); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ + /* Handle a "warning" or "error" attribute; arguments as in + struct attribute_spec.handler. */ + +--- a/gcc/c/Make-lang.in ++++ b/gcc/c/Make-lang.in +@@ -52,7 +52,7 @@ + # Language-specific object files for C and Objective C. + C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ + c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \ +- c/c-fold.o c/gimple-parser.o \ ++ c/c-fold.o c/c-mangle.o c/gimple-parser.o \ + $(C_COMMON_OBJS) $(C_TARGET_OBJS) + + # Language-specific object files for C. +--- a/gcc/c/c-decl.cc ++++ b/gcc/c/c-decl.cc +@@ -2124,6 +2124,44 @@ + } + } + ++/* If DECL is declared __attribute__((overloadable)), mark it as taking ++ part in overload resolution. This has to happen before pushdecl, ++ which needs to know whether DECL may share its name with others. */ ++ ++static void ++c_mark_overloadable (tree decl) ++{ ++ if (TREE_CODE (decl) == FUNCTION_DECL ++ && lookup_attribute ("overloadable", DECL_ATTRIBUTES (decl))) ++ C_DECL_OVERLOADABLE_P (decl) = 1; ++} ++ ++/* Give DECL, an overloadable function, an Itanium ABI mangled assembler ++ name, since it shares its source name with the rest of its overload ++ set. A name the user asked for with asm ("name"), or one ++ multiversioning has already claimed, wins, so this runs late enough ++ to see it. */ ++ ++static void ++c_mangle_overloadable (tree decl) ++{ ++ tree id; ++ ++ if (TREE_CODE (decl) != FUNCTION_DECL ++ || !lookup_attribute ("overloadable", DECL_ATTRIBUTES (decl)) ++ || DECL_ASSEMBLER_NAME_SET_P (decl)) ++ return; ++ ++ id = c_mangle_overloadable_decl (decl); ++ if (id == NULL_TREE) ++ { ++ sorry_at (DECL_SOURCE_LOCATION (decl), ++ "cannot mangle % function %qD", decl); ++ return; ++ } ++ SET_DECL_ASSEMBLER_NAME (decl, targetm.mangle_decl_assembler_name (decl, id)); ++} ++ + /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. + Returns true if the caller should proceed to merge the two, false + if OLDDECL should simply be discarded. As a side effect, issues +@@ -3378,6 +3416,143 @@ + } + } + ++/* True if DECL was declared __attribute__((overloadable)). */ ++ ++static bool ++c_overloadable_attr_p (tree decl) ++{ ++ return lookup_attribute ("overloadable", DECL_ATTRIBUTES (decl)) != NULL_TREE; ++} ++ ++/* True if X, which is being pushed, and the binding B might belong to ++ the same overload set. This is the guard on every overloading path ++ in pushdecl, so it is deliberately two bit tests. */ ++ ++static bool ++c_overload_involved_p (tree x, struct c_binding *b) ++{ ++ if (TREE_CODE (x) != FUNCTION_DECL) ++ return false; ++ return (C_DECL_OVERLOADABLE_P (x) ++ || (TREE_CODE (b->decl) == FUNCTION_DECL ++ && C_DECL_OVERLOADABLE_P (b->decl))); ++} ++ ++/* True if the binding P is another overload of X rather than a ++ declaration of the same function, so that the walks in pushdecl that ++ look for a previous declaration must step over it. */ ++ ++static bool ++c_overload_skip_binding_p (tree x, struct c_binding *p) ++{ ++ return (TREE_CODE (p->decl) == FUNCTION_DECL ++ && !DECL_IS_UNDECLARED_BUILTIN (p->decl) ++ && c_overload_involved_p (x, p) ++ && !c_parm_lists_compatible_p (TREE_TYPE (x), TREE_TYPE (p->decl))); ++} ++ ++/* X is a FUNCTION_DECL about to be pushed into SCOPE and B is the ++ innermost binding of its name. Return the binding that X redeclares, ++ which may be in an outer or in the external scope, or NULL if X opens ++ or extends an overload set instead. Diagnose a redeclaration that ++ disagrees about the attribute, and a second member of a set that ++ lacks it. Mark every member of the resulting set, including the ++ unmarked one, so that a call can find them all. */ ++ ++static struct c_binding * ++c_overload_resolve_decl (tree x, struct c_binding *b, struct c_scope *scope) ++{ ++ location_t loc = DECL_SOURCE_LOCATION (x); ++ struct c_binding *p; ++ tree unmarked; ++ ++ /* A binding of this name in SCOPE that is not a function at all is an ++ ordinary conflict, not an overload; leave it to pushdecl to report ++ the redeclaration as a different kind of symbol. */ ++ for (p = b; p && B_IN_SCOPE (p, scope); p = p->shadowed) ++ if (TREE_CODE (p->decl) != FUNCTION_DECL) ++ return p; ++ ++ /* A built-in the program has not declared cannot be overloaded: it is ++ not a declaration the program made, and a declaration that ++ conflicts with one is the ordinary case of a program replacing a ++ built-in, which pushdecl already handles and diagnoses. So do ++ nothing until the program has declared something itself. */ ++ for (p = b; p; p = p->shadowed) ++ if (TREE_CODE (p->decl) == FUNCTION_DECL ++ && !DECL_IS_UNDECLARED_BUILTIN (p->decl)) ++ break; ++ if (p == NULL) ++ return b; ++ ++ /* Does X redeclare something? Two functions of the same name are ++ declarations of the same function exactly when their parameter ++ lists are compatible; a difference in the return type is then a ++ conflict, diagnosed as usual by duplicate_decls. The match may be ++ in an outer or in the external scope, in which case the ordinary ++ cross-scope machinery in pushdecl still has to run. */ ++ for (p = b; p; p = p->shadowed) ++ if (TREE_CODE (p->decl) == FUNCTION_DECL ++ && c_parm_lists_compatible_p (TREE_TYPE (x), TREE_TYPE (p->decl))) ++ { ++ if (c_overloadable_attr_p (x) != c_overloadable_attr_p (p->decl)) ++ { ++ auto_diagnostic_group d; ++ error_at (loc, "redeclaration of %qD differs in the " ++ "% attribute", x); ++ inform (DECL_SOURCE_LOCATION (p->decl), ++ "previous declaration of %qD", p->decl); ++ } ++ return p; ++ } ++ ++ /* X is a new member of the set formed by the bindings of this name in ++ SCOPE. At most one member may lack the attribute, and that one ++ keeps its unmangled name. */ ++ unmarked = c_overloadable_attr_p (x) ? NULL_TREE : x; ++ for (p = b; p && B_IN_SCOPE (p, scope); p = p->shadowed) ++ if (TREE_CODE (p->decl) == FUNCTION_DECL) ++ { ++ if (!c_overloadable_attr_p (p->decl)) ++ { ++ if (unmarked) ++ { ++ auto_diagnostic_group d; ++ error_at (loc, "more than one declaration of %qD lacks the " ++ "% attribute", x); ++ inform (DECL_SOURCE_LOCATION (p->decl), ++ "previous declaration of %qD", p->decl); ++ } ++ unmarked = p->decl; ++ } ++ C_DECL_OVERLOADABLE_P (p->decl) = 1; ++ } ++ C_DECL_OVERLOADABLE_P (x) = 1; ++ return NULL; ++} ++ ++/* Collect into CANDS every function that the name ID denotes. A name ++ can have several bindings in one scope only through the overloadable ++ attribute; bind keeps the shadowed chain sorted by non-increasing ++ depth, so the bindings of the innermost scope that declares ID are ++ consecutive at the head of that chain. */ ++ ++void ++c_overload_candidates (tree id, vec *cands) ++{ ++ struct c_binding *b = I_SYMBOL_BINDING (id); ++ unsigned int depth; ++ ++ if (!b) ++ return; ++ depth = b->depth; ++ for (; b && b->depth == depth; b = b->shadowed) ++ if (!b->invisible && TREE_CODE (b->decl) == FUNCTION_DECL) ++ cands->safe_push (b->decl); ++ /* The chain runs newest first; report them as they were written. */ ++ cands->reverse (); ++} ++ + /* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). +@@ -3422,6 +3597,13 @@ + diagnostics). In particular, we should not consider possible + duplicates in the external scope, or shadowing. */ + b = I_SYMBOL_BINDING (name); ++ /* With the overloadable attribute a name can have several bindings in ++ one scope. Replace the innermost binding with the one X actually ++ redeclares; if X opens a new overload, forget the existing bindings ++ so that X is bound afresh below, exactly as a first declaration of ++ the name would be. */ ++ if (b && TREE_CODE (x) == FUNCTION_DECL && c_overload_involved_p (x, b)) ++ b = c_overload_resolve_decl (x, b, scope); + if (b && B_IN_SCOPE (b, scope)) + { + struct c_binding *b_ext, *b_use; +@@ -3439,7 +3621,8 @@ + information only. */ + if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl)) + { +- while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext)) ++ while (b_ext && (!B_IN_EXTERNAL_SCOPE (b_ext) ++ || c_overload_skip_binding_p (x, b_ext))) + b_ext = b_ext->shadowed; + if (b_ext) + { +@@ -3557,8 +3740,16 @@ + warning_at (locus, OPT_Wnested_externs, + "nested extern declaration of %qD", x); + +- while (b && !B_IN_EXTERNAL_SCOPE (b)) ++ while (b && (!B_IN_EXTERNAL_SCOPE (b) ++ || c_overload_skip_binding_p (x, b))) + { ++ /* An unrelated overload in the external scope is only being ++ stepped over; none of the bookkeeping below applies to it. */ ++ if (B_IN_EXTERNAL_SCOPE (b)) ++ { ++ b = b->shadowed; ++ continue; ++ } + /* If this decl might be modified, save its type. This is + done here rather than when the decl is first bound + because the type may change after first binding, through +@@ -3641,7 +3832,9 @@ + } + } + +- if (TREE_CODE (x) != PARM_DECL) ++ /* Another overload of the same name is not a shadowing declaration. */ ++ if (TREE_CODE (x) != PARM_DECL ++ && !(TREE_CODE (x) == FUNCTION_DECL && C_DECL_OVERLOADABLE_P (x))) + warn_if_shadowing (x); + + skip_external_and_shadow_checks: +@@ -5947,6 +6140,8 @@ + error ("versioned declarations are only allowed at file scope"); + } + ++ c_mark_overloadable (decl); ++ + /* Add this decl to the current scope. + TEM may equal DECL or it may be a previous decl of the same name. */ + if (do_push) +@@ -6188,6 +6383,10 @@ + set_user_assembler_name (decl, asmspec); + } + ++ /* Now that any asm name has been applied, an overloadable function ++ that still has no assembler name gets its mangled one. */ ++ c_mangle_overloadable (decl); ++ + /* If #pragma weak was used, mark the decl weak now. */ + maybe_apply_pragma_weak (decl); + +@@ -11017,6 +11216,9 @@ + error ("versioned definitions are only allowed at file scope"); + } + ++ c_mark_overloadable (decl1); ++ c_mangle_overloadable (decl1); ++ + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ +--- /dev/null ++++ b/gcc/c/c-mangle.cc +@@ -0,0 +1,538 @@ ++/* Itanium C++ ABI name mangling for the C front end. ++ Copyright (C) 2025 Free Software Foundation, Inc. ++ ++This file is part of GCC. ++ ++GCC is free software; you can redistribute it and/or modify it under ++the terms of the GNU General Public License as published by the Free ++Software Foundation; either version 3, or (at your option) any later ++version. ++ ++GCC is distributed in the hope that it will be useful, but WITHOUT ANY ++WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ ++ ++/* Functions declared __attribute__((overloadable)) share a source name, ++ so they need distinct assembler names. This produces the same Itanium ++ ABI mangling the C++ front end produces for the same signature, which ++ is also what Clang produces for its "overloadable" attribute. ++ ++ cp/mangle.cc cannot be reused here. It is a cc1plus-only object, it ++ includes cp-tree.h, and it needs the C++ garbage collection roots. ++ Worse, it would be silently wrong: TYPE_LANG_SLOT_1 is ++ TYPE_RAISES_EXCEPTIONS in cp/cp-tree.h but TYPE_ACTUAL_ARG_TYPES in ++ c/c-tree.h, so write_function_type would hand a C argument type list ++ to write_exception_spec. Only the subset of types C can express is ++ needed, so mangle them here instead. The writers below follow their ++ cp/mangle.cc counterparts, minus everything only a C++ type can ++ reach, and every gcc_unreachable becomes a soft failure: a parameter ++ type that cannot be mangled is reported with sorry, never an ICE. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "target.h" ++#include "c-tree.h" ++#include "stringpool.h" ++ ++/* State for one mangling. Both vectors are stack allocated, so this ++ file needs no garbage collection roots. */ ++ ++struct c_mangle_state ++{ ++ auto_vec out; /* The mangled name being built. */ ++ auto_vec subs; /* Substitution candidates, in order. */ ++ bool failed; /* A type could not be mangled. */ ++}; ++ ++static void write_type (c_mangle_state *, tree); ++static void write_parm_types (c_mangle_state *, tree); ++ ++/* Single letter codes for the builtin integer types, indexed by ++ integer_type_kind values, as in cp/mangle.cc. */ ++ ++static const char integer_type_codes[itk_none] = ++{ ++ 'c', /* itk_char */ ++ 'a', /* itk_signed_char */ ++ 'h', /* itk_unsigned_char */ ++ 's', /* itk_short */ ++ 't', /* itk_unsigned_short */ ++ 'i', /* itk_int */ ++ 'j', /* itk_unsigned_int */ ++ 'l', /* itk_long */ ++ 'm', /* itk_unsigned_long */ ++ 'x', /* itk_long_long */ ++ 'y', /* itk_unsigned_long_long */ ++ /* __intN types are handled separately */ ++ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' ++}; ++ ++static void ++write_char (c_mangle_state *s, char c) ++{ ++ s->out.safe_push (c); ++} ++ ++static void ++write_string (c_mangle_state *s, const char *str) ++{ ++ for (; *str; str++) ++ s->out.safe_push (*str); ++} ++ ++/* Write VALUE in base 10, as without a sign. */ ++ ++static void ++write_unsigned_number (c_mangle_state *s, unsigned HOST_WIDE_INT value) ++{ ++ char buf[32]; ++ int i = 0; ++ ++ do ++ { ++ buf[i++] = '0' + (int) (value % 10); ++ value /= 10; ++ } ++ while (value); ++ while (i) ++ write_char (s, buf[--i]); ++} ++ ++/* Write VALUE in base 36 with digits 0-9 and A-Z, as . */ ++ ++static void ++write_seq_id (c_mangle_state *s, unsigned HOST_WIDE_INT value) ++{ ++ char buf[16]; ++ int i = 0; ++ ++ do ++ { ++ unsigned digit = (unsigned) (value % 36); ++ buf[i++] = digit < 10 ? '0' + digit : 'A' + digit - 10; ++ value /= 36; ++ } ++ while (value); ++ while (i) ++ write_char (s, buf[--i]); ++} ++ ++/* ::= */ ++ ++static void ++write_source_name (c_mangle_state *s, tree id) ++{ ++ write_unsigned_number (s, IDENTIFIER_LENGTH (id)); ++ write_string (s, IDENTIFIER_POINTER (id)); ++} ++ ++/* If TYPE has already been mangled, write a reference to it and return ++ true. Types are compared by identity: C types are hashed, and a ++ typedef shares its main variant's node, so this is both sufficient ++ and cheap. It also keeps an enumerated type distinct from the ++ integer type it is compatible with, which comptypes would not. */ ++ ++static bool ++find_substitution (c_mangle_state *s, tree type) ++{ ++ unsigned int i; ++ tree t; ++ ++ FOR_EACH_VEC_ELT (s->subs, i, t) ++ if (t == type) ++ { ++ write_char (s, 'S'); ++ if (i > 0) ++ write_seq_id (s, i - 1); ++ write_char (s, '_'); ++ return true; ++ } ++ return false; ++} ++ ++static void ++add_substitution (c_mangle_state *s, tree type) ++{ ++ s->subs.safe_push (type); ++} ++ ++/* . Unlike the C++ front end's version this does not ++ look for wchar_t, char8_t, char16_t or char32_t: in C those names are ++ typedefs for ordinary integer types, and testing for them would ++ mangle, say, a plain unsigned short as 'w'. */ ++ ++static void ++write_builtin_type (c_mangle_state *s, tree type) ++{ ++ if (TYPE_CANONICAL (type)) ++ type = TYPE_CANONICAL (type); ++ ++ switch (TREE_CODE (type)) ++ { ++ case VOID_TYPE: ++ write_char (s, 'v'); ++ break; ++ ++ case BOOLEAN_TYPE: ++ write_char (s, 'b'); ++ break; ++ ++ case INTEGER_TYPE: ++ { ++ size_t itk; ++ iagain: ++ for (itk = 0; itk < itk_none; ++itk) ++ if (integer_types[itk] != NULL_TREE ++ && integer_type_codes[itk] != '\0' ++ && type == integer_types[itk]) ++ { ++ write_char (s, integer_type_codes[itk]); ++ break; ++ } ++ ++ if (itk == itk_none) ++ { ++ tree t = c_common_type_for_mode (TYPE_MODE (type), ++ TYPE_UNSIGNED (type)); ++ if (t != NULL_TREE && type != t) ++ { ++ type = t; ++ goto iagain; ++ } ++ ++ if (TYPE_PRECISION (type) == 128) ++ write_char (s, TYPE_UNSIGNED (type) ? 'o' : 'n'); ++ else ++ { ++ /* A type that is not one of the shared nodes, such as an ++ __attribute__((mode(...))) integer. Write a vendor ++ extended builtin type named intN or uintN. */ ++ const char *prefix = TYPE_UNSIGNED (type) ? "uint" : "int"; ++ char prec[11]; ++ ++ sprintf (prec, "%u", (unsigned) TYPE_PRECISION (type)); ++ write_char (s, 'u'); ++ write_unsigned_number (s, strlen (prefix) + strlen (prec)); ++ write_string (s, prefix); ++ write_string (s, prec); ++ } ++ } ++ } ++ break; ++ ++ case REAL_TYPE: ++ if (type == float_type_node) ++ write_char (s, 'f'); ++ else if (type == double_type_node) ++ write_char (s, 'd'); ++ else if (type == long_double_type_node) ++ write_char (s, 'e'); ++ else if (type == dfloat32_type_node) ++ write_string (s, "Df"); ++ else if (type == dfloat64_type_node) ++ write_string (s, "Dd"); ++ else if (type == dfloat128_type_node) ++ write_string (s, "De"); ++ else if (type == float16_type_node) ++ write_string (s, "DF16_"); ++ else if (type == float32_type_node) ++ write_string (s, "DF32_"); ++ else if (type == float64_type_node) ++ write_string (s, "DF64_"); ++ else if (type == float128_type_node) ++ write_string (s, "DF128_"); ++ else if (type == float32x_type_node) ++ write_string (s, "DF32x"); ++ else if (type == float64x_type_node) ++ write_string (s, "DF64x"); ++ else if (type == float128x_type_node) ++ write_string (s, "DF128x"); ++ else if (type == bfloat16_type_node) ++ write_string (s, "DF16b"); ++ else ++ s->failed = true; ++ break; ++ ++ default: ++ s->failed = true; ++ break; ++ } ++} ++ ++/* * , written farthest from the base ++ type first. _Atomic is a C qualifier with no C++ spelling, mangled ++ as the vendor extended qualifier Clang uses for it. Returns the ++ number of qualifiers written. Array and function types never carry ++ qualifiers of their own here: the qualifiers of an array belong to ++ its element type. */ ++ ++static int ++write_qualifiers (c_mangle_state *s, tree type) ++{ ++ int quals, num = 0; ++ ++ if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == FUNCTION_TYPE) ++ return 0; ++ ++ quals = TYPE_QUALS (type); ++ if (quals & TYPE_QUAL_ATOMIC) ++ { ++ write_string (s, "U7_Atomic"); ++ ++num; ++ } ++ if (quals & TYPE_QUAL_RESTRICT) ++ { ++ write_char (s, 'r'); ++ ++num; ++ } ++ if (quals & TYPE_QUAL_VOLATILE) ++ { ++ write_char (s, 'V'); ++ ++num; ++ } ++ if (quals & TYPE_QUAL_CONST) ++ { ++ write_char (s, 'K'); ++ ++num; ++ } ++ return num; ++} ++ ++/* ::= A _ ++ An array of unknown size omits the dimension. */ ++ ++static void ++write_array_type (c_mangle_state *s, tree type) ++{ ++ tree domain = TYPE_DOMAIN (type); ++ ++ write_char (s, 'A'); ++ if (domain) ++ { ++ tree max = TYPE_MAX_VALUE (domain); ++ if (max && TREE_CODE (max) == INTEGER_CST) ++ { ++ offset_int wmax = wi::to_offset (max) + 1; ++ wmax = wi::zext (wmax, TYPE_PRECISION (TREE_TYPE (max))); ++ if (!wi::fits_uhwi_p (wmax)) ++ { ++ s->failed = true; ++ return; ++ } ++ write_unsigned_number (s, wmax.to_uhwi ()); ++ } ++ else if (max) ++ { ++ /* A variable length array. Mangling the bound would mean ++ mangling an expression, which C overloads never need. */ ++ s->failed = true; ++ return; ++ } ++ } ++ write_char (s, '_'); ++ write_type (s, TREE_TYPE (type)); ++} ++ ++/* The name TYPE_NAME gives, if it gives one. */ ++ ++static tree ++type_name_identifier (tree type) ++{ ++ tree name = TYPE_NAME (type); ++ ++ if (name == NULL_TREE) ++ return NULL_TREE; ++ if (TREE_CODE (name) == IDENTIFIER_NODE) ++ return name; ++ if (TREE_CODE (name) == TYPE_DECL) ++ return DECL_NAME (name); ++ return NULL_TREE; ++} ++ ++/* The name of a tagged type: its tag, or, for a type that has none, the ++ name of a typedef of it. A typedef builds a named variant of the ++ type it names, so the variants have to be searched; C++ gives such a ++ type its typedef name for linkage in the same way. */ ++ ++static tree ++tag_name (tree type) ++{ ++ tree name = type_name_identifier (type); ++ ++ if (name != NULL_TREE) ++ return name; ++ for (tree v = TYPE_MAIN_VARIANT (type); v; v = TYPE_NEXT_VARIANT (v)) ++ { ++ name = type_name_identifier (v); ++ if (name != NULL_TREE) ++ return name; ++ } ++ return NULL_TREE; ++} ++ ++/* . */ ++ ++static void ++write_type (c_mangle_state *s, tree type) ++{ ++ if (s->failed) ++ return; ++ if (type == NULL_TREE || type == error_mark_node) ++ { ++ s->failed = true; ++ return; ++ } ++ ++ if (find_substitution (s, type)) ++ return; ++ ++ if (write_qualifiers (s, type) > 0) ++ { ++ /* Both the qualified and the unqualified type are substitution ++ candidates, so mangle the unqualified one recursively. */ ++ write_type (s, TYPE_MAIN_VARIANT (type)); ++ add_substitution (s, type); ++ return; ++ } ++ ++ switch (TREE_CODE (type)) ++ { ++ case VOID_TYPE: ++ case BOOLEAN_TYPE: ++ case INTEGER_TYPE: ++ case REAL_TYPE: ++ /* Builtin types are not substitution candidates. */ ++ write_builtin_type (s, type); ++ return; ++ ++ case NULLPTR_TYPE: ++ write_string (s, "Dn"); ++ return; ++ ++ case BITINT_TYPE: ++ write_string (s, TYPE_UNSIGNED (type) ? "DU" : "DB"); ++ write_unsigned_number (s, TYPE_PRECISION (type)); ++ write_char (s, '_'); ++ break; ++ ++ case COMPLEX_TYPE: ++ write_char (s, 'C'); ++ write_type (s, TREE_TYPE (type)); ++ break; ++ ++ case POINTER_TYPE: ++ write_char (s, 'P'); ++ write_type (s, TREE_TYPE (type)); ++ break; ++ ++ case ARRAY_TYPE: ++ write_array_type (s, type); ++ break; ++ ++ case FUNCTION_TYPE: ++ write_char (s, 'F'); ++ write_type (s, TREE_TYPE (type)); ++ write_parm_types (s, type); ++ write_char (s, 'E'); ++ break; ++ ++ case VECTOR_TYPE: ++ { ++ poly_uint64 subparts = TYPE_VECTOR_SUBPARTS (type); ++ if (!subparts.is_constant ()) ++ { ++ s->failed = true; ++ return; ++ } ++ write_string (s, "Dv"); ++ write_unsigned_number (s, subparts.to_constant ()); ++ write_char (s, '_'); ++ write_type (s, TREE_TYPE (type)); ++ } ++ break; ++ ++ case RECORD_TYPE: ++ case UNION_TYPE: ++ case ENUMERAL_TYPE: ++ { ++ tree name = tag_name (type); ++ if (name == NULL_TREE) ++ { ++ s->failed = true; ++ return; ++ } ++ write_source_name (s, name); ++ } ++ break; ++ ++ default: ++ s->failed = true; ++ return; ++ } ++ ++ if (!s->failed) ++ add_substitution (s, type); ++} ++ ++/* The parameter types of FNTYPE, as spells them: ++ a variadic function ends in 'z', and a function taking no arguments ++ is written 'v'. As in C++, top level qualifiers on a parameter are ++ not part of the function type, except that _Atomic is kept, since in ++ C it is part of the type rather than a mere access restriction. */ ++ ++static void ++write_parm_types (c_mangle_state *s, tree fntype) ++{ ++ tree args = TYPE_ARG_TYPES (fntype); ++ tree a; ++ int n = 0; ++ ++ for (a = args; a && a != void_list_node; a = TREE_CHAIN (a)) ++ { ++ tree parm = TREE_VALUE (a); ++ ++ if (parm == NULL_TREE || parm == error_mark_node) ++ { ++ s->failed = true; ++ return; ++ } ++ parm = build_qualified_type (TYPE_MAIN_VARIANT (parm), ++ TYPE_QUALS (parm) & TYPE_QUAL_ATOMIC); ++ write_type (s, parm); ++ ++n; ++ } ++ if (a != void_list_node) ++ { ++ write_char (s, 'z'); ++ ++n; ++ } ++ if (n == 0) ++ write_char (s, 'v'); ++} ++ ++/* Return the mangled assembler name for the overloadable function DECL, ++ or NULL_TREE if some parameter type cannot be mangled. The return ++ type is not mangled, as for a non-template C++ function, which is why ++ two declarations differing only in their return type conflict rather ++ than overload. */ ++ ++tree ++c_mangle_overloadable_decl (tree decl) ++{ ++ c_mangle_state s; ++ ++ s.failed = false; ++ write_string (&s, "_Z"); ++ write_source_name (&s, DECL_NAME (decl)); ++ write_parm_types (&s, TREE_TYPE (decl)); ++ ++ if (s.failed) ++ return NULL_TREE; ++ return get_identifier_with_length (s.out.address (), s.out.length ()); ++} +--- a/gcc/c/c-tree.h ++++ b/gcc/c/c-tree.h +@@ -129,6 +129,12 @@ + sizeof and typeof it is set for other function decls as well. */ + #define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP)) + ++/* For a FUNCTION_DECL, nonzero if it takes part in overload resolution ++ for __attribute__((overloadable)): either it carries the attribute ++ itself, or it is the one member of an overload set that does not. */ ++#define C_DECL_OVERLOADABLE_P(EXP) \ ++ DECL_LANG_FLAG_8 (FUNCTION_DECL_CHECK (EXP)) ++ + /* Record whether a variable has been declared threadprivate by + #pragma omp threadprivate. */ + #define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL)) +@@ -786,7 +792,11 @@ + extern bool c_var_mod_p (tree x, tree fn); + extern alias_set_type c_get_alias_set (tree); + extern int c_type_dwarf_attribute (const_tree, int); ++extern void c_overload_candidates (tree, vec *); + ++/* in c-mangle.cc */ ++extern tree c_mangle_overloadable_decl (tree); ++ + /* in c-typeck.cc */ + extern int in_alignof; + extern int in_sizeof; +@@ -856,6 +866,8 @@ + extern bool comptypes_equiv_p (tree, tree); + extern int comptypes_check_different_types (tree, tree, bool *); + extern int comptypes_check_enum_int (tree, tree, bool *); ++extern bool c_parm_lists_compatible_p (tree, tree); ++extern tree c_resolve_overload (location_t, tree, vec *); + extern bool c_mark_addressable (tree, bool = false, bool = false); + extern void c_incomplete_type_error (location_t, const_tree, const_tree); + extern tree c_type_promotes_to (tree); +--- a/gcc/c/c-typeck.cc ++++ b/gcc/c/c-typeck.cc +@@ -1651,7 +1651,37 @@ + return ret ? (data.warning_needed ? 2 : 1) : 0; + } + ++/* True if the parameter lists of the function types T1 and T2 name the ++ same parameter types, so that two functions of that name are ++ declarations of the same function rather than, with the overloadable ++ attribute, distinct overloads. + ++ Mere compatibility is not enough. An enumerated type is compatible ++ with the integer type that represents it and an array of known size ++ is compatible with one of unknown size, yet each pair mangles ++ differently and so names two different functions; that is also how ++ Clang reads them. comptypes_check_different_types reports exactly ++ this distinction. Giving both types a common return type is the ++ smallest way to reuse function_types_compatible_p; function types are ++ hashed, so this costs nothing after the first call for a signature. */ ++ ++bool ++c_parm_lists_compatible_p (tree t1, tree t2) ++{ ++ tree f1, f2; ++ bool different = false; ++ ++ if (TREE_CODE (t1) != FUNCTION_TYPE || TREE_CODE (t2) != FUNCTION_TYPE) ++ return false; ++ ++ f1 = build_function_type (void_type_node, TYPE_ARG_TYPES (t1), ++ TYPE_NO_NAMED_ARGS_STDARG_P (t1)); ++ f2 = build_function_type (void_type_node, TYPE_ARG_TYPES (t2), ++ TYPE_NO_NAMED_ARGS_STDARG_P (t2)); ++ return comptypes_check_different_types (f1, f2, &different) && !different; ++} ++ ++ + /* Like comptypes, but if it returns true for struct and union types + considered equivalent for aliasing purposes, i.e. for setting + TYPE_CANONICAL after completing a struct or union. +@@ -3905,13 +3935,40 @@ + else if (TREE_DEPRECATED (ref)) + warn_deprecated_use (ref, NULL_TREE); + ++ /* An overload set denotes a function only once a call has picked one ++ of its members. Anywhere else the name cannot be resolved, unless ++ the set happens to have a single member. */ ++ bool overloaded = false; ++ if (TREE_CODE (ref) == FUNCTION_DECL && C_DECL_OVERLOADABLE_P (ref)) ++ { ++ auto_vec cands; ++ ++ c_overload_candidates (id, &cands); ++ if (cands.length () > 1) ++ { ++ if (!fun) ++ { ++ auto_diagnostic_group d; ++ error_at (loc, "cannot resolve overloaded function %qE outside " ++ "of a function call", id); ++ for (tree cand : cands) ++ inform (DECL_SOURCE_LOCATION (cand), "candidate: %qD", cand); ++ return error_mark_node; ++ } ++ overloaded = true; ++ } ++ } ++ + /* Recursive call does not count as usage. */ +- if (ref != current_function_decl) ++ if (ref != current_function_decl && !overloaded) + { + TREE_USED (ref) = 1; + } + +- mark_decl_used (ref, false); ++ /* For an overload set, c_resolve_overload records the use instead, on ++ whichever member the call actually selects. */ ++ if (!overloaded) ++ mark_decl_used (ref, false); + + if (TREE_CODE (ref) == CONST_DECL) + { +@@ -4494,64 +4551,299 @@ + return require_complete_type (loc, result); + } + +-/* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ ++/* How good a conversion is, for picking between the members of an ++ __attribute__((overloadable)) set. Smaller is better. */ + +-tree +-c_build_function_call_vec (location_t loc, const vec &arg_loc, +- tree function, vec *params, +- vec *origtypes) ++enum c_conv_rank + { +- /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ +- STRIP_TYPE_NOPS (function); ++ ck_exact, /* Compatible, or a qualification conversion. */ ++ ck_promotion, /* An integer or floating-point promotion. */ ++ ck_conversion, /* Any other conversion C performs quietly. */ ++ ck_bad_pointer, /* Between incompatible pointer types. */ ++ ck_ellipsis, /* Matched by "...". */ ++ ck_none /* Not a conversion; the candidate is not viable. */ ++}; + +- /* Convert anything with function type to a pointer-to-function. */ +- if (TREE_CODE (function) == FUNCTION_DECL) ++/* Rank the conversion of the argument ARG to the parameter type TO. ++ ++ The ranking follows the C++ rules, with the differences C needs. A ++ conversion between compatible but distinct types, such as an enum and ++ the integer type it is compatible with, is a conversion rather than ++ an exact match, so it loses to an exact match and ties with an ++ arithmetic conversion. Widening from float is a promotion whether ++ the target is double or long double, per C99 rather than C++, so a ++ float argument does not prefer double over long double. A conversion ++ between incompatible pointer types is ranked below every other ++ conversion; the ordinary C diagnostic for it is emitted later, by ++ convert_arguments, once a candidate has been chosen. */ ++ ++static enum c_conv_rank ++c_rank_conversion (tree arg, tree to) ++{ ++ tree from = TREE_TYPE (arg); ++ bool different = false; ++ ++ if (from == NULL_TREE || to == NULL_TREE ++ || from == error_mark_node || to == error_mark_node) ++ return ck_none; ++ ++ /* An argument that is an array or a function designator decays. */ ++ if (TREE_CODE (from) == ARRAY_TYPE) ++ from = build_pointer_type (TREE_TYPE (from)); ++ else if (TREE_CODE (from) == FUNCTION_TYPE) ++ from = build_pointer_type (from); ++ ++ /* Top level qualifiers on a parameter do not affect the call. */ ++ from = TYPE_MAIN_VARIANT (from); ++ to = TYPE_MAIN_VARIANT (to); ++ ++ if (comptypes_check_different_types (from, to, &different)) ++ return different ? ck_conversion : ck_exact; ++ ++ if (POINTER_TYPE_P (from) && POINTER_TYPE_P (to)) + { +- /* Implement type-directed function overloading for builtins. +- resolve_overloaded_builtin and targetm.resolve_overloaded_builtin +- handle all the type checking. The result is a complete expression +- that implements this function call. */ +- tree tem = resolve_overloaded_builtin (loc, function, params); +- if (tem) +- return tem; ++ tree tf = TREE_TYPE (from), tt = TREE_TYPE (to); ++ bool quals_ok ++ = (TYPE_QUALS (tf) & ~TYPE_QUALS (tt)) == 0; ++ ++ /* Adding qualifiers to the pointed-to type is an exact match, as ++ in C++; a char * argument should prefer a const char * parameter ++ over anything that needs a real conversion. */ ++ if (quals_ok ++ && comptypes (TYPE_MAIN_VARIANT (tf), TYPE_MAIN_VARIANT (tt))) ++ return ck_exact; ++ if (quals_ok && (VOID_TYPE_P (tt) || VOID_TYPE_P (tf))) ++ return ck_conversion; ++ return ck_bad_pointer; + } +- return build_function_call_vec (loc, arg_loc, function, params, origtypes); ++ ++ if (INTEGRAL_TYPE_P (from) && INTEGRAL_TYPE_P (to) ++ && comptypes (c_type_promotes_to (from), to)) ++ return ck_promotion; ++ ++ if (SCALAR_FLOAT_TYPE_P (to) && from == float_type_node ++ && TYPE_PRECISION (to) > TYPE_PRECISION (float_type_node)) ++ return ck_promotion; ++ ++ if (POINTER_TYPE_P (to) && null_pointer_constant_p (arg)) ++ return ck_conversion; ++ ++ if ((INTEGRAL_TYPE_P (from) || SCALAR_FLOAT_TYPE_P (from) ++ || TREE_CODE (from) == COMPLEX_TYPE) ++ && (INTEGRAL_TYPE_P (to) || SCALAR_FLOAT_TYPE_P (to) ++ || TREE_CODE (to) == COMPLEX_TYPE)) ++ return ck_conversion; ++ ++ return ck_none; + } +- +-/* Helper for convert_arguments called to convert the VALue of argument +- number ARGNUM from ORIGTYPE to the corresponding parameter number +- PARMNUM and TYPE. +- PLOC is the location where the conversion is being performed. +- FUNCTION and FUNDECL are the same as in convert_arguments. +- VALTYPE is the original type of VAL before the conversion and, +- for EXCESS_PRECISION_EXPR, the operand of the expression. +- NPC is true if VAL represents the null pointer constant (VAL itself +- will have been folded to an integer constant). +- RNAME is the same as FUNCTION except in Objective C when it's +- the function selector. +- EXCESS_PRECISION is true when VAL was originally represented +- as EXCESS_PRECISION_EXPR. +- WARNOPT is the same as in convert_for_assignment. */ + +-static tree +-convert_argument (location_t ploc, tree function, tree fundecl, +- tree type, tree origtype, tree val, tree valtype, +- bool npc, tree rname, int parmnum, int argnum, +- bool excess_precision, int warnopt) ++/* True if the candidate whose per-argument ranks start at A is a better ++ match than the one whose ranks start at B: no argument is worse, and ++ at least one is better. Each has NARGS ranks. */ ++ ++static bool ++c_better_candidate_p (const unsigned char *a, const unsigned char *b, ++ unsigned int nargs) + { +- /* Formal parm type is specified by a function prototype. */ ++ bool some_better = false; + +- if (type == error_mark_node || !COMPLETE_TYPE_P (type)) ++ for (unsigned int i = 0; i < nargs; i++) + { +- error_at (ploc, "type of formal parameter %d is incomplete", +- parmnum + 1); +- return error_mark_node; ++ if (a[i] > b[i]) ++ return false; ++ if (a[i] < b[i]) ++ some_better = true; + } ++ return some_better; ++} + +- /* Optionally warn about conversions that differ from the default +- conversions. */ +- if (warn_traditional_conversion || warn_traditional) ++/* Report that no member of the overload set named by FN, or more than ++ one equally good member, matches the call at LOC. CANDS is what to ++ list; AMBIGUOUS says which of the two messages to use. */ ++ ++static void ++c_overload_error (location_t loc, tree fn, const vec &cands, ++ bool ambiguous) ++{ ++ auto_diagnostic_group d; ++ ++ if (ambiguous) ++ error_at (loc, "call of overloaded %qD is ambiguous", fn); ++ else ++ error_at (loc, "no matching function for call to %qD", fn); ++ for (tree cand : cands) ++ inform (DECL_SOURCE_LOCATION (cand), "candidate: %qD", cand); ++} ++ ++/* FN is one member of an __attribute__((overloadable)) set, reached by ++ ordinary name lookup, and PARAMS holds the arguments of a call to it, ++ not yet converted. Return the member the call selects, or ++ error_mark_node after reporting why none could be. ++ ++ This runs before build_function_call_vec because convert_arguments ++ rewrites PARAMS in place, which would destroy the argument types the ++ ranking needs. */ ++ ++tree ++c_resolve_overload (location_t loc, tree fn, vec *params) ++{ ++ unsigned int nargs = vec_safe_length (params); ++ auto_vec cands; ++ auto_vec viable; ++ auto_vec ranks; ++ unsigned int best, i; ++ ++ c_overload_candidates (DECL_NAME (fn), &cands); ++ if (cands.is_empty ()) ++ return fn; ++ ++ for (tree cand : cands) + { ++ tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (cand)); ++ unsigned int nparms = 0; ++ bool variadic; ++ unsigned int base; ++ tree a; ++ bool ok = true; ++ ++ for (a = argtypes; a && a != void_list_node; a = TREE_CHAIN (a)) ++ nparms++; ++ variadic = (a != void_list_node); ++ ++ if (nargs < nparms || (nargs > nparms && !variadic)) ++ continue; ++ ++ base = ranks.length (); ++ a = argtypes; ++ for (i = 0; i < nargs; i++) ++ { ++ enum c_conv_rank r; ++ ++ if (a && a != void_list_node) ++ { ++ r = c_rank_conversion ((*params)[i], TREE_VALUE (a)); ++ a = TREE_CHAIN (a); ++ } ++ else ++ r = ck_ellipsis; ++ if (r == ck_none) ++ { ++ ok = false; ++ break; ++ } ++ ranks.safe_push ((unsigned char) r); ++ } ++ if (!ok) ++ { ++ ranks.truncate (base); ++ continue; ++ } ++ viable.safe_push (cand); ++ } ++ ++ if (viable.is_empty ()) ++ { ++ c_overload_error (loc, fn, cands, false); ++ return error_mark_node; ++ } ++ if (viable.length () == 1) ++ fn = viable[0]; ++ else ++ { ++ /* "Better than" is only a partial order, so pick a provisional ++ best and then check that it really beats every other. */ ++ const unsigned char *r = ranks.address (); ++ ++ best = 0; ++ for (i = 1; i < viable.length (); i++) ++ if (c_better_candidate_p (r + i * nargs, r + best * nargs, nargs)) ++ best = i; ++ for (i = 0; i < viable.length (); i++) ++ if (i != best ++ && !c_better_candidate_p (r + best * nargs, r + i * nargs, nargs)) ++ { ++ c_overload_error (loc, fn, viable, true); ++ return error_mark_node; ++ } ++ fn = viable[best]; ++ } ++ ++ /* Usage was deliberately not recorded for the looked-up decl, which ++ need not be the one the call resolves to. */ ++ if (fn != current_function_decl) ++ TREE_USED (fn) = 1; ++ mark_decl_used (fn, false); ++ return fn; ++} ++ ++/* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ ++ ++tree ++c_build_function_call_vec (location_t loc, const vec &arg_loc, ++ tree function, vec *params, ++ vec *origtypes) ++{ ++ /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ ++ STRIP_TYPE_NOPS (function); ++ ++ /* Convert anything with function type to a pointer-to-function. */ ++ if (TREE_CODE (function) == FUNCTION_DECL) ++ { ++ /* Implement type-directed function overloading for builtins. ++ resolve_overloaded_builtin and targetm.resolve_overloaded_builtin ++ handle all the type checking. The result is a complete expression ++ that implements this function call. */ ++ tree tem = resolve_overloaded_builtin (loc, function, params); ++ if (tem) ++ return tem; ++ ++ /* The same thing for __attribute__((overloadable)) functions. ++ This has to happen before build_function_call_vec, which ++ converts the arguments in place. */ ++ if (C_DECL_OVERLOADABLE_P (function)) ++ { ++ function = c_resolve_overload (loc, function, params); ++ if (function == error_mark_node) ++ return error_mark_node; ++ } ++ } ++ return build_function_call_vec (loc, arg_loc, function, params, origtypes); ++} ++ ++/* Helper for convert_arguments called to convert the VALue of argument ++ number ARGNUM from ORIGTYPE to the corresponding parameter number ++ PARMNUM and TYPE. ++ PLOC is the location where the conversion is being performed. ++ FUNCTION and FUNDECL are the same as in convert_arguments. ++ VALTYPE is the original type of VAL before the conversion and, ++ for EXCESS_PRECISION_EXPR, the operand of the expression. ++ NPC is true if VAL represents the null pointer constant (VAL itself ++ will have been folded to an integer constant). ++ RNAME is the same as FUNCTION except in Objective C when it's ++ the function selector. ++ EXCESS_PRECISION is true when VAL was originally represented ++ as EXCESS_PRECISION_EXPR. ++ WARNOPT is the same as in convert_for_assignment. */ ++ ++static tree ++convert_argument (location_t ploc, tree function, tree fundecl, ++ tree type, tree origtype, tree val, tree valtype, ++ bool npc, tree rname, int parmnum, int argnum, ++ bool excess_precision, int warnopt) ++{ ++ /* Formal parm type is specified by a function prototype. */ ++ ++ if (type == error_mark_node || !COMPLETE_TYPE_P (type)) ++ { ++ error_at (ploc, "type of formal parameter %d is incomplete", ++ parmnum + 1); ++ return error_mark_node; ++ } ++ ++ /* Optionally warn about conversions that differ from the default ++ conversions. */ ++ if (warn_traditional_conversion || warn_traditional) ++ { + if (INTEGRAL_TYPE_P (type) + && SCALAR_FLOAT_TYPE_P (valtype)) + warning_at (ploc, OPT_Wtraditional_conversion, +--- a/gcc/doc/extend.texi ++++ b/gcc/doc/extend.texi +@@ -4207,6 +4207,57 @@ + not on a @code{typedef} that does not also define the enumerated type, + structure, union, or class. + ++@atindex @code{overloadable} ++@cindex functions overloaded on their argument types ++@item overloadable ++This attribute, a GNU extension to C modelled on the Clang attribute of ++the same name, lets several functions share one name and be told apart ++by the types of their arguments: ++ ++@smallexample ++float __attribute__ ((overloadable)) tgsin (float x) @{ return sinf (x); @} ++double __attribute__ ((overloadable)) tgsin (double x) @{ return sin (x); @} ++long double __attribute__ ((overloadable)) tgsin (long double x) ++ @{ return sinl (x); @} ++@end smallexample ++ ++A call picks the member of the set whose parameters need the least ++conversion, following the C++ rules with the adjustments C needs: a ++conversion between compatible but distinct types, such as an enumerated ++type and the integer type it is compatible with, ranks as a conversion ++rather than as an exact match, and widening from @code{float} ranks as a ++promotion whether the destination is @code{double} or @code{long ++double}. A call that fits no member, or fits two equally well, is an ++error. ++ ++Because the members share a source name, they are given distinct ++assembler names using the same Itanium ABI mangling C++ uses, so ++@code{tgsin (1.0f)} above calls @code{_Z5tgsinf}. Do not depend on a ++particular mangling; declaring these functions @code{static inline} is ++the safest use. At most one member of a set may omit the attribute, for ++compatibility with an existing unmangled function; that one keeps its ++ordinary assembler name. An explicit @code{asm} label still overrides ++the mangled name. ++ ++Functions with this attribute must have a prototype, though as in C++ a ++prototype consisting only of an ellipsis is allowed. Two declarations ++of the name whose parameter lists are compatible are declarations of the ++same function, so they must agree about the attribute, and a difference ++only in the return type is a conflict rather than an overload. ++ ++The attribute is accepted in C++, where it does nothing: functions there ++already overload, and already use this mangling. ++ ++This implementation differs from Clang's in two ways worth noting. ++First, an overloaded name is resolved only by a call written directly on ++it. Using the name anywhere else, including taking its address or ++parenthesizing it as in @code{(f) (x)}, is an error unless the set has a ++single member; adding an overload to an existing function therefore ++breaks code that takes that function's address. Second, @code{_Atomic} ++is mangled as an extended qualifier written outside the ++@code{const}/@code{volatile} qualifiers, following the ABI grammar and ++the C++ front end, where Clang writes it inside them. ++ + @atindex @code{patchable_function_entry} + @cindex extra NOP instructions at the function entry point + @cindex functions that have patchable entries diff --git a/src/gcc-final/series b/src/gcc-final/series index 45893e4..a1e04b4 100644 --- a/src/gcc-final/series +++ b/src/gcc-final/series @@ -2,5 +2,6 @@ Os-no-declone-ctor-dtor.patch driver-self-locate.patch i686-dumpmachine.patch libgomp-gfortran-path.patch +overloadable.patch relocatable.patch static-complit-flex-array.patch