Skip to content

Commit 77718f3

Browse files
committed
d: Match function declarations of gcc built-ins from any module.
Declarations of recognised gcc built-in functions are now matched from any module. Previously, only the `core.stdc' package was scanned. In addition to matching of the symbol, any user-applied `@attributes' or `pragma(mangle)' name will be applied to the built-in decl as well. Because there would now be no control over where built-in declarations are coming from, the warning option `-Wbuiltin-declaration-mismatch' has been implemented in the D front-end too. gcc/d/ChangeLog: * d-builtins.cc: Include builtins.h. (gcc_builtins_libfuncs): Remove. (strip_type_modifiers): New function. (matches_builtin_type): New function. (covariant_with_builtin_type_p): New function. (maybe_set_builtin_1): Set front-end built-in if identifier matches gcc built-in name. Apply user-specified attributes and assembler name overrides to the built-in. Warn about built-in declaration mismatches. (d_builtin_function): Set IDENTIFIER_DECL_TREE of built-in functions. * d-compiler.cc (Compiler::onParseModule): Scan all modules for any identifiers that match built-in function names. * lang.opt (Wbuiltin-declaration-mismatch): New option. gcc/testsuite/ChangeLog: * gdc.dg/Wbuiltin_declaration_mismatch.d: New test. * gdc.dg/builtins.d: New test.
1 parent f8baf40 commit 77718f3

File tree

5 files changed

+203
-31
lines changed

5 files changed

+203
-31
lines changed

gcc/d/d-builtins.cc

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ along with GCC; see the file COPYING3. If not see
3737
#include "common/common-target.h"
3838
#include "stringpool.h"
3939
#include "stor-layout.h"
40+
#include "builtins.h"
4041

4142
#include "d-tree.h"
4243
#include "d-frontend.h"
4344
#include "d-target.h"
4445

4546

4647
static GTY(()) vec <tree, va_gc> *gcc_builtins_functions = NULL;
47-
static GTY(()) vec <tree, va_gc> *gcc_builtins_libfuncs = NULL;
4848
static GTY(()) vec <tree, va_gc> *gcc_builtins_types = NULL;
4949

5050
/* Record built-in types and their associated decls for re-use when
@@ -672,6 +672,87 @@ d_build_builtins_module (Module *m)
672672
m->members->push (LinkDeclaration::create (Loc (), LINK::c, members));
673673
}
674674

675+
/* Remove all type modifiers from TYPE, returning the naked type. */
676+
677+
static Type *
678+
strip_type_modifiers (Type *type)
679+
{
680+
if (type->ty == TY::Tpointer)
681+
{
682+
Type *tnext = strip_type_modifiers (type->nextOf ());
683+
return tnext->pointerTo ();
684+
}
685+
686+
return type->castMod (0);
687+
}
688+
689+
/* Returns true if types T1 and T2 representing return types or types of
690+
function arguments are close enough to be considered interchangeable. */
691+
692+
static bool
693+
matches_builtin_type (Type *t1, Type *t2)
694+
{
695+
Type *tb1 = strip_type_modifiers (t1);
696+
Type *tb2 = strip_type_modifiers (t2);
697+
698+
if (same_type_p (t1, t2))
699+
return true;
700+
701+
if (((tb1->isTypePointer () && tb2->isTypePointer ())
702+
|| (tb1->isTypeVector () && tb2->isTypeVector ()))
703+
&& tb1->implicitConvTo (tb2) != MATCH::nomatch)
704+
return true;
705+
706+
if (tb1->isintegral () == tb2->isintegral ()
707+
&& tb1->size () == tb2->size ())
708+
return true;
709+
710+
return false;
711+
}
712+
713+
/* Check whether the declared function type T1 is covariant with the built-in
714+
function type T2. Returns true if they are covariant. */
715+
716+
static bool
717+
covariant_with_builtin_type_p (Type *t1, Type *t2)
718+
{
719+
/* Check whether the declared function matches the built-in. */
720+
if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes)
721+
return true;
722+
723+
/* May not be covariant because of D attributes applied on t1.
724+
Strip them all off and compare again. */
725+
TypeFunction *tf1 = t1->isTypeFunction ();
726+
TypeFunction *tf2 = t2->isTypeFunction ();
727+
728+
/* Check for obvious reasons why types may be distinct. */
729+
if (tf1 == NULL || tf2 == NULL
730+
|| tf1->isref () != tf2->isref ()
731+
|| tf1->parameterList.varargs != tf2->parameterList.varargs
732+
|| tf1->parameterList.length () != tf2->parameterList.length ())
733+
return false;
734+
735+
/* Check return type and each parameter type for mismatch. */
736+
if (!matches_builtin_type (tf1->next, tf2->next))
737+
return false;
738+
739+
const size_t nparams = tf1->parameterList.length ();
740+
for (size_t i = 0; i < nparams; i++)
741+
{
742+
Parameter *fparam1 = tf1->parameterList[i];
743+
Parameter *fparam2 = tf2->parameterList[i];
744+
745+
if (fparam1->isReference () != fparam2->isReference ()
746+
|| fparam1->isLazy () != fparam2->isLazy ())
747+
return false;
748+
749+
if (!matches_builtin_type (fparam1->type, fparam2->type))
750+
return false;
751+
}
752+
753+
return true;
754+
}
755+
675756
/* Search for any `extern(C)' functions that match any known GCC library builtin
676757
function in D and override its internal back-end symbol. */
677758

@@ -694,23 +775,46 @@ maybe_set_builtin_1 (Dsymbol *d)
694775
}
695776
}
696777
}
697-
else if (fd && !fd->fbody)
778+
else if (fd && !fd->fbody && fd->resolvedLinkage () == LINK::c)
698779
{
699-
tree t;
780+
tree ident = get_identifier (fd->ident->toChars ());
781+
tree decl = IDENTIFIER_DECL_TREE (ident);
700782

701-
for (size_t i = 0; vec_safe_iterate (gcc_builtins_libfuncs, i, &t); ++i)
783+
if (decl && TREE_CODE (decl) == FUNCTION_DECL
784+
&& DECL_ASSEMBLER_NAME_SET_P (decl)
785+
&& fndecl_built_in_p (decl, BUILT_IN_NORMAL))
702786
{
703-
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (t));
704-
705-
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t));
706-
if (fd->ident != Identifier::idPool (name))
707-
continue;
708-
709787
/* Found a match, tell the frontend this is a builtin. */
710-
DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
711-
fd->csym = t;
788+
DECL_LANG_SPECIFIC (decl) = build_lang_decl (fd);
789+
fd->csym = decl;
712790
fd->builtin = BUILTIN::gcc;
713-
return;
791+
792+
/* Copy front-end attributes to the builtin. */
793+
apply_user_attributes (fd, fd->csym);
794+
795+
/* Function has `pragma(mangle)' specified, override its name. */
796+
if (fd->mangleOverride.length)
797+
{
798+
tree mangle =
799+
get_identifier_with_length (fd->mangleOverride.ptr,
800+
fd->mangleOverride.length);
801+
const char *asmname = IDENTIFIER_POINTER (mangle);
802+
set_builtin_user_assembler_name (decl, asmname);
803+
}
804+
805+
/* Warn when return and argument types of the user defined function is
806+
not covariant with the built-in function type. */
807+
if (Type *type = build_frontend_type (TREE_TYPE (decl)))
808+
{
809+
if (!covariant_with_builtin_type_p (fd->type, type))
810+
{
811+
warning_at (make_location_t (fd->loc),
812+
OPT_Wbuiltin_declaration_mismatch,
813+
"conflicting types for built-in function %qs; "
814+
"expected %qs",
815+
fd->toChars (), type->toChars ());
816+
}
817+
}
714818
}
715819
}
716820
}
@@ -1221,7 +1325,11 @@ tree
12211325
d_builtin_function (tree decl)
12221326
{
12231327
if (!flag_no_builtin && DECL_ASSEMBLER_NAME_SET_P (decl))
1224-
vec_safe_push (gcc_builtins_libfuncs, decl);
1328+
{
1329+
/* Associate the assembler identifier with the built-in. */
1330+
tree ident = DECL_ASSEMBLER_NAME (decl);
1331+
IDENTIFIER_DECL_TREE (ident) = decl;
1332+
}
12251333

12261334
vec_safe_push (gcc_builtins_functions, decl);
12271335
return decl;

gcc/d/d-compiler.cc

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -119,31 +119,37 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
119119
Modules we look out for are:
120120
- object: For D runtime type information.
121121
- gcc.builtins: For all gcc builtins.
122-
- core.stdc.*: For all gcc library builtins. */
122+
- all other modules for extern(C) gcc library builtins. */
123123

124124
void
125125
Compiler::onParseModule (Module *m)
126126
{
127127
ModuleDeclaration *md = m->md;
128128

129-
if (!md || !md->id|| md->packages.length == 0)
129+
if (md && md->id)
130130
{
131-
Identifier *id = (md && md->id) ? md->id : m->ident;
132-
if (!strcmp (id->toChars (), "object"))
133-
create_tinfo_types (m);
134-
}
135-
else if (md->packages.length == 1)
136-
{
137-
if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
138-
&& !strcmp (md->id->toChars (), "builtins"))
139-
d_build_builtins_module (m);
140-
}
141-
else if (md->packages.length == 2)
142-
{
143-
if (!strcmp (md->packages.ptr[0]->toChars (), "core")
144-
&& !strcmp (md->packages.ptr[1]->toChars (), "stdc"))
145-
d_add_builtin_module (m);
131+
if (md->packages.length == 0)
132+
{
133+
Identifier *id = (md && md->id) ? md->id : m->ident;
134+
if (!strcmp (id->toChars (), "object"))
135+
{
136+
create_tinfo_types (m);
137+
return;
138+
}
139+
}
140+
else if (md->packages.length == 1)
141+
{
142+
if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
143+
&& !strcmp (md->id->toChars (), "builtins"))
144+
{
145+
d_build_builtins_module (m);
146+
return;
147+
}
148+
}
146149
}
150+
151+
if (!flag_no_builtin)
152+
d_add_builtin_module (m);
147153
}
148154

149155
/* A callback function that is called once an imported module is parsed.

gcc/d/lang.opt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ Wno-alloca-larger-than
118118
D
119119
; Documented in C
120120

121+
Wbuiltin-declaration-mismatch
122+
D
123+
; Documented in C
124+
121125
Wcast-result
122126
D Warning Var(warn_cast_result) LangEnabledBy(D, Wextra)
123127
Warn about casts that will produce a null result.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// { dg-do compile }
2+
// { dg-options "-Wbuiltin-declaration-mismatch" }
3+
4+
extern(C):
5+
6+
// Mismatched parameter lengths
7+
double tan(); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
8+
9+
// Mismatched variadic arguments
10+
int printf(const(char)*); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
11+
12+
// Mismatched return type
13+
void puts(char*); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
14+
15+
// Mismatched return storage class
16+
ref int isalnum(int); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
17+
18+
// Mismatched parameter type
19+
double sin(long); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
20+
21+
// Mismatched parameter storage class
22+
double frexp(double, lazy int*); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
23+
double log(ref double); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" }
24+
25+
// Verify that storage classes don't affect covariance matching
26+
@trusted nothrow @nogc pure double fabs(double);
27+
28+
// Verify inout is allowed instead of const
29+
inout(char)* strstr(return scope inout(char)*, scope const char*) pure;
30+
31+
// Verify that FILE* is allowed as it is implicitly convertable to void*
32+
struct _IO_FILE{}
33+
alias FILE = shared(_IO_FILE);
34+
int fprintf(FILE*, scope const char*, scope const ...);
35+
36+
// Verify integral types with same size are treated as if equivalent
37+
int putchar(dchar);

gcc/testsuite/gdc.dg/builtins.d

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// { dg-do compile }
2+
// { dg-options "-fdump-tree-original" }
3+
4+
// { dg-final { scan-tree-dump " __builtin_sqrt " "original" } }
5+
extern(C) double sqrt(double);
6+
double test_sqrt(double a) { return sqrt(a); }
7+
8+
// { dg-final { scan-tree-dump-not " __builtin_tan " "original" } }
9+
pragma(mangle, "tan")
10+
extern(C) double libc_tan(double);
11+
double test_tan(double a) { return libc_tan(a); }
12+
13+
// { dg-final { scan-tree-dump " __builtin_malloc " "original" } }
14+
// { dg-final { scan-assembler "mangle_override" } }
15+
pragma(mangle, "mangle_override")
16+
extern(C) void *malloc(size_t);
17+
void* test_malloc(size_t a) { return malloc(a); }

0 commit comments

Comments
 (0)