ChangeLog: * Makefile.def (target_modules): Add libphobos. (flags_to_pass): Add GDC, GDCFLAGS, GDC_FOR_TARGET and GDCFLAGS_FOR_TARGET. (dependencies): Make libphobos depend on libatomic, libbacktrace configure, and zlib configure. (language): Add language d. * Makefile.in: Rebuild. * Makefile.tpl (BUILD_EXPORTS): Add GDC and GDCFLAGS. (HOST_EXPORTS): Add GDC. (POSTSTAGE1_HOST_EXPORTS): Add GDC and GDC_FOR_BUILD. (BASE_TARGET_EXPORTS): Add GDC. (GDC_FOR_BUILD, GDC, GDCFLAGS): New variables. (GDC_FOR_TARGET, GDC_FLAGS_FOR_TARGET): New variables. (EXTRA_HOST_FLAGS): Add GDC. (STAGE1_FLAGS_TO_PASS): Add GDC. (EXTRA_TARGET_FLAGS): Add GDC and GDCFLAGS. * config-ml.in: Treat GDC and GDCFLAGS like other compiler/flag environment variables. * configure: Rebuild. * configure.ac: Add target-libphobos to target_libraries. Set and substitute GDC_FOR_BUILD and GDC_FOR_TARGET. config/ChangeLog: * multi.m4: Set GDC. gcc/ChangeLog: * Makefile.in (tm_d_file_list, tm_d_include_list): New variables. (TM_D_H, D_TARGET_DEF, D_TARGET_H, D_TARGET_OBJS): New variables. (tm_d.h, cs-tm_d.h, default-d.o): New rules. (d/d-target-hooks-def.h, s-d-target-hooks-def-h): New rules. (s-tm-texi): Also check timestamp on d-target.def. (generated_files): Add TM_D_H and d-target-hooks-def.h. (build/genhooks.o): Also depend on D_TARGET_DEF. * config.gcc (tm_d_file, d_target_objs, target_has_targetdm): New variables. * config/aarch64/aarch64-d.c: New file. * config/aarch64/aarch64-linux.h (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/aarch64/aarch64-protos.h (aarch64_d_target_versions): New prototype. * config/aarch64/aarch64.h (TARGET_D_CPU_VERSIONS): Define. * config/aarch64/t-aarch64 (aarch64-d.o): New rule. * config/arm/arm-d.c: New file. * config/arm/arm-protos.h (arm_d_target_versions): New prototype. * config/arm/arm.h (TARGET_D_CPU_VERSIONS): Define. * config/arm/linux-eabi.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/arm/t-arm (arm-d.o): New rule. * config/default-d.c: New file. * config/glibc-d.c: New file. * config/gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/i386/i386-d.c: New file. * config/i386/i386-protos.h (ix86_d_target_versions): New prototype. * config/i386/i386.h (TARGET_D_CPU_VERSIONS): Define. * config/i386/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/i386/t-i386 (i386-d.o): New rule. * config/kfreebsd-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/kopensolaris-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/linux-android.h (ANDROID_TARGET_D_OS_VERSIONS): Define. * config/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/mips/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/mips/mips-d.c: New file. * config/mips/mips-protos.h (mips_d_target_versions): New prototype. * config/mips/mips.h (TARGET_D_CPU_VERSIONS): Define. * config/mips/t-mips (mips-d.o): New rule. * config/powerpcspe/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/powerpcspe-d.c: New file. * config/powerpcspe/powerpcspe-protos.h (rs6000_d_target_versions): New prototype. * config/powerpcspe/powerpcspe.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/powerpcspe/powerpcspe.h (TARGET_D_CPU_VERSIONS): Define. * config/powerpcspe/t-powerpcspe (powerpcspe-d.o): New rule. * config/riscv/riscv-d.c: New file. * config/riscv/riscv-protos.h (riscv_d_target_versions): New prototype. * config/riscv/riscv.h (TARGET_D_CPU_VERSIONS): Define. * config/riscv/t-riscv (riscv-d.o): New rule. * config/rs6000/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/rs6000-d.c: New file. * config/rs6000/rs6000-protos.h (rs6000_d_target_versions): New prototype. * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/rs6000/rs6000.h (TARGET_D_CPU_VERSIONS): Define. * config/rs6000/t-rs6000 (rs6000-d.o): New rule. * config/s390/s390-d.c: New file. * config/s390/s390-protos.h (s390_d_target_versions): New prototype. * config/s390/s390.h (TARGET_D_CPU_VERSIONS): Define. * config/s390/t-s390 (s390-d.o): New rule. * config/sparc/sparc-d.c: New file. * config/sparc/sparc-protos.h (sparc_d_target_versions): New prototype. * config/sparc/sparc.h (TARGET_D_CPU_VERSIONS): Define. * config/sparc/t-sparc (sparc-d.o): New rule. * config/t-glibc (glibc-d.o): New rule. * configure: Regenerated. * configure.ac (tm_d_file): New variable. (tm_d_file_list, tm_d_include_list, d_target_objs): Add substitutes. * doc/contrib.texi (Contributors): Add self for the D frontend. * doc/frontends.texi (G++ and GCC): Mention D as a supported language. * doc/install.texi (Configuration): Mention libphobos as an option for --enable-shared. Mention d as an option for --enable-languages. (Testing): Mention check-d as a target. * doc/invoke.texi (Overall Options): Mention .d, .dd, and .di as file name suffixes. Mention d as a -x option. * doc/sourcebuild.texi (Top Level): Mention libphobos. * doc/standards.texi (Standards): Add section on D language. * doc/tm.texi: Regenerated. * doc/tm.texi.in: Add @node for D language and ABI, and @hook for TARGET_CPU_VERSIONS, TARGET_D_OS_VERSIONS, and TARGET_D_CRITSEC_SIZE. * dwarf2out.c (is_dlang): New function. (gen_compile_unit_die): Use DW_LANG_D for D. (declare_in_namespace): Return module die for D, instead of adding extra declarations into the namespace. (gen_namespace_die): Generate DW_TAG_module for D. (gen_decl_die): Handle CONST_DECLSs for D. (dwarf2out_decl): Likewise. (prune_unused_types_walk_local_classes): Handle DW_tag_interface_type. (prune_unused_types_walk): Handle DW_tag_interface_type same as other kinds of aggregates. * gcc.c (default_compilers): Add entries for .d, .dd and .di. * genhooks.c: Include d/d-target.def. gcc/po/ChangeLog: * EXCLUDES: Add sources from d/dmd. gcc/testsuite/ChangeLog: * gcc.misc-tests/help.exp: Add D to option descriptions check. * gdc.dg/asan/asan.exp: New file. * gdc.dg/asan/gdc272.d: New test. * gdc.dg/compilable.d: New test. * gdc.dg/dg.exp: New file. * gdc.dg/gdc254.d: New test. * gdc.dg/gdc260.d: New test. * gdc.dg/gdc270a.d: New test. * gdc.dg/gdc270b.d: New test. * gdc.dg/gdc282.d: New test. * gdc.dg/gdc283.d: New test. * gdc.dg/imports/gdc170.d: New test. * gdc.dg/imports/gdc231.d: New test. * gdc.dg/imports/gdc239.d: New test. * gdc.dg/imports/gdc241a.d: New test. * gdc.dg/imports/gdc241b.d: New test. * gdc.dg/imports/gdc251a.d: New test. * gdc.dg/imports/gdc251b.d: New test. * gdc.dg/imports/gdc253.d: New test. * gdc.dg/imports/gdc254a.d: New test. * gdc.dg/imports/gdc256.d: New test. * gdc.dg/imports/gdc27.d: New test. * gdc.dg/imports/gdcpkg256/package.d: New test. * gdc.dg/imports/runnable.d: New test. * gdc.dg/link.d: New test. * gdc.dg/lto/lto.exp: New file. * gdc.dg/lto/ltotests_0.d: New test. * gdc.dg/lto/ltotests_1.d: New test. * gdc.dg/runnable.d: New test. * gdc.dg/simd.d: New test. * gdc.test/gdc-test.exp: New file. * lib/gdc-dg.exp: New file. * lib/gdc.exp: New file. libphobos/ChangeLog: * Makefile.am: New file. * Makefile.in: New file. * acinclude.m4: New file. * aclocal.m4: New file. * config.h.in: New file. * configure: New file. * configure.ac: New file. * d_rules.am: New file. * libdruntime/Makefile.am: New file. * libdruntime/Makefile.in: New file. * libdruntime/__entrypoint.di: New file. * libdruntime/__main.di: New file. * libdruntime/gcc/attribute.d: New file. * libdruntime/gcc/backtrace.d: New file. * libdruntime/gcc/builtins.d: New file. * libdruntime/gcc/config.d.in: New file. * libdruntime/gcc/deh.d: New file. * libdruntime/gcc/libbacktrace.d.in: New file. * libdruntime/gcc/unwind/arm.d: New file. * libdruntime/gcc/unwind/arm_common.d: New file. * libdruntime/gcc/unwind/c6x.d: New file. * libdruntime/gcc/unwind/generic.d: New file. * libdruntime/gcc/unwind/package.d: New file. * libdruntime/gcc/unwind/pe.d: New file. * m4/autoconf.m4: New file. * m4/druntime.m4: New file. * m4/druntime/cpu.m4: New file. * m4/druntime/libraries.m4: New file. * m4/druntime/os.m4: New file. * m4/gcc_support.m4: New file. * m4/gdc.m4: New file. * m4/libtool.m4: New file. * src/Makefile.am: New file. * src/Makefile.in: New file. * src/libgphobos.spec.in: New file. * testsuite/Makefile.am: New file. * testsuite/Makefile.in: New file. * testsuite/config/default.exp: New file. * testsuite/lib/libphobos-dg.exp: New file. * testsuite/lib/libphobos.exp: New file. * testsuite/testsuite_flags.in: New file. From-SVN: r265573
836 lines
24 KiB
C++
836 lines
24 KiB
C++
/* d-attribs.c -- D attributes handling.
|
|
Copyright (C) 2015-2018 Free Software Foundation, Inc.
|
|
|
|
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
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* Implementation of attribute handlers for user defined attributes and
|
|
internal built-in functions. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
|
|
#include "dmd/declaration.h"
|
|
#include "dmd/mtype.h"
|
|
|
|
#include "tree.h"
|
|
#include "diagnostic.h"
|
|
#include "tm.h"
|
|
#include "cgraph.h"
|
|
#include "toplev.h"
|
|
#include "target.h"
|
|
#include "common/common-target.h"
|
|
#include "stringpool.h"
|
|
#include "attribs.h"
|
|
#include "varasm.h"
|
|
|
|
#include "d-tree.h"
|
|
|
|
|
|
/* Internal attribute handlers for built-in functions. */
|
|
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
|
|
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
|
|
|
|
/* D attribute handlers for user defined attributes. */
|
|
static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_target_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_section_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *);
|
|
static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ;
|
|
|
|
/* Helper to define attribute exclusions. */
|
|
#define ATTR_EXCL(name, function, type, variable) \
|
|
{ name, function, type, variable }
|
|
|
|
/* Define attributes that are mutually exclusive with one another. */
|
|
static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
|
|
{
|
|
ATTR_EXCL ("const", true, true, true),
|
|
ATTR_EXCL ("malloc", true, true, true),
|
|
ATTR_EXCL ("pure", true, true, true),
|
|
ATTR_EXCL ("returns_twice", true, true, true),
|
|
ATTR_EXCL (NULL, false, false, false),
|
|
};
|
|
|
|
static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
|
|
{
|
|
ATTR_EXCL ("noreturn", true, true, true),
|
|
ATTR_EXCL (NULL, false, false, false),
|
|
};
|
|
|
|
static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
|
|
{
|
|
ATTR_EXCL ("const", true, true, true),
|
|
ATTR_EXCL ("noreturn", true, true, true),
|
|
ATTR_EXCL ("pure", true, true, true),
|
|
ATTR_EXCL (NULL, false, false, false)
|
|
};
|
|
|
|
static const struct attribute_spec::exclusions attr_inline_exclusions[] =
|
|
{
|
|
ATTR_EXCL ("noinline", true, true, true),
|
|
ATTR_EXCL (NULL, false, false, false),
|
|
};
|
|
|
|
static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
|
|
{
|
|
ATTR_EXCL ("forceinline", true, true, true),
|
|
ATTR_EXCL (NULL, false, false, false),
|
|
};
|
|
|
|
/* Helper to define an attribute. */
|
|
#define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \
|
|
affects_type_identity, handler, exclude) \
|
|
{ name, min_len, max_len, decl_req, type_req, fn_type_req, \
|
|
affects_type_identity, handler, exclude }
|
|
|
|
/* Table of machine-independent attributes.
|
|
For internal use (marking of built-ins) only. */
|
|
const attribute_spec d_langhook_common_attribute_table[] =
|
|
{
|
|
ATTR_SPEC ("noreturn", 0, 0, true, false, false, false,
|
|
handle_noreturn_attribute, attr_noreturn_exclusions),
|
|
ATTR_SPEC ("leaf", 0, 0, true, false, false, false,
|
|
handle_leaf_attribute, NULL),
|
|
ATTR_SPEC ("const", 0, 0, true, false, false, false,
|
|
handle_const_attribute, attr_const_pure_exclusions),
|
|
ATTR_SPEC ("malloc", 0, 0, true, false, false, false,
|
|
handle_malloc_attribute, NULL),
|
|
ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false,
|
|
handle_returns_twice_attribute, attr_returns_twice_exclusions),
|
|
ATTR_SPEC ("pure", 0, 0, true, false, false, false,
|
|
handle_pure_attribute, attr_const_pure_exclusions),
|
|
ATTR_SPEC ("nonnull", 0, -1, false, true, true, false,
|
|
handle_nonnull_attribute, NULL),
|
|
ATTR_SPEC ("nothrow", 0, 0, true, false, false, false,
|
|
handle_nothrow_attribute, NULL),
|
|
ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false,
|
|
handle_transaction_pure_attribute, NULL),
|
|
ATTR_SPEC ("no vops", 0, 0, true, false, false, false,
|
|
handle_novops_attribute, NULL),
|
|
ATTR_SPEC ("type generic", 0, 0, false, true, true, false,
|
|
handle_type_generic_attribute, NULL),
|
|
ATTR_SPEC ("fn spec", 1, 1, false, true, true, false,
|
|
handle_fnspec_attribute, NULL),
|
|
ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
|
|
};
|
|
|
|
/* Table of D language attributes exposed by `gcc.attribute' UDAs. */
|
|
const attribute_spec d_langhook_attribute_table[] =
|
|
{
|
|
ATTR_SPEC ("noinline", 0, 0, true, false, false, false,
|
|
d_handle_noinline_attribute, attr_noinline_exclusions),
|
|
ATTR_SPEC ("forceinline", 0, 0, true, false, false, false,
|
|
d_handle_forceinline_attribute, attr_inline_exclusions),
|
|
ATTR_SPEC ("flatten", 0, 0, true, false, false, false,
|
|
d_handle_flatten_attribute, NULL),
|
|
ATTR_SPEC ("target", 1, -1, true, false, false, false,
|
|
d_handle_target_attribute, NULL),
|
|
ATTR_SPEC ("noclone", 0, 0, true, false, false, false,
|
|
d_handle_noclone_attribute, NULL),
|
|
ATTR_SPEC ("section", 1, 1, true, false, false, false,
|
|
d_handle_section_attribute, NULL),
|
|
ATTR_SPEC ("alias", 1, 1, true, false, false, false,
|
|
d_handle_alias_attribute, NULL),
|
|
ATTR_SPEC ("weak", 0, 0, true, false, false, false,
|
|
d_handle_weak_attribute, NULL),
|
|
ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
|
|
};
|
|
|
|
|
|
/* Insert the type attribute ATTRNAME with value VALUE into TYPE.
|
|
Returns a new variant of the original type declaration. */
|
|
|
|
tree
|
|
insert_type_attribute (tree type, const char *attrname, tree value)
|
|
{
|
|
tree ident = get_identifier (attrname);
|
|
|
|
if (value)
|
|
value = tree_cons (NULL_TREE, value, NULL_TREE);
|
|
|
|
tree attribs = merge_attributes (TYPE_ATTRIBUTES (type),
|
|
tree_cons (ident, value, NULL_TREE));
|
|
|
|
return build_type_attribute_variant (type, attribs);
|
|
}
|
|
|
|
/* Insert the decl attribute ATTRNAME with value VALUE into DECL. */
|
|
|
|
tree
|
|
insert_decl_attribute (tree decl, const char *attrname, tree value)
|
|
{
|
|
tree ident = get_identifier (attrname);
|
|
|
|
if (value)
|
|
value = tree_cons (NULL_TREE, value, NULL_TREE);
|
|
|
|
tree attribs = merge_attributes (DECL_ATTRIBUTES (decl),
|
|
tree_cons (ident, value, NULL_TREE));
|
|
|
|
return build_decl_attribute_variant (decl, attribs);
|
|
}
|
|
|
|
/* Returns TRUE if NAME is an attribute recognized as being handled by
|
|
the `gcc.attribute' module. */
|
|
|
|
static bool
|
|
uda_attribute_p (const char *name)
|
|
{
|
|
tree ident = get_identifier (name);
|
|
|
|
/* Search both our language, and target attribute tables.
|
|
Common and format attributes are kept internal. */
|
|
for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++)
|
|
{
|
|
if (get_identifier (p->name) == ident)
|
|
return true;
|
|
}
|
|
|
|
for (const attribute_spec *p = targetm.attribute_table; p->name; p++)
|
|
{
|
|
if (get_identifier (p->name) == ident)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* [attribute/uda]
|
|
|
|
User Defined Attributes (UDA) are compile time expressions that can be
|
|
attached to a declaration. These attributes can then be queried, extracted,
|
|
and manipulated at compile-time. There is no run-time component to them.
|
|
|
|
Expand and merge all UDAs found in the EATTRS list that are of type
|
|
`gcc.attribute.Attribute'. This symbol is internally recognized by the
|
|
compiler and maps them to their equivalent GCC attribute. */
|
|
|
|
tree
|
|
build_attributes (Expressions *eattrs)
|
|
{
|
|
if (!eattrs)
|
|
return NULL_TREE;
|
|
|
|
expandTuples (eattrs);
|
|
|
|
tree attribs = NULL_TREE;
|
|
|
|
for (size_t i = 0; i < eattrs->dim; i++)
|
|
{
|
|
Expression *attr = (*eattrs)[i];
|
|
Dsymbol *sym = attr->type->toDsymbol (0);
|
|
|
|
if (!sym)
|
|
continue;
|
|
|
|
/* Attribute symbol must come from the `gcc.attribute' module. */
|
|
Dsymbol *mod = (Dsymbol*) sym->getModule ();
|
|
if (!(strcmp (mod->toChars (), "attribute") == 0
|
|
&& mod->parent != NULL
|
|
&& strcmp (mod->parent->toChars (), "gcc") == 0
|
|
&& !mod->parent->parent))
|
|
continue;
|
|
|
|
/* Get the result of the attribute if it hasn't already been folded. */
|
|
if (attr->op == TOKcall)
|
|
attr = attr->ctfeInterpret ();
|
|
|
|
/* Should now have a struct `Attribute("attrib", "value", ...)'
|
|
initializer list. */
|
|
gcc_assert (attr->op == TOKstructliteral);
|
|
Expressions *elems = ((StructLiteralExp*) attr)->elements;
|
|
Expression *e0 = (*elems)[0];
|
|
|
|
if (e0->op != TOKstring)
|
|
{
|
|
error ("expected string attribute, not %qs", e0->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
|
|
StringExp *se = (StringExp*) e0;
|
|
gcc_assert (se->sz == 1);
|
|
|
|
/* Empty string attribute, just ignore it. */
|
|
if (se->len == 0)
|
|
continue;
|
|
|
|
/* Check if the attribute is recognized and handled.
|
|
Done here to report the diagnostic at the right location. */
|
|
const char *name = (const char *)(se->len ? se->string : "");
|
|
if (!uda_attribute_p (name))
|
|
{
|
|
warning_at (make_location_t (e0->loc), OPT_Wattributes,
|
|
"unknown attribute %qs", name);
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* Chain all attribute arguments together. */
|
|
tree args = NULL_TREE;
|
|
|
|
for (size_t j = 1; j < elems->dim; j++)
|
|
{
|
|
Expression *e = (*elems)[j];
|
|
tree t;
|
|
if (e->op == TOKstring && ((StringExp *) e)->sz == 1)
|
|
{
|
|
StringExp *s = (StringExp *) e;
|
|
const char *string = (const char *)(s->len ? s->string : "");
|
|
t = build_string (s->len, string);
|
|
}
|
|
else
|
|
t = build_expr (e);
|
|
|
|
args = chainon (args, build_tree_list (0, t));
|
|
}
|
|
|
|
tree list = build_tree_list (get_identifier (name), args);
|
|
attribs = chainon (attribs, list);
|
|
}
|
|
|
|
return attribs;
|
|
}
|
|
|
|
/* Built-in attribute handlers. */
|
|
|
|
/* Handle a "noreturn" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
tree type = TREE_TYPE (*node);
|
|
|
|
if (TREE_CODE (*node) == FUNCTION_DECL)
|
|
TREE_THIS_VOLATILE (*node) = 1;
|
|
else if (TREE_CODE (type) == POINTER_TYPE
|
|
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
|
|
TREE_TYPE (*node)
|
|
= build_pointer_type
|
|
(build_type_variant (TREE_TYPE (type),
|
|
TYPE_READONLY (TREE_TYPE (type)), 1));
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "leaf" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_leaf_attribute (tree *node, tree name,
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags), bool *no_add_attrs)
|
|
{
|
|
if (TREE_CODE (*node) != FUNCTION_DECL)
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
if (!TREE_PUBLIC (*node))
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute has no effect", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "const" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_const_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
tree type = TREE_TYPE (*node);
|
|
|
|
if (TREE_CODE (*node) == FUNCTION_DECL)
|
|
TREE_READONLY (*node) = 1;
|
|
else if (TREE_CODE (type) == POINTER_TYPE
|
|
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
|
|
TREE_TYPE (*node)
|
|
= build_pointer_type
|
|
(build_type_variant (TREE_TYPE (type), 1,
|
|
TREE_THIS_VOLATILE (TREE_TYPE (type))));
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "malloc" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
tree
|
|
handle_malloc_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_DECL
|
|
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))));
|
|
DECL_IS_MALLOC (*node) = 1;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "pure" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_pure_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
|
|
DECL_PURE_P (*node) = 1;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "no vops" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
|
|
DECL_IS_NOVOPS (*node) = 1;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Helper for nonnull attribute handling; fetch the operand number
|
|
from the attribute argument list. */
|
|
|
|
static bool
|
|
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
|
|
{
|
|
/* Verify the arg number is a constant. */
|
|
if (!tree_fits_uhwi_p (arg_num_expr))
|
|
return false;
|
|
|
|
*valp = TREE_INT_CST_LOW (arg_num_expr);
|
|
return true;
|
|
}
|
|
|
|
/* Handle the "nonnull" attribute. */
|
|
|
|
static tree
|
|
handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree args, int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
tree type = *node;
|
|
|
|
/* If no arguments are specified, all pointer arguments should be
|
|
non-null. Verify a full prototype is given so that the arguments
|
|
will have the correct types when we actually check them later.
|
|
Avoid diagnosing type-generic built-ins since those have no
|
|
prototype. */
|
|
if (!args)
|
|
{
|
|
gcc_assert (prototype_p (type)
|
|
|| !TYPE_ATTRIBUTES (type)
|
|
|| lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Argument list specified. Verify that each argument number references
|
|
a pointer argument. */
|
|
for (; args; args = TREE_CHAIN (args))
|
|
{
|
|
tree argument;
|
|
unsigned HOST_WIDE_INT arg_num = 0, ck_num;
|
|
|
|
if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
|
|
gcc_unreachable ();
|
|
|
|
argument = TYPE_ARG_TYPES (type);
|
|
if (argument)
|
|
{
|
|
for (ck_num = 1; ; ck_num++)
|
|
{
|
|
if (!argument || ck_num == arg_num)
|
|
break;
|
|
argument = TREE_CHAIN (argument);
|
|
}
|
|
|
|
gcc_assert (argument
|
|
&& TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE);
|
|
}
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "nothrow" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
|
|
TREE_NOTHROW (*node) = 1;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "type_generic" attribute. */
|
|
|
|
static tree
|
|
handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
/* Ensure we have a function type. */
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
|
|
|
|
/* Ensure we have a variadic function. */
|
|
gcc_assert (!prototype_p (*node) || stdarg_p (*node));
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "transaction_pure" attribute. */
|
|
|
|
static tree
|
|
handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
/* Ensure we have a function type. */
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "returns_twice" attribute. */
|
|
|
|
static tree
|
|
handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
|
|
|
|
DECL_IS_RETURNS_TWICE (*node) = 1;
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "fn spec" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
tree
|
|
handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
|
|
tree args, int ARG_UNUSED (flags),
|
|
bool *no_add_attrs ATTRIBUTE_UNUSED)
|
|
{
|
|
gcc_assert (args
|
|
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST
|
|
&& !TREE_CHAIN (args));
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Language specific attribute handlers. */
|
|
|
|
/* Handle a "noinline" attribute. */
|
|
|
|
static tree
|
|
d_handle_noinline_attribute (tree *node, tree name,
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags), bool *no_add_attrs)
|
|
{
|
|
Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
|
|
|
|
if (t->ty == Tfunction)
|
|
DECL_UNINLINABLE (*node) = 1;
|
|
else
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "forceinline" attribute. */
|
|
|
|
static tree
|
|
d_handle_forceinline_attribute (tree *node, tree name,
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags),
|
|
bool *no_add_attrs)
|
|
{
|
|
Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
|
|
|
|
if (t->ty == Tfunction)
|
|
{
|
|
tree attributes = DECL_ATTRIBUTES (*node);
|
|
|
|
/* Push attribute always_inline. */
|
|
if (! lookup_attribute ("always_inline", attributes))
|
|
DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"),
|
|
NULL_TREE, attributes);
|
|
|
|
DECL_DECLARED_INLINE_P (*node) = 1;
|
|
DECL_NO_INLINE_WARNING_P (*node) = 1;
|
|
DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
|
|
}
|
|
else
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "flatten" attribute. */
|
|
|
|
static tree
|
|
d_handle_flatten_attribute (tree *node, tree name,
|
|
tree args ATTRIBUTE_UNUSED,
|
|
int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
|
|
{
|
|
Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
|
|
|
|
if (t->ty != Tfunction)
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "target" attribute. */
|
|
|
|
static tree
|
|
d_handle_target_attribute (tree *node, tree name, tree args, int flags,
|
|
bool *no_add_attrs)
|
|
{
|
|
Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
|
|
|
|
/* Ensure we have a function type. */
|
|
if (t->ty != Tfunction)
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
else if (! targetm.target_option.valid_attribute_p (*node, name, args, flags))
|
|
*no_add_attrs = true;
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "noclone" attribute. */
|
|
|
|
static tree
|
|
d_handle_noclone_attribute (tree *node, tree name,
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags),
|
|
bool *no_add_attrs)
|
|
{
|
|
Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
|
|
|
|
if (t->ty == Tfunction)
|
|
{
|
|
tree attributes = DECL_ATTRIBUTES (*node);
|
|
|
|
/* Push attribute noclone. */
|
|
if (! lookup_attribute ("noclone", attributes))
|
|
DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"),
|
|
NULL_TREE, attributes);
|
|
}
|
|
else
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle a "section" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
d_handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
|
|
int ARG_UNUSED (flags), bool *no_add_attrs)
|
|
{
|
|
tree decl = *node;
|
|
|
|
if (targetm_common.have_named_sections)
|
|
{
|
|
if (VAR_OR_FUNCTION_DECL_P (decl)
|
|
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
|
|
{
|
|
if (VAR_P (decl)
|
|
&& current_function_decl != NULL_TREE
|
|
&& !TREE_STATIC (decl))
|
|
{
|
|
error_at (DECL_SOURCE_LOCATION (decl),
|
|
"section attribute cannot be specified for "
|
|
"local variables");
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
/* The decl may have already been given a section attribute
|
|
from a previous declaration. Ensure they match. */
|
|
else if (DECL_SECTION_NAME (decl) != NULL
|
|
&& strcmp (DECL_SECTION_NAME (decl),
|
|
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
|
|
{
|
|
error ("section of %q+D conflicts with previous declaration",
|
|
*node);
|
|
*no_add_attrs = true;
|
|
}
|
|
else if (VAR_P (decl)
|
|
&& !targetm.have_tls && targetm.emutls.tmpl_section
|
|
&& DECL_THREAD_LOCAL_P (decl))
|
|
{
|
|
error ("section of %q+D cannot be overridden", *node);
|
|
*no_add_attrs = true;
|
|
}
|
|
else
|
|
set_decl_section_name (decl,
|
|
TREE_STRING_POINTER (TREE_VALUE (args)));
|
|
}
|
|
else
|
|
{
|
|
error ("section attribute not allowed for %q+D", *node);
|
|
*no_add_attrs = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error_at (DECL_SOURCE_LOCATION (*node),
|
|
"section attributes are not supported for this target");
|
|
*no_add_attrs = true;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Handle an "alias" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
d_handle_alias_attribute (tree *node, tree ARG_UNUSED (name),
|
|
tree args, int ARG_UNUSED (flags),
|
|
bool *no_add_attrs ATTRIBUTE_UNUSED)
|
|
{
|
|
tree decl = *node;
|
|
|
|
if (TREE_CODE (decl) != FUNCTION_DECL
|
|
&& TREE_CODE (decl) != VAR_DECL)
|
|
{
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
*no_add_attrs = true;
|
|
return NULL_TREE;
|
|
}
|
|
else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
|
|
|| (TREE_CODE (decl) != FUNCTION_DECL
|
|
&& TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
|
|
/* A static variable declaration is always a tentative definition,
|
|
but the alias is a non-tentative definition which overrides. */
|
|
|| (TREE_CODE (decl) != FUNCTION_DECL
|
|
&& ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
|
|
{
|
|
error ("%q+D defined both normally and as %qE attribute", decl, name);
|
|
*no_add_attrs = true;
|
|
return NULL_TREE;
|
|
}
|
|
else if (decl_function_context (decl))
|
|
{
|
|
error ("%q+D alias functions must be global", name);
|
|
*no_add_attrs = true;
|
|
return NULL_TREE;
|
|
}
|
|
else
|
|
{
|
|
tree id;
|
|
|
|
id = TREE_VALUE (args);
|
|
if (TREE_CODE (id) != STRING_CST)
|
|
{
|
|
error ("attribute %qE argument not a string", name);
|
|
*no_add_attrs = true;
|
|
return NULL_TREE;
|
|
}
|
|
id = get_identifier (TREE_STRING_POINTER (id));
|
|
/* This counts as a use of the object pointed to. */
|
|
TREE_USED (id) = 1;
|
|
|
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
DECL_INITIAL (decl) = error_mark_node;
|
|
else
|
|
TREE_STATIC (decl) = 1;
|
|
|
|
return NULL_TREE;
|
|
}
|
|
}
|
|
|
|
/* Handle a "weak" attribute; arguments as in
|
|
struct attribute_spec.handler. */
|
|
|
|
static tree
|
|
d_handle_weak_attribute (tree *node, tree name,
|
|
tree ARG_UNUSED (args),
|
|
int ARG_UNUSED (flags),
|
|
bool * ARG_UNUSED (no_add_attrs))
|
|
{
|
|
if (TREE_CODE (*node) == FUNCTION_DECL
|
|
&& DECL_DECLARED_INLINE_P (*node))
|
|
{
|
|
warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
|
|
*no_add_attrs = true;
|
|
}
|
|
else if (VAR_OR_FUNCTION_DECL_P (*node))
|
|
{
|
|
struct symtab_node *n = symtab_node::get (*node);
|
|
if (n && n->refuse_visibility_changes)
|
|
error ("%q+D declared weak after being used", *node);
|
|
declare_weak (*node);
|
|
}
|
|
else
|
|
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|