diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-17 02:06:34 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-17 02:20:51 +0200 |
commit | ef8f7e3f973d90fdffaf4b8e720db484ce63df6f (patch) | |
tree | 552b47ec87801a86a9a6a9fb834c55ce1c9ab13f /gcc/d | |
parent | e16ace7c79687c224d08ee8d04fd637589333a99 (diff) | |
download | gcc-ef8f7e3f973d90fdffaf4b8e720db484ce63df6f.zip gcc-ef8f7e3f973d90fdffaf4b8e720db484ce63df6f.tar.gz gcc-ef8f7e3f973d90fdffaf4b8e720db484ce63df6f.tar.bz2 |
d: Forbid taking the address of an intrinsic with no implementation
This code fails to link:
import core.math;
real function(real) fn = &sin;
However, when called directly, the D intrinsic `sin()' is expanded by
the front-end into the GCC built-in `__builtin_sin()'. This has been
fixed to now also expand the function when a reference is taken.
As there are D intrinsics and GCC built-ins that don't have a fallback
implementation, raise an error if taking the address is not possible.
gcc/d/ChangeLog:
* d-tree.h (intrinsic_code): Update define for DEF_D_INTRINSIC.
(maybe_reject_intrinsic): New prototype.
* expr.cc (ExprVisitor::visit (SymOffExp *)): Call
maybe_reject_intrinsic.
* intrinsics.cc (intrinsic_decl): Add fallback field.
(intrinsic_decls): Update define for DEF_D_INTRINSIC.
(maybe_reject_intrinsic): New function.
* intrinsics.def (DEF_D_LIB_BUILTIN): Update.
(DEF_CTFE_BUILTIN): Update.
(INTRINSIC_BSF): Declare as library builtin.
(INTRINSIC_BSR): Likewise.
(INTRINSIC_BT): Likewise.
(INTRINSIC_BSF64): Likewise.
(INTRINSIC_BSR64): Likewise.
(INTRINSIC_BT64): Likewise.
(INTRINSIC_POPCNT32): Likewise.
(INTRINSIC_POPCNT64): Likewise.
(INTRINSIC_ROL): Likewise.
(INTRINSIC_ROL_TIARG): Likewise.
(INTRINSIC_ROR): Likewise.
(INTRINSIC_ROR_TIARG): Likewise.
(INTRINSIC_ADDS): Likewise.
(INTRINSIC_ADDSL): Likewise.
(INTRINSIC_ADDU): Likewise.
(INTRINSIC_ADDUL): Likewise.
(INTRINSIC_SUBS): Likewise.
(INTRINSIC_SUBSL): Likewise.
(INTRINSIC_SUBU): Likewise.
(INTRINSIC_SUBUL): Likewise.
(INTRINSIC_MULS): Likewise.
(INTRINSIC_MULSL): Likewise.
(INTRINSIC_MULU): Likewise.
(INTRINSIC_MULUI): Likewise.
(INTRINSIC_MULUL): Likewise.
(INTRINSIC_NEGS): Likewise.
(INTRINSIC_NEGSL): Likewise.
(INTRINSIC_TOPRECF): Likewise.
(INTRINSIC_TOPREC): Likewise.
(INTRINSIC_TOPRECL): Likewise.
gcc/testsuite/ChangeLog:
* gdc.dg/builtins_reject.d: New test.
* gdc.dg/intrinsics_reject.d: New test.
Diffstat (limited to 'gcc/d')
-rw-r--r-- | gcc/d/d-tree.h | 3 | ||||
-rw-r--r-- | gcc/d/expr.cc | 3 | ||||
-rw-r--r-- | gcc/d/intrinsics.cc | 47 | ||||
-rw-r--r-- | gcc/d/intrinsics.def | 128 |
4 files changed, 118 insertions, 63 deletions
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index b64a6fb..66c2f24 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -94,7 +94,7 @@ enum level_kind enum intrinsic_code { -#define DEF_D_INTRINSIC(CODE, B, N, M, D, C) CODE, +#define DEF_D_INTRINSIC(CODE, B, N, M, D, C, F) CODE, #include "intrinsics.def" @@ -668,6 +668,7 @@ extern tree build_import_decl (Dsymbol *); /* In intrinsics.cc. */ extern void maybe_set_intrinsic (FuncDeclaration *); extern tree maybe_expand_intrinsic (tree); +extern tree maybe_reject_intrinsic (tree); /* In modules.cc. */ extern void build_module_tree (Module *); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index cc4aa03..52243e6 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -2050,6 +2050,9 @@ public: tree result = get_decl_tree (e->var); TREE_USED (result) = 1; + if (e->var->isFuncDeclaration ()) + result = maybe_reject_intrinsic (result); + if (declaration_reference_p (e->var)) gcc_assert (POINTER_TYPE_P (TREE_TYPE (result))); else diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc index 583d5a9..1b03e9e 100644 --- a/gcc/d/intrinsics.cc +++ b/gcc/d/intrinsics.cc @@ -60,12 +60,15 @@ struct intrinsic_decl /* True if the intrinsic is only handled in CTFE. */ bool ctfeonly; + + /* True if the intrinsic has a library implementation. */ + bool fallback; }; static const intrinsic_decl intrinsic_decls[] = { -#define DEF_D_INTRINSIC(CODE, BUILTIN, NAME, MODULE, DECO, CTFE) \ - { CODE, BUILTIN, NAME, MODULE, DECO, CTFE }, +#define DEF_D_INTRINSIC(CODE, BUILTIN, NAME, MODULE, DECO, CTFE, FALLBACK) \ + { CODE, BUILTIN, NAME, MODULE, DECO, CTFE, FALLBACK }, #include "intrinsics.def" @@ -1436,3 +1439,43 @@ maybe_expand_intrinsic (tree callexp) gcc_unreachable (); } } + +/* If FNDECL is an intrinsic, return the FUNCTION_DECL that has a library + fallback implementation of it, otherwise raise an error. */ + +tree +maybe_reject_intrinsic (tree fndecl) +{ + gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); + + intrinsic_code intrinsic = DECL_INTRINSIC_CODE (fndecl); + + if (intrinsic == INTRINSIC_NONE) + { + /* Not an intrinsic, but it still might be a declaration from the + `gcc.builtins' module. */ + if (fndecl_built_in_p (fndecl) && DECL_IS_UNDECLARED_BUILTIN (fndecl) + && !DECL_ASSEMBLER_NAME_SET_P (fndecl)) + error ("built-in function %qE must be directly called", fndecl); + + return fndecl; + } + + /* Nothing to do if the intrinsic has a D library implementation. */ + if (intrinsic_decls[intrinsic].fallback) + return fndecl; + + /* Check the GCC built-in decl if the intrinsic maps to one. */ + built_in_function code = intrinsic_decls[intrinsic].built_in; + if (code != BUILT_IN_NONE) + { + tree builtin = builtin_decl_explicit (code); + if (!DECL_IS_UNDECLARED_BUILTIN (builtin) + || DECL_ASSEMBLER_NAME_SET_P (builtin)) + return builtin; + } + + /* It's a D language intrinsic with no library implementation. */ + error ("intrinsic function %qE must be directly called", fndecl); + return fndecl; +} diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def index 454bddf..e472cf7 100644 --- a/gcc/d/intrinsics.def +++ b/gcc/d/intrinsics.def @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -/* DEF_D_INTRINSIC (CODE, BUILTIN, NAME, MODULE, DECO, CTFE) +/* DEF_D_INTRINSIC (CODE, BUILTIN, NAME, MODULE, DECO, CTFE, FALLBACK) CODE The enum code used to refer to this intrinsic. BUILTIN The enum code used to reference the function DECL_FUNCTION_CODE, if the intrinsic can be mapped 1:1 to a GCC built-in. @@ -24,40 +24,45 @@ along with GCC; see the file COPYING3. If not see DECO The function signature decoration of the intrinsic. CTFE True if the function is only handled as a built-in during CTFE, otherwise the runtime implementation is used. + FALLBACK True if the function has a D runtime library implementation. Used for declaring internally recognized functions that either map to a GCC builtin, or are specially handled by the compiler. */ /* A D built-in that has no runtime implementation. */ #define DEF_D_BUILTIN(C, B, N, M, D) \ - DEF_D_INTRINSIC (C, B, N, M, D, false) + DEF_D_INTRINSIC (C, B, N, M, D, false, false) + +/* A D built-in that has a runtime implementation. */ +#define DEF_D_LIB_BUILTIN(C, B, N, M, D) \ + DEF_D_INTRINSIC (C, B, N, M, D, false, true) /* A D built-in that is specially recognized only during CTFE. */ #define DEF_CTFE_BUILTIN(C, B, N, M, D) \ - DEF_D_INTRINSIC (C, B, N, M, D, true) + DEF_D_INTRINSIC (C, B, N, M, D, true, true) DEF_D_BUILTIN (INTRINSIC_NONE, BUILT_IN_NONE, 0, 0, 0) /* core.bitop intrinsics. */ -DEF_D_BUILTIN (INTRINSIC_BSF, BUILT_IN_NONE, "bsf", "core.bitop", - "FNaNbNiNfkZi") -DEF_D_BUILTIN (INTRINSIC_BSR, BUILT_IN_NONE, "bsr", "core.bitop", - "FNaNbNiNfkZi") -DEF_D_BUILTIN (INTRINSIC_BT, BUILT_IN_NONE, "bt", "core.bitop", - "FNaNbNiMxPkkZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BSF, BUILT_IN_NONE, "bsf", "core.bitop", + "FNaNbNiNfkZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BSR, BUILT_IN_NONE, "bsr", "core.bitop", + "FNaNbNiNfkZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BT, BUILT_IN_NONE, "bt", "core.bitop", + "FNaNbNiMxPkkZi") DEF_D_BUILTIN (INTRINSIC_BTC, BUILT_IN_NONE, "btc", "core.bitop", "FNaNbNiPkkZi") DEF_D_BUILTIN (INTRINSIC_BTR, BUILT_IN_NONE, "btr", "core.bitop", "FNaNbNiPkkZi") DEF_D_BUILTIN (INTRINSIC_BTS, BUILT_IN_NONE, "bts", "core.bitop", "FNaNbNiPkkZi") -DEF_D_BUILTIN (INTRINSIC_BSF64, BUILT_IN_NONE, "bsf", "core.bitop", - "FNaNbNiNfmZi") -DEF_D_BUILTIN (INTRINSIC_BSR64, BUILT_IN_NONE, "bsr", "core.bitop", - "FNaNbNiNfmZi") -DEF_D_BUILTIN (INTRINSIC_BT64, BUILT_IN_NONE, "bt", "core.bitop", - "FNaNbNiMxPmmZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BSF64, BUILT_IN_NONE, "bsf", "core.bitop", + "FNaNbNiNfmZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BSR64, BUILT_IN_NONE, "bsr", "core.bitop", + "FNaNbNiNfmZi") +DEF_D_LIB_BUILTIN (INTRINSIC_BT64, BUILT_IN_NONE, "bt", "core.bitop", + "FNaNbNiMxPmmZi") DEF_D_BUILTIN (INTRINSIC_BTC64, BUILT_IN_NONE, "btc", "core.bitop", "FNaNbNiPmmZi") DEF_D_BUILTIN (INTRINSIC_BTR64, BUILT_IN_NONE, "btr", "core.bitop", @@ -72,17 +77,19 @@ DEF_D_BUILTIN (INTRINSIC_BSWAP32, BUILT_IN_BSWAP32, "bswap", "core.bitop", DEF_D_BUILTIN (INTRINSIC_BSWAP64, BUILT_IN_BSWAP64, "bswap", "core.bitop", "FNaNbNiNfmZm") -DEF_D_BUILTIN (INTRINSIC_POPCNT32, BUILT_IN_NONE, "popcnt", "core.bitop", - "FNaNbNiNfkZi") -DEF_D_BUILTIN (INTRINSIC_POPCNT64, BUILT_IN_NONE, "popcnt", "core.bitop", - "FNaNbNiNfmZi") +DEF_D_LIB_BUILTIN (INTRINSIC_POPCNT32, BUILT_IN_NONE, "popcnt", "core.bitop", + "FNaNbNiNfkZi") +DEF_D_LIB_BUILTIN (INTRINSIC_POPCNT64, BUILT_IN_NONE, "popcnt", "core.bitop", + "FNaNbNiNfmZi") -DEF_D_BUILTIN (INTRINSIC_ROL, BUILT_IN_NONE, "rol", "core.bitop", "FNa@1TkZ@1T") -DEF_D_BUILTIN (INTRINSIC_ROL_TIARG, BUILT_IN_NONE, "rol", "core.bitop", - "FNa@1TZ@1T") -DEF_D_BUILTIN (INTRINSIC_ROR, BUILT_IN_NONE, "ror", "core.bitop", "FNa@1TkZ@1T") -DEF_D_BUILTIN (INTRINSIC_ROR_TIARG, BUILT_IN_NONE, "ror", "core.bitop", - "FNa@1TZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_ROL, BUILT_IN_NONE, "rol", "core.bitop", + "FNa@1TkZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_ROL_TIARG, BUILT_IN_NONE, "rol", "core.bitop", + "FNa@1TZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_ROR, BUILT_IN_NONE, "ror", "core.bitop", + "FNa@1TkZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_ROR_TIARG, BUILT_IN_NONE, "ror", "core.bitop", + "FNa@1TZ@1T") /* core.volatile intrinsics. */ @@ -105,36 +112,36 @@ DEF_D_BUILTIN (INTRINSIC_VSTORE64, BUILT_IN_NONE, "volatileStore", /* core.checkedint intrinsics. */ -DEF_D_BUILTIN (INTRINSIC_ADDS, BUILT_IN_NONE, "adds", "core.checkedint", - "FiiKbZi") -DEF_D_BUILTIN (INTRINSIC_ADDSL, BUILT_IN_NONE, "adds", "core.checkedint", - "FllKbZl") -DEF_D_BUILTIN (INTRINSIC_ADDU, BUILT_IN_NONE, "addu", "core.checkedint", - "FkkKbZk") -DEF_D_BUILTIN (INTRINSIC_ADDUL, BUILT_IN_NONE, "addu", "core.checkedint", - "FmmKbZm") -DEF_D_BUILTIN (INTRINSIC_SUBS, BUILT_IN_NONE, "subs", "core.checkedint", - "FiiKbZi") -DEF_D_BUILTIN (INTRINSIC_SUBSL, BUILT_IN_NONE, "subs", "core.checkedint", - "FllKbZl") -DEF_D_BUILTIN (INTRINSIC_SUBU, BUILT_IN_NONE, "subu", "core.checkedint", - "FkkKbZk") -DEF_D_BUILTIN (INTRINSIC_SUBUL, BUILT_IN_NONE, "subu", "core.checkedint", - "FmmKbZm") -DEF_D_BUILTIN (INTRINSIC_MULS, BUILT_IN_NONE, "muls", "core.checkedint", - "FiiKbZi") -DEF_D_BUILTIN (INTRINSIC_MULSL, BUILT_IN_NONE, "muls", "core.checkedint", - "FllKbZl") -DEF_D_BUILTIN (INTRINSIC_MULU, BUILT_IN_NONE, "mulu", "core.checkedint", - "FkkKbZk") -DEF_D_BUILTIN (INTRINSIC_MULUI, BUILT_IN_NONE, "mulu", "core.checkedint", - "FmkKbZm") -DEF_D_BUILTIN (INTRINSIC_MULUL, BUILT_IN_NONE, "mulu", "core.checkedint", - "FmmKbZm") -DEF_D_BUILTIN (INTRINSIC_NEGS, BUILT_IN_NONE, "negs", "core.checkedint", - "FiKbZi") -DEF_D_BUILTIN (INTRINSIC_NEGSL, BUILT_IN_NONE, "negs", "core.checkedint", - "FlKbZl") +DEF_D_LIB_BUILTIN (INTRINSIC_ADDS, BUILT_IN_NONE, "adds", "core.checkedint", + "FiiKbZi") +DEF_D_LIB_BUILTIN (INTRINSIC_ADDSL, BUILT_IN_NONE, "adds", "core.checkedint", + "FllKbZl") +DEF_D_LIB_BUILTIN (INTRINSIC_ADDU, BUILT_IN_NONE, "addu", "core.checkedint", + "FkkKbZk") +DEF_D_LIB_BUILTIN (INTRINSIC_ADDUL, BUILT_IN_NONE, "addu", "core.checkedint", + "FmmKbZm") +DEF_D_LIB_BUILTIN (INTRINSIC_SUBS, BUILT_IN_NONE, "subs", "core.checkedint", + "FiiKbZi") +DEF_D_LIB_BUILTIN (INTRINSIC_SUBSL, BUILT_IN_NONE, "subs", "core.checkedint", + "FllKbZl") +DEF_D_LIB_BUILTIN (INTRINSIC_SUBU, BUILT_IN_NONE, "subu", "core.checkedint", + "FkkKbZk") +DEF_D_LIB_BUILTIN (INTRINSIC_SUBUL, BUILT_IN_NONE, "subu", "core.checkedint", + "FmmKbZm") +DEF_D_LIB_BUILTIN (INTRINSIC_MULS, BUILT_IN_NONE, "muls", "core.checkedint", + "FiiKbZi") +DEF_D_LIB_BUILTIN (INTRINSIC_MULSL, BUILT_IN_NONE, "muls", "core.checkedint", + "FllKbZl") +DEF_D_LIB_BUILTIN (INTRINSIC_MULU, BUILT_IN_NONE, "mulu", "core.checkedint", + "FkkKbZk") +DEF_D_LIB_BUILTIN (INTRINSIC_MULUI, BUILT_IN_NONE, "mulu", "core.checkedint", + "FmkKbZm") +DEF_D_LIB_BUILTIN (INTRINSIC_MULUL, BUILT_IN_NONE, "mulu", "core.checkedint", + "FmmKbZm") +DEF_D_LIB_BUILTIN (INTRINSIC_NEGS, BUILT_IN_NONE, "negs", "core.checkedint", + "FiKbZi") +DEF_D_LIB_BUILTIN (INTRINSIC_NEGSL, BUILT_IN_NONE, "negs", "core.checkedint", + "FlKbZl") /* core.math intrinsics. */ @@ -182,11 +189,12 @@ DEF_D_BUILTIN (INTRINSIC_SQRT, BUILT_IN_SQRT, "sqrt", "core.math", "FNaNbNiNfdZd") DEF_D_BUILTIN (INTRINSIC_SQRTL, BUILT_IN_SQRTL, "sqrt", "core.math", "FNaNbNiNfeZe") -DEF_D_BUILTIN (INTRINSIC_TOPRECF, BUILT_IN_NONE, "toPrec", "core.math", - "FfZ@1T") -DEF_D_BUILTIN (INTRINSIC_TOPREC, BUILT_IN_NONE, "toPrec", "core.math", "FdZ@1T") -DEF_D_BUILTIN (INTRINSIC_TOPRECL, BUILT_IN_NONE, "toPrec", "core.math", - "FeZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_TOPRECF, BUILT_IN_NONE, "toPrec", "core.math", + "FfZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_TOPREC, BUILT_IN_NONE, "toPrec", "core.math", + "FdZ@1T") +DEF_D_LIB_BUILTIN (INTRINSIC_TOPRECL, BUILT_IN_NONE, "toPrec", "core.math", + "FeZ@1T") /* std.math intrinsics. */ |